[JSC] Add a new byte code op_define_property instead of calling defineProperty
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Oct 2016 19:31:24 +0000 (19:31 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Oct 2016 19:31:24 +0000 (19:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=162108

Reviewed by Saam Barati.

To construct ES6 class, we emitted bytecode that performs the following operations.

    1. construct a new object
    2. put "configurable", "enumerable" etc. fields
    3. call "defineProperty" function

However, this approach has problems. Every time we define a class method, we need to create
a new object to represent property descriptor. This can be removed if we can introduce
a special bytecode or special function.

This patch introduces new bytecodes, op_define_data_property and op_define_accessor_property.
Instead of taking an object, they takes several registers to avoid object allocations.
We're planning to use this bytecode to implement Object.defineProperty in builtin JS next.
This allows us to leverage object allocation sinking. And it also gives us a chance to use
faster ::get and ::hasProperty in JS.

Originally, I attempted to create one bytecode, op_define_property. However, it takes too many
children in DFG and uses so many registers in DFG. This leads tricky program in 32bit platforms.
Furthermore, it does not fit to the number of x64 argument registers. So instead, we introduce
two bytecodes.

And for op_define_accessor_property, we perform CellUse edge filter to getter and setter children.
This edge filter makes us possible to use SpeculateCellOperand and reduce the number of used registers
in comparison with JSValueOperand. To make children Cells even if we do not specify some accessors (for
example, { get: func, set: null } case), we fill registers with special throwTypeErrorFunction.
The attributes bitset keep information like "This property descriptor only has getter slot".

In these two bytecodes, we take attributes (configurable, enumerable, writable, hasGetter etc.) as
register instead of embedding constant int value because we will use these bytecodes to implement
Object.defineProperty next. In Object.defineProperty case, an attributes are not statically defined
at bytecode compiling time.

Run ES6SampleBench/Air 20 times. The result shows ~2% performance improvement.

Baseline:
    firstIteration:     84.05 ms +- 4.37 ms
    averageWorstCase:   40.54 ms +- 2.81 ms
    steadyState:        3317.49 ms +- 48.25 ms
    summary:            223.51 ms +- 5.07 ms

Patched:
    firstIteration:     84.46 ms +- 4.22 ms
    averageWorstCase:   41.48 ms +- 2.33 ms
    steadyState:        3253.48 ms +- 29.31 ms
    summary:            224.40 ms +- 4.72 ms

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/SpecialPointer.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitMoveLinkTimeConstant):
(JSC::BytecodeGenerator::emitCallDefineProperty):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::PropertyListNode::emitPutConstantProperty):
(JSC::BitwiseNotNode::emitBytecode):
(JSC::ClassExprNode::emitBytecode):
(JSC::ObjectPatternNode::bindValue):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileDefineDataProperty):
(JSC::DFG::SpeculativeJIT::compileDefineAccessorProperty):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileDefineDataProperty):
(JSC::FTL::DFG::LowerDFGToB3::compileDefineAccessorProperty):
(JSC::FTL::DFG::LowerDFGToB3::compilePutByValWithThis): Deleted.
* jit/CCallHelpers.cpp:
(JSC::CCallHelpers::setupFourStubArgsGPR): Deleted.
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupFourStubArgsGPR):
(JSC::CCallHelpers::setupFiveStubArgsGPR):
(JSC::CCallHelpers::setupArgumentsWithExecState):
(JSC::CCallHelpers::setupStubArgsGPR):
(JSC::CCallHelpers::prepareForTailCallSlow): Deleted.
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_define_data_property):
(JSC::JIT::emit_op_define_accessor_property):
* llint/LowLevelInterpreter.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/DefinePropertyAttributes.h: Added.
(JSC::DefinePropertyAttributes::DefinePropertyAttributes):
(JSC::DefinePropertyAttributes::rawRepresentation):
(JSC::DefinePropertyAttributes::hasValue):
(JSC::DefinePropertyAttributes::setValue):
(JSC::DefinePropertyAttributes::hasGet):
(JSC::DefinePropertyAttributes::setGet):
(JSC::DefinePropertyAttributes::hasSet):
(JSC::DefinePropertyAttributes::setSet):
(JSC::DefinePropertyAttributes::writable):
(JSC::DefinePropertyAttributes::configurable):
(JSC::DefinePropertyAttributes::enumerable):
(JSC::DefinePropertyAttributes::setWritable):
(JSC::DefinePropertyAttributes::setConfigurable):
(JSC::DefinePropertyAttributes::setEnumerable):
(JSC::DefinePropertyAttributes::fillWithTriState):
(JSC::DefinePropertyAttributes::extractTriState):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::throwTypeErrorFunction):
(JSC::JSGlobalObject::definePropertyFunction): Deleted.
* runtime/ObjectConstructor.cpp:
(JSC::ObjectConstructor::addDefineProperty): Deleted.
* runtime/ObjectConstructor.h:
* runtime/PropertyDescriptor.h:
(JSC::toPropertyDescriptor):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206778 268f45cc-cd09-0410-ab3c-d52691b4dbfc

41 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/SpecialPointer.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/CCallHelpers.cpp
Source/JavaScriptCore/jit/CCallHelpers.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/DefinePropertyAttributes.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/ObjectConstructor.cpp
Source/JavaScriptCore/runtime/ObjectConstructor.h
Source/JavaScriptCore/runtime/PropertyDescriptor.h

index e793aa2..5dd7678 100644 (file)
@@ -1,3 +1,155 @@
+2016-09-27  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Add a new byte code op_define_property instead of calling defineProperty
+        https://bugs.webkit.org/show_bug.cgi?id=162108
+
+        Reviewed by Saam Barati.
+
+        To construct ES6 class, we emitted bytecode that performs the following operations.
+
+            1. construct a new object
+            2. put "configurable", "enumerable" etc. fields
+            3. call "defineProperty" function
+
+        However, this approach has problems. Every time we define a class method, we need to create
+        a new object to represent property descriptor. This can be removed if we can introduce
+        a special bytecode or special function.
+
+        This patch introduces new bytecodes, op_define_data_property and op_define_accessor_property.
+        Instead of taking an object, they takes several registers to avoid object allocations.
+        We're planning to use this bytecode to implement Object.defineProperty in builtin JS next.
+        This allows us to leverage object allocation sinking. And it also gives us a chance to use
+        faster ::get and ::hasProperty in JS.
+
+        Originally, I attempted to create one bytecode, op_define_property. However, it takes too many
+        children in DFG and uses so many registers in DFG. This leads tricky program in 32bit platforms.
+        Furthermore, it does not fit to the number of x64 argument registers. So instead, we introduce
+        two bytecodes.
+
+        And for op_define_accessor_property, we perform CellUse edge filter to getter and setter children.
+        This edge filter makes us possible to use SpeculateCellOperand and reduce the number of used registers
+        in comparison with JSValueOperand. To make children Cells even if we do not specify some accessors (for
+        example, { get: func, set: null } case), we fill registers with special throwTypeErrorFunction.
+        The attributes bitset keep information like "This property descriptor only has getter slot".
+
+        In these two bytecodes, we take attributes (configurable, enumerable, writable, hasGetter etc.) as
+        register instead of embedding constant int value because we will use these bytecodes to implement
+        Object.defineProperty next. In Object.defineProperty case, an attributes are not statically defined
+        at bytecode compiling time.
+
+        Run ES6SampleBench/Air 20 times. The result shows ~2% performance improvement.
+
+        Baseline:
+            firstIteration:     84.05 ms +- 4.37 ms
+            averageWorstCase:   40.54 ms +- 2.81 ms
+            steadyState:        3317.49 ms +- 48.25 ms
+            summary:            223.51 ms +- 5.07 ms
+
+        Patched:
+            firstIteration:     84.46 ms +- 4.22 ms
+            averageWorstCase:   41.48 ms +- 2.33 ms
+            steadyState:        3253.48 ms +- 29.31 ms
+            summary:            224.40 ms +- 4.72 ms
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/SpecialPointer.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitMoveLinkTimeConstant):
+        (JSC::BytecodeGenerator::emitCallDefineProperty):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PropertyListNode::emitPutConstantProperty):
+        (JSC::BitwiseNotNode::emitBytecode):
+        (JSC::ClassExprNode::emitBytecode):
+        (JSC::ObjectPatternNode::bindValue):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDefineDataProperty):
+        (JSC::DFG::SpeculativeJIT::compileDefineAccessorProperty):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileDefineDataProperty):
+        (JSC::FTL::DFG::LowerDFGToB3::compileDefineAccessorProperty):
+        (JSC::FTL::DFG::LowerDFGToB3::compilePutByValWithThis): Deleted.
+        * jit/CCallHelpers.cpp:
+        (JSC::CCallHelpers::setupFourStubArgsGPR): Deleted.
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::setupFourStubArgsGPR):
+        (JSC::CCallHelpers::setupFiveStubArgsGPR):
+        (JSC::CCallHelpers::setupArgumentsWithExecState):
+        (JSC::CCallHelpers::setupStubArgsGPR):
+        (JSC::CCallHelpers::prepareForTailCallSlow): Deleted.
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_define_data_property):
+        (JSC::JIT::emit_op_define_accessor_property):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        * runtime/DefinePropertyAttributes.h: Added.
+        (JSC::DefinePropertyAttributes::DefinePropertyAttributes):
+        (JSC::DefinePropertyAttributes::rawRepresentation):
+        (JSC::DefinePropertyAttributes::hasValue):
+        (JSC::DefinePropertyAttributes::setValue):
+        (JSC::DefinePropertyAttributes::hasGet):
+        (JSC::DefinePropertyAttributes::setGet):
+        (JSC::DefinePropertyAttributes::hasSet):
+        (JSC::DefinePropertyAttributes::setSet):
+        (JSC::DefinePropertyAttributes::writable):
+        (JSC::DefinePropertyAttributes::configurable):
+        (JSC::DefinePropertyAttributes::enumerable):
+        (JSC::DefinePropertyAttributes::setWritable):
+        (JSC::DefinePropertyAttributes::setConfigurable):
+        (JSC::DefinePropertyAttributes::setEnumerable):
+        (JSC::DefinePropertyAttributes::fillWithTriState):
+        (JSC::DefinePropertyAttributes::extractTriState):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::throwTypeErrorFunction):
+        (JSC::JSGlobalObject::definePropertyFunction): Deleted.
+        * runtime/ObjectConstructor.cpp:
+        (JSC::ObjectConstructor::addDefineProperty): Deleted.
+        * runtime/ObjectConstructor.h:
+        * runtime/PropertyDescriptor.h:
+        (JSC::toPropertyDescriptor):
+
 2016-10-04  Saam Barati  <sbarati@apple.com>
 
         Follow up fix to GetMapBucket and MapHash speculating on child node types.
