Ignore:
Timestamp:
Jan 8, 2021, 8:31:12 PM (4 years ago)
Author:
Alexey Shvayka
Message:

Implement @copyDataProperties in C++ to optimize object rest / spread
https://bugs.webkit.org/show_bug.cgi?id=193618

Reviewed by Yusuke Suzuki.

JSTests:

  • microbenchmarks/object-rest-destructuring.js: Added.
  • microbenchmarks/object-spread.js: Added.
  • stress/object-rest-deconstruct.js:
  • stress/object-spread.js:

Source/JavaScriptCore:

Since @copyDataProperties is inherently polymorphic, implementing it in JS is not beneficial.
This patch:

  1. Merges almost identical @copyDataProperties variants and moves them to C++, avoiding allocations of JSArray instances and Identifier wrappers.
  2. Skips non-observable Get calls, leveraging slot.isTaintedByOpaqueObject().
  3. Performs DefineOwnProperty via putDirectMayBeIndex(), since the spec guarantees property creation to be successful [1]: target is an newly created object that is not yet accessible to userland code. It's impossible for target to be non-extensible nor have a non-configurable property.
  4. Introduces a fast path similar to Object.assign, but: a) with no checks on target, because it's guaranteed to be an extensible JSFinalObject; b) with less checks on source, since we are performing putDirect() and don't care about

read-only properties nor proto.

Altogether, these changes result in 3.1x speed-up for object rest / spread.
Also, this patch removes unnecessary target return and @isObject check.

[1]: https://tc39.es/ecma262/#sec-copydataproperties (step 6.c.ii.2, note the "!" prefix)

  • builtins/BuiltinNames.h:
  • builtins/GlobalOperations.js:

(globalPrivate.speciesConstructor):
(globalPrivate.copyDataProperties): Deleted.
(globalPrivate.copyDataPropertiesNoExclusions): Deleted.

  • bytecode/BytecodeIntrinsicRegistry.h:
  • bytecode/LinkTimeConstant.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ObjectPatternNode::bindValue const):
(JSC::ObjectSpreadExpressionNode::emitBytecode):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_defineEnumerableWritableConfigurableDataProperty): Deleted.

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::canPerformFastPropertyEnumerationForCopyDataProperties):
(JSC::JSC_DEFINE_HOST_FUNCTION):

  • runtime/JSGlobalObjectFunctions.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r271265 r271343  
    17771777    ASSERT(!m_args->m_listNode);
    17781778    return generator.emitCreateArgumentsButterfly(generator.finalDestination(dst));
    1779 }
    1780 
    1781 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_defineEnumerableWritableConfigurableDataProperty(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst)
    1782 {
    1783     ArgumentListNode* node = m_args->m_listNode;
    1784     RefPtr<RegisterID> newObj = generator.emitNode(node);
    1785     node = node->m_next;
    1786     RefPtr<RegisterID> propertyNameRegister = generator.emitNode(node);
    1787     node = node->m_next;
    1788     RefPtr<RegisterID> value = generator.emitNode(node);
    1789     ASSERT(!node->m_next);
    1790 
    1791     generator.emitCallDefineProperty(newObj.get(), propertyNameRegister.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
    1792     return dst;
    17931779}
    17941780
     
    53595345            }
    53605346
    5361             RefPtr<RegisterID> result = generator.newTemporary();
    5362             generator.emitCall(result.get(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
    5363             target.pattern->bindValue(generator, result.get());
     5347            generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
     5348            target.pattern->bindValue(generator, newObject.get());
    53645349        }
    53655350    }
     
    55705555    generator.emitNode(src.get(), m_expression);
    55715556   
    5572     // load and call @copyDataPropertiesNoExclusions
    5573     RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataPropertiesNoExclusions);
     5557    RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataProperties);
    55745558   
    55755559    CallArguments args(generator, nullptr, 2);
Note: See TracChangeset for help on using the changeset viewer.