index 6ee5772..9579f7a 100644 (file)
                FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FEF040511AAE662D00BD28B0 /* CompareAndSwapTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */; };
                FEFD6FC61D5E7992008F2F0B /* JSStringInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FEFD6FC51D5E7970008F2F0B /* JSStringInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               473DA4A4764C45FE871B0485 /* DefinePropertyAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
                FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompareAndSwapTest.cpp; path = API/tests/CompareAndSwapTest.cpp; sourceTree = "<group>"; };
                FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompareAndSwapTest.h; path = API/tests/CompareAndSwapTest.h; sourceTree = "<group>"; };
                FEFD6FC51D5E7970008F2F0B /* JSStringInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringInlines.h; sourceTree = "<group>"; };
+               169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DefinePropertyAttributes.h; path = DefinePropertyAttributes.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                                709FB8661AE335C60039D069 /* WeakSetPrototype.h */,
                                A7DCB77912E3D90500911940 /* WriteBarrier.h */,
                                C2B6D75218A33793004A9301 /* WriteBarrierInlines.h */,
+                               169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */,
                        );
                        path = runtime;
                        sourceTree = "<group>";
                                86704B4312DB8A8100A9FE7B /* YarrSyntaxChecker.h in Headers */,
                                A79D3ED9C5064DD0A8466A3A /* ModuleScopeData.h in Headers */,
                                D9722752DC54459B9125B539 /* JSModuleLoader.h in Headers */,
+                               473DA4A4764C45FE871B0485 /* DefinePropertyAttributes.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index dc59980..576de40 100644 (file)
@@ -81,6 +81,8 @@
             { "name" : "op_put_getter_setter_by_id", "length" : 6 },
             { "name" : "op_put_getter_by_val", "length" : 5 },
             { "name" : "op_put_setter_by_val", "length" : 5 },
+            { "name" : "op_define_data_property", "length" : 5 },
+            { "name" : "op_define_accessor_property", "length" : 6 },
             { "name" : "op_jmp", "length" : 2 },
             { "name" : "op_jtrue", "length" : 3 },
             { "name" : "op_jfalse", "length" : 3 },
index 46e8957..d973bcf 100644 (file)
@@ -143,6 +143,23 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
         functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
         return;
     }
+    case op_define_data_property: {
+        ASSERT(opcodeLengths[opcodeID] > 4);
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
+    case op_define_accessor_property: {
+        ASSERT(opcodeLengths[opcodeID] > 5);
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[5].u.operand);
+        return;
+    }
     case op_get_property_enumerator:
     case op_get_enumerable_length:
     case op_new_func_exp:
@@ -331,6 +348,8 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_put_by_val:
     case op_put_by_val_direct:
     case op_put_by_index:
+    case op_define_data_property:
+    case op_define_accessor_property:
     case op_profile_type:
     case op_profile_control_flow:
     case op_put_to_arguments:
index 8bd9cbc..960e1ef 100644 (file)
@@ -1235,6 +1235,25 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s, %d, %s", registerName(r0).data(), registerName(r1).data(), n0, registerName(r2).data());
             break;
         }
+        case op_define_data_property: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int r3 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "define_data_property");
+            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+            break;
+        }
+        case op_define_accessor_property: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int r3 = (++it)->u.operand;
+            int r4 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "define_accessor_property");
+            out.printf("%s, %s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), registerName(r4).data());
+            break;
+        }
         case op_del_by_id: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
index 04eab6c..21329ec 100644 (file)
@@ -41,7 +41,7 @@ enum Pointer {
 } // namespace Special
 
 enum class LinkTimeConstant {
-    DefinePropertyFunction,
+    ThrowTypeErrorFunction,
 };
 const unsigned LinkTimeConstantCount = 1;
 
index bad5571..1beec08 100644 (file)
@@ -35,6 +35,7 @@
 #include "BuiltinExecutables.h"
 #include "BytecodeGeneratorification.h"
 #include "BytecodeLivenessAnalysis.h"
+#include "DefinePropertyAttributes.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
 #include "JSGeneratorFunction.h"
@@ -1543,6 +1544,9 @@ RegisterID* BytecodeGenerator::emitMoveLinkTimeConstant(RegisterID* dst, LinkTim
         m_linkTimeConstantRegisters[constantIndex] = &m_constantPoolRegisters[index];
     }
 
+    if (!dst)
+        return m_linkTimeConstantRegisters[constantIndex];
+
     emitOpcode(op_mov);
     instructions().append(dst->index());
     instructions().append(m_linkTimeConstantRegisters[constantIndex]->index());
@@ -3274,38 +3278,59 @@ void BytecodeGenerator::emitLogShadowChickenTailIfNecessary()
 }
 
 void BytecodeGenerator::emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister,
-    RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition& position)
+    RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options)
 {
-    RefPtr<RegisterID> descriptorRegister = emitNewObject(newTemporary());
-
-    RefPtr<RegisterID> trueRegister = emitLoad(newTemporary(), true);
+    DefinePropertyAttributes attributes;
     if (options & PropertyConfigurable)
-        emitDirectPutById(descriptorRegister.get(), propertyNames().configurable, trueRegister.get(), PropertyNode::Unknown);
+        attributes.setConfigurable(true);
+
     if (options & PropertyWritable)
-        emitDirectPutById(descriptorRegister.get(), propertyNames().writable, trueRegister.get(), PropertyNode::Unknown);
-    else if (valueRegister) {
-        RefPtr<RegisterID> falseRegister = emitLoad(newTemporary(), false);
-        emitDirectPutById(descriptorRegister.get(), propertyNames().writable, falseRegister.get(), PropertyNode::Unknown);
-    }
+        attributes.setWritable(true);
+    else if (valueRegister)
+        attributes.setWritable(false);
+
     if (options & PropertyEnumerable)
-        emitDirectPutById(descriptorRegister.get(), propertyNames().enumerable, trueRegister.get(), PropertyNode::Unknown);
+        attributes.setEnumerable(true);
 
     if (valueRegister)
-        emitDirectPutById(descriptorRegister.get(), propertyNames().value, valueRegister, PropertyNode::Unknown);
+        attributes.setValue();
     if (getterRegister)
-        emitDirectPutById(descriptorRegister.get(), propertyNames().get, getterRegister, PropertyNode::Unknown);
+        attributes.setGet();
     if (setterRegister)
-        emitDirectPutById(descriptorRegister.get(), propertyNames().set, setterRegister, PropertyNode::Unknown);
+        attributes.setSet();
 
-    RefPtr<RegisterID> definePropertyRegister = emitMoveLinkTimeConstant(newTemporary(), LinkTimeConstant::DefinePropertyFunction);
+    ASSERT(!valueRegister || (!getterRegister && !setterRegister));
 
-    CallArguments callArguments(*this, nullptr, 3);
-    emitLoad(callArguments.thisRegister(), jsUndefined());
-    emitMove(callArguments.argumentRegister(0), newObj);
-    emitMove(callArguments.argumentRegister(1), propertyNameRegister);
-    emitMove(callArguments.argumentRegister(2), descriptorRegister.get());
+    if (attributes.hasGet() || attributes.hasSet()) {
+        RefPtr<RegisterID> throwTypeErrorFunction;
+        if (!attributes.hasGet() || !attributes.hasSet())
+            throwTypeErrorFunction = emitMoveLinkTimeConstant(nullptr, LinkTimeConstant::ThrowTypeErrorFunction);
 
-    emitCall(newTemporary(), definePropertyRegister.get(), NoExpectedFunction, callArguments, position, position, position, DebuggableCall::No);
+        RefPtr<RegisterID> getter;
+        if (attributes.hasGet())
+            getter = getterRegister;
+        else
+            getter = throwTypeErrorFunction;
+
+        RefPtr<RegisterID> setter;
+        if (attributes.hasSet())
+            setter = setterRegister;
+        else
+            setter = throwTypeErrorFunction;
+
+        emitOpcode(op_define_accessor_property);
+        instructions().append(newObj->index());
+        instructions().append(propertyNameRegister->index());
+        instructions().append(getter->index());
+        instructions().append(setter->index());
+        instructions().append(emitLoad(nullptr, jsNumber(attributes.rawRepresentation()))->index());
+    } else {
+        emitOpcode(op_define_data_property);
+        instructions().append(newObj->index());
+        instructions().append(propertyNameRegister->index());
+        instructions().append(valueRegister->index());
+        instructions().append(emitLoad(nullptr, jsNumber(attributes.rawRepresentation()))->index());
+    }
 }
 
 RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
index 3e56ca7..6d70d35 100644 (file)
@@ -588,7 +588,7 @@ namespace JSC {
             PropertyEnumerable   = 1 << 2,
         };
         void emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister,
-            RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition&);
+            RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options);
 
         void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack, ForOfNode* = nullptr, RegisterID* forLoopSymbolTable = nullptr);
 
index df19c1c..f82836c 100644 (file)
@@ -590,12 +590,12 @@ void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, Reg
         ASSERT(node.needsSuperBinding());
         RefPtr<RegisterID> propertyNameRegister;
         if (node.name())
-            propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node.name());
+            propertyNameRegister = generator.emitLoad(nullptr, *node.name());
         else
             propertyNameRegister = generator.emitNode(node.m_expression);
 
         generator.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyNameRegister.get());
-        generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position);
+        generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable);
         return;
     }
     if (const auto* identifier = node.name()) {
@@ -605,7 +605,7 @@ void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, Reg
             return;
         }
 
-        RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(optionalIndex.value()));
+        RefPtr<RegisterID> index = generator.emitLoad(nullptr, jsNumber(optionalIndex.value()));
         generator.emitDirectPutByVal(newObj, index.get(), value.get());
         return;
     }
@@ -1623,7 +1623,7 @@ RegisterID* UnaryPlusNode::emitBytecode(BytecodeGenerator& generator, RegisterID
  
 RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<RegisterID> src2 = generator.emitLoad(generator.newTemporary(), jsNumber(-1));
+    RefPtr<RegisterID> src2 = generator.emitLoad(nullptr, jsNumber(-1));
     RefPtr<RegisterID> src1 = generator.emitNode(m_expr);
     return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32()));
 }
@@ -3609,12 +3609,12 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID
         emitPutHomeObject(generator, constructor.get(), prototype.get());
     }
 
-    RefPtr<RegisterID> constructorNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.constructor);
+    RefPtr<RegisterID> constructorNameRegister = generator.emitLoad(nullptr, propertyNames.constructor);
     generator.emitCallDefineProperty(prototype.get(), constructorNameRegister.get(), constructor.get(), nullptr, nullptr,
-        BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position);
+        BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable);
 
-    RefPtr<RegisterID> prototypeNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.prototype);
-    generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position);
+    RefPtr<RegisterID> prototypeNameRegister = generator.emitLoad(nullptr, propertyNames.prototype);
+    generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0);
 
     if (m_staticMethods)
         generator.emitNode(constructor.get(), m_staticMethods);
@@ -3876,7 +3876,7 @@ void ObjectPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs)
             if (!optionalIndex)
                 generator.emitGetById(temp.get(), rhs, target.propertyName);
             else {
-                RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(optionalIndex.value()));
+                RefPtr<RegisterID> index = generator.emitLoad(nullptr, jsNumber(optionalIndex.value()));
                 generator.emitGetByVal(temp.get(), rhs, index.get());
             }
         } else {
index 9db13e3..ce6bef9 100644 (file)
@@ -2656,6 +2656,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         clobberWorld(node->origin.semantic, clobberLimit);
         break;
     }
+
+    case DefineDataProperty:
+    case DefineAccessorProperty:
+        clobberWorld(node->origin.semantic, clobberLimit);
+        break;
         
     case In: {
         // FIXME: We can determine when the property definitely exists based on abstract
index 0452280..0b5fb95 100644 (file)
@@ -4238,6 +4238,38 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_put_by_val_with_this);
         }
 
+        case op_define_data_property: {
+            Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* property = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* value = get(VirtualRegister(currentInstruction[3].u.operand));
+            Node* attributes = get(VirtualRegister(currentInstruction[4].u.operand));
+
+            addVarArgChild(base);
+            addVarArgChild(property);
+            addVarArgChild(value);
+            addVarArgChild(attributes);
+            addToGraph(Node::VarArg, DefineDataProperty, OpInfo(0), OpInfo(0));
+
+            NEXT_OPCODE(op_define_data_property);
+        }
+
+        case op_define_accessor_property: {
+            Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* property = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* getter = get(VirtualRegister(currentInstruction[3].u.operand));
+            Node* setter = get(VirtualRegister(currentInstruction[4].u.operand));
+            Node* attributes = get(VirtualRegister(currentInstruction[5].u.operand));
+
+            addVarArgChild(base);
+            addVarArgChild(property);
+            addVarArgChild(getter);
+            addVarArgChild(setter);
+            addVarArgChild(attributes);
+            addToGraph(Node::VarArg, DefineAccessorProperty, OpInfo(0), OpInfo(0));
+
+            NEXT_OPCODE(op_define_accessor_property);
+        }
+
         case op_try_get_by_id:
         case op_get_by_id:
         case op_get_by_id_proto_load:
index 48fa495..c323d46 100644 (file)
@@ -173,6 +173,8 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_put_getter_setter_by_id:
     case op_put_getter_by_val:
     case op_put_setter_by_val:
+    case op_define_data_property:
+    case op_define_accessor_property:
     case op_del_by_id:
     case op_del_by_val:
     case op_jmp:
index 87d8b52..1e555fe 100644 (file)
@@ -494,6 +494,8 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case PutGetterSetterById:
     case PutGetterByVal:
     case PutSetterByVal:
+    case DefineDataProperty:
+    case DefineAccessorProperty:
     case DeleteById:
     case DeleteByVal:
     case ArrayPush:
index 0ad54fe..3185596 100644 (file)
@@ -111,6 +111,8 @@ bool doesGC(Graph& graph, Node* node)
     case PutGetterSetterById:
     case PutGetterByVal:
     case PutSetterByVal:
+    case DefineDataProperty:
+    case DefineAccessorProperty:
     case DeleteById:
     case DeleteByVal:
     case CheckStructure:
index 8001911..fd6dd54 100644 (file)
@@ -1657,6 +1657,39 @@ private:
             break;
         }
 
+        case DefineDataProperty: {
+            fixEdge<CellUse>(m_graph.varArgChild(node, 0));
+            Edge& propertyEdge = m_graph.varArgChild(node, 1);
+            if (propertyEdge->shouldSpeculateSymbol())
+                fixEdge<SymbolUse>(propertyEdge);
+            else if (propertyEdge->shouldSpeculateStringIdent())
+                fixEdge<StringIdentUse>(propertyEdge);
+            else if (propertyEdge->shouldSpeculateString())
+                fixEdge<StringUse>(propertyEdge);
+            else
+                fixEdge<UntypedUse>(propertyEdge);
+            fixEdge<UntypedUse>(m_graph.varArgChild(node, 2));
+            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 3));
+            break;
+        }
+
+        case DefineAccessorProperty: {
+            fixEdge<CellUse>(m_graph.varArgChild(node, 0));
+            Edge& propertyEdge = m_graph.varArgChild(node, 1);
+            if (propertyEdge->shouldSpeculateSymbol())
+                fixEdge<SymbolUse>(propertyEdge);
+            else if (propertyEdge->shouldSpeculateStringIdent())
+                fixEdge<StringIdentUse>(propertyEdge);
+            else if (propertyEdge->shouldSpeculateString())
+                fixEdge<StringUse>(propertyEdge);
+            else
+                fixEdge<UntypedUse>(propertyEdge);
+            fixEdge<CellUse>(m_graph.varArgChild(node, 2));
+            fixEdge<CellUse>(m_graph.varArgChild(node, 3));
+            fixEdge<KnownInt32Use>(m_graph.varArgChild(node, 4));
+            break;
+        }
+
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:
@@ -1726,8 +1759,6 @@ private:
         case GetByValWithThis:
         case CompareEqPtr:
             break;
-            
-            break;
 #else
         default:
             break;
index 8b4d9f0..d5ada89 100644 (file)
@@ -198,6 +198,8 @@ namespace JSC { namespace DFG {
     macro(PutGetterSetterById, NodeMustGenerate) \
     macro(PutGetterByVal, NodeMustGenerate) \
     macro(PutSetterByVal, NodeMustGenerate) \
+    macro(DefineDataProperty, NodeMustGenerate | NodeHasVarArgs) \
+    macro(DefineAccessorProperty, NodeMustGenerate | NodeHasVarArgs) \
     macro(DeleteById, NodeResultBoolean | NodeMustGenerate) \
     macro(DeleteByVal, NodeResultBoolean | NodeMustGenerate) \
     macro(CheckStructure, NodeMustGenerate) \
index 99829cb..3aed72c 100644 (file)
@@ -38,6 +38,7 @@
 #include "DFGToFTLDeferredCompilationCallback.h"
 #include "DFGToFTLForOSREntryDeferredCompilationCallback.h"
 #include "DFGWorklist.h"
+#include "DefinePropertyAttributes.h"
 #include "DirectArguments.h"
 #include "FTLForOSREntryJITCode.h"
 #include "FTLOSREntry.h"
@@ -994,6 +995,98 @@ void JIT_OPERATION operationPutByValWithThis(ExecState* exec, EncodedJSValue enc
     putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, property);
 }
 
+ALWAYS_INLINE static void defineDataProperty(ExecState* exec, VM& vm, JSObject* base, const Identifier& propertyName, JSValue value, int32_t attributes)
+{
+    PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes));
+    ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
+    if (base->methodTable(vm)->defineOwnProperty == JSObject::defineOwnProperty)
+        JSObject::defineOwnProperty(base, exec, propertyName, descriptor, true);
+    else
+        base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
+}
+
+void JIT_OPERATION operationDefineDataProperty(ExecState* exec, JSObject* base, EncodedJSValue encodedProperty, EncodedJSValue encodedValue, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Identifier propertyName = JSValue::decode(encodedProperty).toPropertyKey(exec);
+    RETURN_IF_EXCEPTION(scope, void());
+    defineDataProperty(exec, vm, base, propertyName, JSValue::decode(encodedValue), attributes);
+}
+
+void JIT_OPERATION operationDefineDataPropertyString(ExecState* exec, JSObject* base, JSString* property, EncodedJSValue encodedValue, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Identifier propertyName = property->toIdentifier(exec);
+    RETURN_IF_EXCEPTION(scope, void());
+    defineDataProperty(exec, vm, base, propertyName, JSValue::decode(encodedValue), attributes);
+}
+
+void JIT_OPERATION operationDefineDataPropertyStringIdent(ExecState* exec, JSObject* base, UniquedStringImpl* property, EncodedJSValue encodedValue, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    defineDataProperty(exec, vm, base, Identifier::fromUid(&vm, property), JSValue::decode(encodedValue), attributes);
+}
+
+void JIT_OPERATION operationDefineDataPropertySymbol(ExecState* exec, JSObject* base, Symbol* property, EncodedJSValue encodedValue, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    defineDataProperty(exec, vm, base, Identifier::fromUid(property->privateName()), JSValue::decode(encodedValue), attributes);
+}
+
+ALWAYS_INLINE static void defineAccessorProperty(ExecState* exec, VM& vm, JSObject* base, const Identifier& propertyName, JSObject* getter, JSObject* setter, int32_t attributes)
+{
+    PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes));
+    ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
+    if (base->methodTable(vm)->defineOwnProperty == JSObject::defineOwnProperty)
+        JSObject::defineOwnProperty(base, exec, propertyName, descriptor, true);
+    else
+        base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
+}
+
+void JIT_OPERATION operationDefineAccessorProperty(ExecState* exec, JSObject* base, EncodedJSValue encodedProperty, JSObject* getter, JSObject* setter, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Identifier propertyName = JSValue::decode(encodedProperty).toPropertyKey(exec);
+    RETURN_IF_EXCEPTION(scope, void());
+    defineAccessorProperty(exec, vm, base, propertyName, getter, setter, attributes);
+}
+
+void JIT_OPERATION operationDefineAccessorPropertyString(ExecState* exec, JSObject* base, JSString* property, JSObject* getter, JSObject* setter, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Identifier propertyName = property->toIdentifier(exec);
+    RETURN_IF_EXCEPTION(scope, void());
+    defineAccessorProperty(exec, vm, base, propertyName, getter, setter, attributes);
+}
+
+void JIT_OPERATION operationDefineAccessorPropertyStringIdent(ExecState* exec, JSObject* base, UniquedStringImpl* property, JSObject* getter, JSObject* setter, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    defineAccessorProperty(exec, vm, base, Identifier::fromUid(&vm, property), getter, setter, attributes);
+}
+
+void JIT_OPERATION operationDefineAccessorPropertySymbol(ExecState* exec, JSObject* base, Symbol* property, JSObject* getter, JSObject* setter, int32_t attributes)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    defineAccessorProperty(exec, vm, base, Identifier::fromUid(property->privateName()), getter, setter, attributes);
+}
+
 char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
 {
     VM* vm = &exec->vm();
index 96d9f00..11c2b8c 100644 (file)
@@ -113,6 +113,14 @@ void JIT_OPERATION operationPutByIdWithThis(ExecState*, EncodedJSValue, EncodedJ
 void JIT_OPERATION operationPutByIdWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 void JIT_OPERATION operationPutByValWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+void JIT_OPERATION operationDefineDataProperty(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineDataPropertyString(ExecState*, JSObject*, JSString*, EncodedJSValue, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineDataPropertyStringIdent(ExecState*, JSObject*, UniquedStringImpl*, EncodedJSValue, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineDataPropertySymbol(ExecState*, JSObject*, Symbol*, EncodedJSValue, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineAccessorProperty(ExecState*, JSObject*, EncodedJSValue, JSObject*, JSObject*, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineAccessorPropertyString(ExecState*, JSObject*, JSString*, JSObject*, JSObject*, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineAccessorPropertyStringIdent(ExecState*, JSObject*, UniquedStringImpl*, JSObject*, JSObject*, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationDefineAccessorPropertySymbol(ExecState*, JSObject*, Symbol*, JSObject*, JSObject*, int32_t) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
index bafdf90..459418a 100644 (file)
@@ -1041,6 +1041,8 @@ private:
         case PutGetterSetterById:
         case PutGetterByVal:
         case PutSetterByVal:
+        case DefineDataProperty:
+        case DefineAccessorProperty:
         case DFG::Jump:
         case Branch:
         case Switch:
index bddd466..abe672a 100644 (file)
@@ -213,6 +213,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case PutGetterSetterById:
     case PutGetterByVal:
     case PutSetterByVal:
+    case DefineDataProperty:
+    case DefineAccessorProperty:
     case CheckStructure:
     case GetExecutable:
     case GetButterfly:
index 10efb72..6b64454 100644 (file)
@@ -8644,6 +8644,165 @@ void SpeculativeJIT::compileCompareEqPtr(Node* node)
     blessedBooleanResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileDefineDataProperty(Node* node)
+{
+#if USE(JSVALUE64)
+    static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
+#else
+    static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
+#endif
+
+    SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
+    GPRReg baseGPR = base.gpr();
+
+    JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
+    JSValueRegs valueRegs = value.jsValueRegs();
+
+    SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 3));
+    GPRReg attributesGPR = attributes.gpr();
+
+    Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
+    switch (propertyEdge.useKind()) {
+    case StringUse: {
+        SpeculateCellOperand property(this, propertyEdge);
+        GPRReg propertyGPR = property.gpr();
+        speculateString(propertyEdge, propertyGPR);
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineDataPropertyString, NoResult, baseGPR, propertyGPR, valueRegs, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    case StringIdentUse: {
+        SpeculateCellOperand property(this, propertyEdge);
+        GPRTemporary ident(this);
+
+        GPRReg propertyGPR = property.gpr();
+        GPRReg identGPR = ident.gpr();
+
+        speculateString(propertyEdge, propertyGPR);
+        speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineDataPropertyStringIdent, NoResult, baseGPR, identGPR, valueRegs, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    case SymbolUse: {
+        SpeculateCellOperand property(this, propertyEdge);
+        GPRReg propertyGPR = property.gpr();
+        speculateSymbol(propertyEdge, propertyGPR);
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineDataPropertySymbol, NoResult, baseGPR, propertyGPR, valueRegs, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    case UntypedUse: {
+        JSValueOperand property(this, propertyEdge);
+        JSValueRegs propertyRegs = property.jsValueRegs();
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineDataProperty, NoResult, baseGPR, propertyRegs, valueRegs, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+
+    noResult(node, UseChildrenCalledExplicitly);
+}
+
+void SpeculativeJIT::compileDefineAccessorProperty(Node* node)
+{
+#if USE(JSVALUE64)
+    static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
+#else
+    static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
+#endif
+
+    SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
+    GPRReg baseGPR = base.gpr();
+
+    SpeculateCellOperand getter(this, m_jit.graph().varArgChild(node, 2));
+    GPRReg getterGPR = getter.gpr();
+
+    SpeculateCellOperand setter(this, m_jit.graph().varArgChild(node, 3));
+    GPRReg setterGPR = setter.gpr();
+
+    SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 4));
+    GPRReg attributesGPR = attributes.gpr();
+
+    Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
+    switch (propertyEdge.useKind()) {
+    case StringUse: {
+        SpeculateCellOperand property(this, propertyEdge);
+        GPRReg propertyGPR = property.gpr();
+        speculateString(propertyEdge, propertyGPR);
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineAccessorPropertyString, NoResult, baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    case StringIdentUse: {
+        SpeculateCellOperand property(this, propertyEdge);
+        GPRTemporary ident(this);
+
+        GPRReg propertyGPR = property.gpr();
+        GPRReg identGPR = ident.gpr();
+
+        speculateString(propertyEdge, propertyGPR);
+        speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineAccessorPropertyStringIdent, NoResult, baseGPR, identGPR, getterGPR, setterGPR, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    case SymbolUse: {
+        SpeculateCellOperand property(this, propertyEdge);
+        GPRReg propertyGPR = property.gpr();
+        speculateSymbol(propertyEdge, propertyGPR);
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineAccessorPropertySymbol, NoResult, baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    case UntypedUse: {
+        JSValueOperand property(this, propertyEdge);
+        JSValueRegs propertyRegs = property.jsValueRegs();
+
+        useChildren(node);
+
+        flushRegisters();
+        callOperation(operationDefineAccessorProperty, NoResult, baseGPR, propertyRegs, getterGPR, setterGPR, attributesGPR);
+        m_jit.exceptionCheck();
+        break;
+    }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+
+    noResult(node, UseChildrenCalledExplicitly);
+}
+
 } } // namespace JSC::DFG
 
 #endif
index ca978f6..1dab921 100644 (file)
@@ -1335,6 +1335,46 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4);
         return appendCall(operation);
     }
+    JITCompiler::Call callOperation(V_JITOperation_EOJJZ operation, GPRReg arg1, JSValueRegs arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg3.payloadGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOJssJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3.payloadGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOIJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3.payloadGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOSymJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3.payloadGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOJOOZ operation, GPRReg arg1, JSValueRegs arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg3, arg4, arg5);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOJssOOZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4, arg5);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOIOOZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4, arg5);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOSymOOZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4, arg5);
+        return appendCall(operation);
+    }
     JITCompiler::Call callOperation(V_JITOperation_EOJIUi operation, GPRReg arg1, GPRReg arg2, UniquedStringImpl* impl, unsigned value)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(impl), TrustedImm32(value));
@@ -1779,7 +1819,46 @@ public:
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR(), arg2.payloadGPR(), arg2.tagGPR(), arg3.payloadGPR(), arg3.tagGPR(), arg4.payloadGPR(), arg4.tagGPR());
         return appendCall(operation);
     }
-
+    JITCompiler::Call callOperation(V_JITOperation_EOJJZ operation, GPRReg arg1, JSValueRegs arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), arg3.payloadGPR(), arg3.tagGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOJssJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3.payloadGPR(), arg3.tagGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOIJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3.payloadGPR(), arg3.tagGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOSymJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3.payloadGPR(), arg3.tagGPR(), arg4);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOJOOZ operation, GPRReg arg1, JSValueRegs arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), arg3, arg4, arg5);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOJssOOZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4, arg5);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOIOOZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4, arg5);
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EOSymOOZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4, arg5);
+        return appendCall(operation);
+    }
     JITCompiler::Call callOperation(V_JITOperation_EOJIUi operation, GPRReg arg1, JSValueRegs arg2, UniquedStringImpl* impl, unsigned value)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), TrustedImmPtr(impl), TrustedImm32(value));
@@ -2570,6 +2649,8 @@ public:
     void compileGetDynamicVar(Node*);
     void compilePutDynamicVar(Node*);
     void compileCompareEqPtr(Node*);
+    void compileDefineDataProperty(Node*);
+    void compileDefineAccessorProperty(Node*);
 
     void moveTrueTo(GPRReg);
     void moveFalseTo(GPRReg);
index 3a10a10..5884638 100644 (file)
@@ -4479,6 +4479,16 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case DefineDataProperty: {
+        compileDefineDataProperty(node);
+        break;
+    }
+
+    case DefineAccessorProperty: {
+        compileDefineAccessorProperty(node);
+        break;
+    }
+
     case GetGlobalLexicalVariable:
     case GetGlobalVar: {
         GPRTemporary resultPayload(this);
index 5eae20d..96a7daf 100644 (file)
@@ -4437,6 +4437,16 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case DefineDataProperty: {
+        compileDefineDataProperty(node);
+        break;
+    }
+
+    case DefineAccessorProperty: {
+        compileDefineAccessorProperty(node);
+        break;
+    }
+
     case GetGlobalLexicalVariable:
     case GetGlobalVar: {
         GPRTemporary result(this);
index b6eb2e5..3cef998 100644 (file)
@@ -263,6 +263,8 @@ inline CapabilityLevel canCompile(Node* node)
     case CompareGreater:
     case CompareGreaterEq:
     case CompareStrictEq:
+    case DefineDataProperty:
+    case DefineAccessorProperty:
         // These are OK.
         break;
 
index bb953b7..25dd667 100644 (file)
@@ -691,6 +691,12 @@ private:
         case PutByValWithThis:
             compilePutByValWithThis();
             break;
+        case DefineDataProperty:
+            compileDefineDataProperty();
+            break;
+        case DefineAccessorProperty:
+            compileDefineAccessorProperty();
+            break;
         case ArrayPush:
             compileArrayPush();
             break;
@@ -2763,6 +2769,71 @@ private:
         vmCall(Void, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis),
             m_callFrame, base, thisValue, property, value);
     }
+
+    void compileDefineDataProperty()
+    {
+        LValue base = lowCell(m_graph.varArgChild(m_node, 0));
+        LValue value  = lowJSValue(m_graph.varArgChild(m_node, 2));
+        LValue attributes = lowInt32(m_graph.varArgChild(m_node, 3));
+        Edge& propertyEdge = m_graph.varArgChild(m_node, 1);
+        switch (propertyEdge.useKind()) {
+        case StringUse: {
+            LValue property = lowString(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineDataPropertyString), m_callFrame, base, property, value, attributes);
+            break;
+        }
+        case StringIdentUse: {
+            LValue property = lowStringIdent(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineDataPropertyStringIdent), m_callFrame, base, property, value, attributes);
+            break;
+        }
+        case SymbolUse: {
+            LValue property = lowSymbol(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineDataPropertySymbol), m_callFrame, base, property, value, attributes);
+            break;
+        }
+        case UntypedUse: {
+            LValue property = lowJSValue(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineDataProperty), m_callFrame, base, property, value, attributes);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+
+    void compileDefineAccessorProperty()
+    {
+        LValue base = lowCell(m_graph.varArgChild(m_node, 0));
+        LValue getter = lowCell(m_graph.varArgChild(m_node, 2));
+        LValue setter = lowCell(m_graph.varArgChild(m_node, 3));
+        LValue attributes = lowInt32(m_graph.varArgChild(m_node, 4));
+        Edge& propertyEdge = m_graph.varArgChild(m_node, 1);
+        switch (propertyEdge.useKind()) {
+        case StringUse: {
+            LValue property = lowString(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineAccessorPropertyString), m_callFrame, base, property, getter, setter, attributes);
+            break;
+        }
+        case StringIdentUse: {
+            LValue property = lowStringIdent(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineAccessorPropertyStringIdent), m_callFrame, base, property, getter, setter, attributes);
+            break;
+        }
+        case SymbolUse: {
+            LValue property = lowSymbol(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineAccessorPropertySymbol), m_callFrame, base, property, getter, setter, attributes);
+            break;
+        }
+        case UntypedUse: {
+            LValue property = lowJSValue(propertyEdge);
+            vmCall(Void, m_out.operation(operationDefineAccessorProperty), m_callFrame, base, property, getter, setter, attributes);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
     
     void compilePutById()
     {
index 75d15a6..3c3df61 100644 (file)
@@ -68,107 +68,6 @@ void CCallHelpers::ensureShadowChickenPacket(GPRReg shadowPacket, GPRReg scratch
     storePtr(scratch2, Address(scratch1NonArgGPR));
 }
 
-#if NUMBER_OF_ARGUMENT_REGISTERS >= 4
-void CCallHelpers::setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD)
-{
-    if (!ASSERT_DISABLED) {
-        RegisterSet destinations(destA, destB, destC, destD);
-        ASSERT_WITH_MESSAGE(destinations.numberOfSetGPRs() == 4, "Destinations should not be aliased.");
-    }
-
-    typedef std::pair<GPRReg, GPRReg> RegPair;
-    Vector<RegPair, 4> pairs;
-
-    if (srcA != destA)
-        pairs.append(std::make_pair(srcA, destA));
-    if (srcB != destB)
-        pairs.append(std::make_pair(srcB, destB));
-    if (srcC != destC)
-        pairs.append(std::make_pair(srcC, destC));
-    if (srcD != destD)
-        pairs.append(std::make_pair(srcD, destD));
-
-
-#if !ASSERT_DISABLED
-    auto numUniqueSources = [&] () -> unsigned {
-        RegisterSet set;
-        for (auto& pair : pairs) {
-            GPRReg source = pair.first;
-            set.set(source);
-        }
-        return set.numberOfSetGPRs();
-    };
-
-    auto numUniqueDests = [&] () -> unsigned {
-        RegisterSet set;
-        for (auto& pair : pairs) {
-            GPRReg dest = pair.second;
-            set.set(dest);
-        }
-        return set.numberOfSetGPRs();
-    };
-#endif
-
-    while (pairs.size()) {
-        RegisterSet freeDestinations;
-        for (auto& pair : pairs) {
-            GPRReg dest = pair.second;
-            freeDestinations.set(dest);
-        }
-        for (auto& pair : pairs) {
-            GPRReg source = pair.first;
-            freeDestinations.clear(source);
-        }
-
-        if (freeDestinations.numberOfSetGPRs()) {
-            bool madeMove = false;
-            for (unsigned i = 0; i < pairs.size(); i++) {
-                auto& pair = pairs[i];
-                GPRReg source = pair.first;
-                GPRReg dest = pair.second;
-                if (freeDestinations.get(dest)) {
-                    move(source, dest);
-                    pairs.remove(i);
-                    madeMove = true;
-                    break;
-                }
-            }
-            ASSERT_UNUSED(madeMove, madeMove);
-            continue;
-        }
-
-        ASSERT(numUniqueDests() == numUniqueSources());
-        ASSERT(numUniqueDests() == pairs.size());
-        // The set of source and destination registers are equivalent sets. This means we don't have
-        // any free destination registers that won't also clobber a source. We get around this by
-        // exchanging registers.
-
-        GPRReg source = pairs[0].first;
-        GPRReg dest = pairs[0].second;
-        swap(source, dest);
-        pairs.remove(0);
-
-        GPRReg newSource = source;
-        for (auto& pair : pairs) {
-            GPRReg source = pair.first;
-            if (source == dest) {
-                pair.first = newSource;
-                break;
-            }
-        }
-
-        // We may have introduced pairs that have the same source and destination. Remove those now.
-        for (unsigned i = 0; i < pairs.size(); i++) {
-            auto& pair = pairs[i];
-            if (pair.first == pair.second) {
-                pairs.remove(i);
-                i--;
-            }
-        }
-    }
-}
-#endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4
-
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index d4322f2..443783d 100644 (file)
@@ -986,7 +986,14 @@ public:
             swap(destB, destC);
     }
 
-    void setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD);
+    void setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD)
+    {
+        setupStubArgsGPR<4>({ { destA, destB, destC, destD } }, { { srcA, srcB, srcC, srcD } });
+    }
+    void setupFiveStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg destE, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD, GPRReg srcE)
+    {
+        setupStubArgsGPR<5>({ { destA, destB, destC, destD, destE } }, { { srcA, srcB, srcC, srcD, srcE } });
+    }
 
 #if CPU(X86_64) || CPU(ARM64)
     template<FPRReg destA, FPRReg destB>
@@ -2183,6 +2190,12 @@ public:
         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
+    {
+        setupFiveStubArgsGPR(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4, GPRInfo::argumentGPR5, arg1, arg2, arg3, arg4, arg5);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3, GPRReg arg4)
     {
         setupStubArguments134(arg1, arg3, arg4);
@@ -2471,6 +2484,105 @@ public:
         // Ready for a jump!
         move(newFramePointer, stackPointerRegister);
     }
+
+#if NUMBER_OF_ARGUMENT_REGISTERS >= 4
+    template<unsigned NumberOfRegisters>
+    void setupStubArgsGPR(std::array<GPRReg, NumberOfRegisters> destinations, std::array<GPRReg, NumberOfRegisters> sources)
+    {
+        if (!ASSERT_DISABLED) {
+            RegisterSet set;
+            for (GPRReg dest : destinations)
+                set.set(dest);
+            ASSERT_WITH_MESSAGE(set.numberOfSetGPRs() == NumberOfRegisters, "Destinations should not be aliased.");
+        }
+
+        typedef std::pair<GPRReg, GPRReg> RegPair;
+        Vector<RegPair, NumberOfRegisters> pairs;
+
+        for (unsigned i = 0; i < NumberOfRegisters; ++i) {
+            if (sources[i] != destinations[i])
+                pairs.append(std::make_pair(sources[i], destinations[i]));
+        }
+
+#if !ASSERT_DISABLED
+        auto numUniqueSources = [&] () -> unsigned {
+            RegisterSet set;
+            for (auto& pair : pairs) {
+                GPRReg source = pair.first;
+                set.set(source);
+            }
+            return set.numberOfSetGPRs();
+        };
+
+        auto numUniqueDests = [&] () -> unsigned {
+            RegisterSet set;
+            for (auto& pair : pairs) {
+                GPRReg dest = pair.second;
+                set.set(dest);
+            }
+            return set.numberOfSetGPRs();
+        };
+#endif
+
+        while (pairs.size()) {
+            RegisterSet freeDestinations;
+            for (auto& pair : pairs) {
+                GPRReg dest = pair.second;
+                freeDestinations.set(dest);
+            }
+            for (auto& pair : pairs) {
+                GPRReg source = pair.first;
+                freeDestinations.clear(source);
+            }
+
+            if (freeDestinations.numberOfSetGPRs()) {
+                bool madeMove = false;
+                for (unsigned i = 0; i < pairs.size(); i++) {
+                    auto& pair = pairs[i];
+                    GPRReg source = pair.first;
+                    GPRReg dest = pair.second;
+                    if (freeDestinations.get(dest)) {
+                        move(source, dest);
+                        pairs.remove(i);
+                        madeMove = true;
+                        break;
+                    }
+                }
+                ASSERT_UNUSED(madeMove, madeMove);
+                continue;
+            }
+
+            ASSERT(numUniqueDests() == numUniqueSources());
+            ASSERT(numUniqueDests() == pairs.size());
+            // The set of source and destination registers are equivalent sets. This means we don't have
+            // any free destination registers that won't also clobber a source. We get around this by
+            // exchanging registers.
+
+            GPRReg source = pairs[0].first;
+            GPRReg dest = pairs[0].second;
+            swap(source, dest);
+            pairs.remove(0);
+
+            GPRReg newSource = source;
+            for (auto& pair : pairs) {
+                GPRReg source = pair.first;
+                if (source == dest) {
+                    pair.first = newSource;
+                    break;
+                }
+            }
+
+            // We may have introduced pairs that have the same source and destination. Remove those now.
+            for (unsigned i = 0; i < pairs.size(); i++) {
+                auto& pair = pairs[i];
+                if (pair.first == pair.second) {
+                    pairs.remove(i);
+                    i--;
+                }
+            }
+        }
+    }
+#endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4
     
     // These operations clobber all volatile registers. They assume that there is room on the top of
     // stack to marshall call arguments.
index 1abe7c4..237d19a 100644 (file)
@@ -322,6 +322,8 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_put_getter_setter_by_id)
         DEFINE_OP(op_put_getter_by_val)
         DEFINE_OP(op_put_setter_by_val)
+        DEFINE_OP(op_define_data_property)
+        DEFINE_OP(op_define_accessor_property)
 
         DEFINE_OP(op_ret)
         DEFINE_OP(op_rshift)
index 99a643b..05de28c 100644 (file)
@@ -566,6 +566,8 @@ namespace JSC {
         void emit_op_put_getter_setter_by_id(Instruction*);
         void emit_op_put_getter_by_val(Instruction*);
         void emit_op_put_setter_by_val(Instruction*);
+        void emit_op_define_data_property(Instruction*);
+        void emit_op_define_accessor_property(Instruction*);
         void emit_op_ret(Instruction*);
         void emit_op_rshift(Instruction*);
         void emit_op_set_function_name(Instruction*);
index 1d4ad38..551a78d 100644 (file)
@@ -58,6 +58,7 @@ class RegExpObject;
 class Register;
 class Structure;
 class StructureStubInfo;
+class Symbol;
 class SymbolTable;
 class WatchpointSet;
 
@@ -110,6 +111,7 @@ typedef char* UnusedPtr;
     Ssi: StructureStubInfo*
     St: Structure*
     Symtab: SymbolTable*
+    Sym: Symbol*
     T: StringImpl*
     V: void
     Vm: VM*
@@ -268,6 +270,14 @@ typedef void (JIT_OPERATION *V_JITOperation_EPZJ)(ExecState*, void*, int32_t, En
 typedef void (JIT_OPERATION *V_JITOperation_ESsiJJI)(ExecState*, StructureStubInfo*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
 typedef void (JIT_OPERATION *V_JITOperation_EJJJI)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
 typedef void (JIT_OPERATION *V_JITOperation_EJJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void (JIT_OPERATION *V_JITOperation_EOJJZ)(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOJssJZ)(ExecState*, JSObject*, JSString*, EncodedJSValue, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOIJZ)(ExecState*, JSObject*, UniquedStringImpl*, EncodedJSValue, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOSymJZ)(ExecState*, JSObject*, Symbol*, EncodedJSValue, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOJOOZ)(ExecState*, JSObject*, EncodedJSValue, JSObject*, JSObject*, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOJssOOZ)(ExecState*, JSObject*, JSString*, JSObject*, JSObject*, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOIOOZ)(ExecState*, JSObject*, UniquedStringImpl*, JSObject*, JSObject*, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_EOSymOOZ)(ExecState*, JSObject*, Symbol*, JSObject*, JSObject*, int32_t);
 typedef void (JIT_OPERATION *V_JITOperation_EWs)(ExecState*, WatchpointSet*);
 typedef void (JIT_OPERATION *V_JITOperation_EZ)(ExecState*, int32_t);
 typedef void (JIT_OPERATION *V_JITOperation_EZJ)(ExecState*, int32_t, EncodedJSValue);
index ada46f6..d7424f1 100644 (file)
@@ -1770,6 +1770,18 @@ JIT::JumpList JIT::emitFloatTypedArrayPutByVal(Instruction* currentInstruction,
     return slowCases;
 }
 
+void JIT::emit_op_define_data_property(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_define_data_property);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_define_accessor_property(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_define_accessor_property);
+    slowPathCall.call();
+}
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index d0f1ecb..97f42b2 100644 (file)
@@ -1458,6 +1458,18 @@ _llint_op_put_setter_by_val:
     dispatch(5)
 
 
+_llint_op_define_data_property:
+    traceExecution()
+    callOpcodeSlowPath(_slow_path_define_data_property)
+    dispatch(5)
+
+
+_llint_op_define_accessor_property:
+    traceExecution()
+    callOpcodeSlowPath(_slow_path_define_accessor_property)
+    dispatch(6)
+
+
 _llint_op_jtrue:
     traceExecution()
     jumpTrueOrFalse(
index caf826d..f25ee81 100644 (file)
@@ -33,6 +33,7 @@
 #include "ClonedArguments.h"
 #include "CodeProfiling.h"
 #include "CommonSlowPathsExceptions.h"
+#include "DefinePropertyAttributes.h"
 #include "DirectArguments.h"
 #include "Error.h"
 #include "ErrorHandlingScope.h"
@@ -930,4 +931,39 @@ SLOW_PATH_DECL(slow_path_put_by_val_with_this)
     END();
 }
 
+SLOW_PATH_DECL(slow_path_define_data_property)
+{
+    BEGIN();
+    JSObject* base = asObject(OP_C(1).jsValue());
+    JSValue property = OP_C(2).jsValue();
+    JSValue value = OP_C(3).jsValue();
+    JSValue attributes = OP_C(4).jsValue();
+    ASSERT(attributes.isInt32());
+
+    auto propertyName = property.toPropertyKey(exec);
+    CHECK_EXCEPTION();
+    PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes.asInt32()));
+    ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
+    base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
+    END();
+}
+
+SLOW_PATH_DECL(slow_path_define_accessor_property)
+{
+    BEGIN();
+    JSObject* base = asObject(OP_C(1).jsValue());
+    JSValue property = OP_C(2).jsValue();
+    JSValue getter = OP_C(3).jsValue();
+    JSValue setter = OP_C(4).jsValue();
+    JSValue attributes = OP_C(5).jsValue();
+    ASSERT(attributes.isInt32());
+
+    auto propertyName = property.toPropertyKey(exec);
+    CHECK_EXCEPTION();
+    PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes.asInt32()));
+    ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
+    base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
+    END();
+}
+
 } // namespace JSC
index a9080d5..f8830d4 100644 (file)
@@ -256,5 +256,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
 SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
 SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this);
 SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_define_accessor_property);
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DefinePropertyAttributes.h b/Source/JavaScriptCore/runtime/DefinePropertyAttributes.h
new file mode 100644 (file)
index 0000000..c2aee71
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Optional.h>
+#include <wtf/TriState.h>
+
+namespace JSC {
+
+class DefinePropertyAttributes {
+public:
+    static_assert(FalseTriState == 0, "FalseTriState is 0.");
+    static_assert(TrueTriState == 1, "TrueTriState is 1.");
+    static_assert(MixedTriState == 2, "MixedTriState is 2.");
+
+    static const unsigned ConfigurableShift = 0;
+    static const unsigned EnumerableShift = 2;
+    static const unsigned WritableShift = 4;
+    static const unsigned ValueShift = 6;
+    static const unsigned GetShift = 7;
+    static const unsigned SetShift = 8;
+
+    DefinePropertyAttributes()
+        : m_attributes(
+            (MixedTriState << ConfigurableShift)
+            | (MixedTriState << EnumerableShift)
+            | (MixedTriState << WritableShift)
+            | (0 << ValueShift)
+            | (0 << GetShift)
+            | (0 << SetShift))
+    {
+    }
+
+    explicit DefinePropertyAttributes(unsigned attributes)
+        : m_attributes(attributes)
+    {
+    }
+
+    unsigned rawRepresentation() const
+    {
+        return m_attributes;
+    }
+
+    bool hasValue() const
+    {
+        return m_attributes & (0b1 << ValueShift);
+    }
+
+    void setValue()
+    {
+        m_attributes = m_attributes | (0b1 << ValueShift);
+    }
+
+    bool hasGet() const
+    {
+        return m_attributes & (0b1 << GetShift);
+    }
+
+    void setGet()
+    {
+        m_attributes = m_attributes | (0b1 << GetShift);
+    }
+
+    bool hasSet() const
+    {
+        return m_attributes & (0b1 << SetShift);
+    }
+
+    void setSet()
+    {
+        m_attributes = m_attributes | (0b1 << SetShift);
+    }
+
+    bool hasWritable() const
+    {
+        return extractTriState(WritableShift) != MixedTriState;
+    }
+
+    Optional<bool> writable() const
+    {
+        if (!hasWritable())
+            return Nullopt;
+        return extractTriState(WritableShift) == TrueTriState;
+    }
+
+    bool hasConfigurable() const
+    {
+        return extractTriState(ConfigurableShift) != MixedTriState;
+    }
+
+    Optional<bool> configurable() const
+    {
+        if (!hasConfigurable())
+            return Nullopt;
+        return extractTriState(ConfigurableShift) == TrueTriState;
+    }
+
+    bool hasEnumerable() const
+    {
+        return extractTriState(EnumerableShift) != MixedTriState;
+    }
+
+    Optional<bool> enumerable() const
+    {
+        if (!hasEnumerable())
+            return Nullopt;
+        return extractTriState(EnumerableShift) == TrueTriState;
+    }
+
+    void setWritable(bool value)
+    {
+        fillWithTriState(value ? TrueTriState : FalseTriState, WritableShift);
+    }
+
+    void setConfigurable(bool value)
+    {
+        fillWithTriState(value ? TrueTriState : FalseTriState, ConfigurableShift);
+    }
+
+    void setEnumerable(bool value)
+    {
+        fillWithTriState(value ? TrueTriState : FalseTriState, EnumerableShift);
+    }
+
+private:
+    void fillWithTriState(TriState state, unsigned shift)
+    {
+        unsigned mask = 0b11 << shift;
+        m_attributes = (m_attributes & ~mask) | (state << shift);
+    }
+
+    TriState extractTriState(unsigned shift) const
+    {
+        return static_cast<TriState>((m_attributes >> shift) & 0b11);
+    }
+
+    unsigned m_attributes;
+};
+
+
+} // namespace JSC
index 4889cc6..3a4ead9 100644 (file)
@@ -404,7 +404,7 @@ void JSGlobalObject::init(VM& vm)
     m_functionProtoHasInstanceSymbolFunction.set(vm, this, hasInstanceSymbolFunction);
     m_throwTypeErrorGetterSetter.initLater(
         [] (const Initializer<GetterSetter>& init) {
-            JSFunction* thrower = JSFunction::create(init.vm, init.owner, 0, String(), globalFuncThrowTypeError);
+            JSFunction* thrower = init.owner->throwTypeErrorFunction();
             GetterSetter* getterSetter = GetterSetter::create(init.vm, init.owner);
             getterSetter->setGetter(init.vm, init.owner, thrower);
             getterSetter->setSetter(init.vm, init.owner, thrower);
@@ -581,8 +581,8 @@ m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, th
     ObjectConstructor* objectConstructor = ObjectConstructor::create(vm, this, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get());
     m_objectConstructor.set(vm, this, objectConstructor);
 
-    JSFunction* definePropertyFunction = m_objectConstructor->addDefineProperty(exec, this);
-    m_definePropertyFunction.set(vm, this, definePropertyFunction);
+    JSFunction* throwTypeErrorFunction = JSFunction::create(vm, this, 0, String(), globalFuncThrowTypeError);
+    m_throwTypeErrorFunction.set(vm, this, throwTypeErrorFunction);
 
     JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get());
     ArrayConstructor* arrayConstructor = ArrayConstructor::create(vm, this, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get(), m_speciesGetterSetter.get());
@@ -803,7 +803,7 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
     m_specialPointers[Special::ObjectConstructor] = objectConstructor;
     m_specialPointers[Special::ArrayConstructor] = arrayConstructor;
 
-    m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::DefinePropertyFunction)] = m_definePropertyFunction.get();
+    m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::ThrowTypeErrorFunction)] = m_throwTypeErrorFunction.get();
 
     if (UNLIKELY(Options::useDollarVM())) {
         JSDollarVMPrototype* dollarVMPrototype = JSDollarVMPrototype::create(vm, this, JSDollarVMPrototype::createStructure(vm, this, m_objectPrototype.get()));
@@ -1066,7 +1066,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_evalFunction);
     visitor.append(&thisObject->m_callFunction);
     visitor.append(&thisObject->m_applyFunction);
-    visitor.append(&thisObject->m_definePropertyFunction);
+    visitor.append(&thisObject->m_throwTypeErrorFunction);
     thisObject->m_arrayProtoToStringFunction.visit(visitor);
     thisObject->m_arrayProtoValuesFunction.visit(visitor);
     thisObject->m_initializePromiseFunction.visit(visitor);
index a228d97..25bde2b 100644 (file)
@@ -233,7 +233,7 @@ public:
     WriteBarrier<JSFunction> m_evalFunction;
     WriteBarrier<JSFunction> m_callFunction;
     WriteBarrier<JSFunction> m_applyFunction;
-    WriteBarrier<JSFunction> m_definePropertyFunction;
+    WriteBarrier<JSFunction> m_throwTypeErrorFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_arrayProtoToStringFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_arrayProtoValuesFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_initializePromiseFunction;
@@ -478,7 +478,7 @@ public:
     JSFunction* evalFunction() const { return m_evalFunction.get(); }
     JSFunction* callFunction() const { return m_callFunction.get(); }
     JSFunction* applyFunction() const { return m_applyFunction.get(); }
-    JSFunction* definePropertyFunction() const { return m_definePropertyFunction.get(); }
+    JSFunction* throwTypeErrorFunction() const { return m_throwTypeErrorFunction.get(); }
     JSFunction* arrayProtoToStringFunction() const { return m_arrayProtoToStringFunction.get(this); }
     JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(this); }
     JSFunction* initializePromiseFunction() const { return m_initializePromiseFunction.get(this); }
index 781fcbc..0fa0ce6 100644 (file)
@@ -107,14 +107,6 @@ void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, Obj
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getOwnPropertyNamesPrivateName(), objectConstructorGetOwnPropertyNames, DontEnum, 1);
 }
 
-JSFunction* ObjectConstructor::addDefineProperty(ExecState* exec, JSGlobalObject* globalObject)
-{
-    VM& vm = exec->vm();
-    JSFunction* definePropertyFunction = JSFunction::create(vm, globalObject, 3, vm.propertyNames->defineProperty.string(), objectConstructorDefineProperty);
-    putDirectWithoutTransition(vm, vm.propertyNames->defineProperty, definePropertyFunction, DontEnum);
-    return definePropertyFunction;
-}
-
 // ES 19.1.1.1 Object([value])
 static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSValue newTarget)
 {
index 351128d..3bf54ba 100644 (file)
@@ -53,8 +53,6 @@ public:
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
-    JSFunction* addDefineProperty(ExecState*, JSGlobalObject*);
-
 protected:
     void finishCreation(VM&, JSGlobalObject*, ObjectPrototype*);
 
index 82b54ac..ce463e1 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "DefinePropertyAttributes.h"
 #include "JSCJSValue.h"
 
 namespace JSC {
@@ -92,4 +93,30 @@ private:
     unsigned m_seenAttributes;
 };
 
-} // namespace JSC
+inline PropertyDescriptor toPropertyDescriptor(JSValue value, JSValue getter, JSValue setter, DefinePropertyAttributes attributes)
+{
+    // We assume that validation is already done.
+    PropertyDescriptor desc;
+
+    if (Optional<bool> enumerable = attributes.enumerable())
+        desc.setEnumerable(enumerable.value());
+
+    if (Optional<bool> configurable = attributes.configurable())
+        desc.setConfigurable(configurable.value());
+
+    if (attributes.hasValue())
+        desc.setValue(value);
+
+    if (Optional<bool> writable = attributes.writable())
+        desc.setWritable(writable.value());
+
+    if (attributes.hasGet())
+        desc.setGetter(getter);
+
+    if (attributes.hasSet())
+        desc.setSetter(setter);
+
+    return desc;
+}
+
+}