Title: [106255] trunk/Source/_javascript_Core
Revision
106255
Author
[email protected]
Date
2012-01-30 10:28:39 -0800 (Mon, 30 Jan 2012)

Log Message

Clean up putDirect
https://bugs.webkit.org/show_bug.cgi?id=76232

Reviewed by Sam Weinig.

Part 3 - merge op_put_getter & op_put_setter.

Putting these separately is inefficient (and makes future optimiation,
e.g. making GetterSetter immutable) harder. Change to emit a single
op_put_getter_setter bytecode op. Ultimately we should probably be
able to merge this with put direct, to create a common op to initialize
object literal properties.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
* bytecode/Opcode.h:
(JSC):
():
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitPutGetterSetter):
* bytecompiler/BytecodeGenerator.h:
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC::PropertyListNode::emitBytecode):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
(JIT):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_getter_setter):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_getter_setter):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* jit/JITStubs.h:
():
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectVirtual):
(JSC::JSObject::putDirectAccessor):
(JSC):
(JSC::putDescriptor):
(JSC::JSObject::defineOwnProperty):
* runtime/JSObject.h:
():
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectWithoutTransition):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (106254 => 106255)


--- trunk/Source/_javascript_Core/ChangeLog	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-01-30 18:28:39 UTC (rev 106255)
@@ -1,3 +1,55 @@
+2012-01-30  Gavin Barraclough  <[email protected]>
+
+        Clean up putDirect
+        https://bugs.webkit.org/show_bug.cgi?id=76232
+
+        Reviewed by Sam Weinig.
+
+        Part 3 - merge op_put_getter & op_put_setter.
+
+        Putting these separately is inefficient (and makes future optimiation,
+        e.g. making GetterSetter immutable) harder. Change to emit a single
+        op_put_getter_setter bytecode op. Ultimately we should probably be
+        able to merge this with put direct, to create a common op to initialize
+        object literal properties.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * bytecode/Opcode.h:
+        (JSC):
+        ():
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitPutGetterSetter):
+        * bytecompiler/BytecodeGenerator.h:
+        (BytecodeGenerator):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PropertyListNode::emitBytecode):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        (JIT):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_put_getter_setter):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_put_getter_setter):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * jit/JITStubs.h:
+        ():
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::putDirectVirtual):
+        (JSC::JSObject::putDirectAccessor):
+        (JSC):
+        (JSC::putDescriptor):
+        (JSC::JSObject::defineOwnProperty):
+        * runtime/JSObject.h:
+        ():
+        (JSC::JSObject::putDirectInternal):
+        (JSC::JSObject::putDirect):
+        (JSC::JSObject::putDirectWithoutTransition):
+
 2012-01-30  Michael Saboff  <[email protected]>
 
         Dromaeo tests call parseSimpleLengthValue() on 8 bit strings

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -902,20 +902,14 @@
             printPutByIdOp(exec, location, it, "put_by_id_generic");
             break;
         }
-        case op_put_getter: {
+        case op_put_getter_setter: {
             int r0 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
-            printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
+            int r2 = (++it)->u.operand;
+            printf("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
             break;
         }
-        case op_put_setter: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
-            break;
-        }
         case op_method_check: {
             printf("[%4d] method_check\n", location);
             break;

Modified: trunk/Source/_javascript_Core/bytecode/Opcode.h (106254 => 106255)


--- trunk/Source/_javascript_Core/bytecode/Opcode.h	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecode/Opcode.h	2012-01-30 18:28:39 UTC (rev 106255)
@@ -132,8 +132,7 @@
         macro(op_put_by_val, 4) \
         macro(op_del_by_val, 4) \
         macro(op_put_by_index, 4) \
-        macro(op_put_getter, 4) \
-        macro(op_put_setter, 4) \
+        macro(op_put_getter_setter, 5) \
         \
         macro(op_jmp, 2) \
         macro(op_jtrue, 3) \

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -1573,24 +1573,15 @@
     return value;
 }
 
-RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
+void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter)
 {
-    emitOpcode(op_put_getter);
+    emitOpcode(op_put_getter_setter);
     instructions().append(base->index());
     instructions().append(addConstant(property));
-    instructions().append(value->index());
-    return value;
+    instructions().append(getter->index());
+    instructions().append(setter->index());
 }
 
-RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
-{
-    emitOpcode(op_put_setter);
-    instructions().append(base->index());
-    instructions().append(addConstant(property));
-    instructions().append(value->index());
-    return value;
-}
-
 RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
 {
     emitOpcode(op_del_by_id);

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (106254 => 106255)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2012-01-30 18:28:39 UTC (rev 106255)
@@ -330,8 +330,7 @@
         RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
         RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
         RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
-        RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value);
-        RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value);
+        void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
 
         RegisterID* emitCall(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
         RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -236,27 +236,79 @@
     
     generator.emitNewObject(newObj.get());
     
-    for (PropertyListNode* p = this; p; p = p->m_next) {
-        RegisterID* value = generator.emitNode(p->m_node->m_assign);
-        
-        switch (p->m_node->m_type) {
-            case PropertyNode::Constant: {
-                generator.emitDirectPutById(newObj.get(), p->m_node->name(), value);
-                break;
+    // Fast case: this loop just handles regular value properties.
+    PropertyListNode* p = this;
+    for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next)
+        generator.emitDirectPutById(newObj.get(), p->m_node->name(), generator.emitNode(p->m_node->m_assign));
+
+    // Were there any get/set properties?
+    if (p) {
+        typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair;
+        typedef HashMap<StringImpl*, GetterSetterPair> GetterSetterMap;
+        GetterSetterMap map;
+
+        // Build a map, pairing get/set values together.
+        for (PropertyListNode* q = p; q; q = q->m_next) {
+            PropertyNode* node = q->m_node;
+            if (node->m_type == PropertyNode::Constant)
+                continue;
+
+            GetterSetterPair pair(node, 0);
+            std::pair<GetterSetterMap::iterator, bool> result = map.add(node->name().impl(), pair);
+            if (!result.second)
+                result.first->second.second = node;
+        }
+
+        // Iterate over the remaining properties in the list.
+        for (; p; p = p->m_next) {
+            PropertyNode* node = p->m_node;
+            RegisterID* value = generator.emitNode(node->m_assign);
+
+            // Handle regular values.
+            if (node->m_type == PropertyNode::Constant) {
+                generator.emitDirectPutById(newObj.get(), node->name(), value);
+                continue;
             }
-            case PropertyNode::Getter: {
-                generator.emitPutGetter(newObj.get(), p->m_node->name(), value);
-                break;
+
+            // This is a get/set property, find its entry in the map.
+            ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter);
+            GetterSetterMap::iterator it = map.find(node->name().impl());
+            ASSERT(it != map.end());
+            GetterSetterPair& pair = it->second;
+
+            // Was this already generated as a part of its partner?
+            if (pair.second == node)
+                continue;
+    
+            // Generate the paired node now.
+            RefPtr<RegisterID> getterReg;
+            RefPtr<RegisterID> setterReg;
+
+            if (node->m_type == PropertyNode::Getter) {
+                getterReg = value;
+                if (pair.second) {
+                    ASSERT(pair.second->m_type == PropertyNode::Setter);
+                    setterReg = generator.emitNode(pair.second->m_assign);
+                } else {
+                    setterReg = generator.newTemporary();
+                    generator.emitLoad(setterReg.get(), jsUndefined());
+                }
+            } else {
+                ASSERT(node->m_type == PropertyNode::Setter);
+                setterReg = value;
+                if (pair.second) {
+                    ASSERT(pair.second->m_type == PropertyNode::Getter);
+                    getterReg = generator.emitNode(pair.second->m_assign);
+                } else {
+                    getterReg = generator.newTemporary();
+                    generator.emitLoad(getterReg.get(), jsUndefined());
+                }
             }
-            case PropertyNode::Setter: {
-                generator.emitPutSetter(newObj.get(), p->m_node->name(), value);
-                break;
-            }
-            default:
-                ASSERT_NOT_REACHED();
+
+            generator.emitPutGetterSetter(newObj.get(), node->name(), getterReg.get(), setterReg.get());
         }
     }
-    
+
     return generator.moveToDestinationIfNeeded(dst, newObj.get());
 }
 

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -4961,52 +4961,41 @@
         int result = vPC[1].u.operand;
         return callFrame->r(result).jsValue();
     }
-    DEFINE_OPCODE(op_put_getter) {
-        /* put_getter base(r) property(id) function(r)
+    DEFINE_OPCODE(op_put_getter_setter) {
+        /* put_getter_setter base(r) property(id) getter(r) setter(r)
 
-           Sets register function on register base as the getter named
-           by identifier property. Base and function are assumed to be
-           objects as this op should only be used for getters defined
-           in object literal form.
+           Puts accessor descriptor to register base as the named
+           identifier property. Base and function may be objects
+           or undefined, this op should only be used for accessors
+           defined in object literal form.
 
            Unlike many opcodes, this one does not write any output to
            the register file.
         */
         int base = vPC[1].u.operand;
         int property = vPC[2].u.operand;
-        int function = vPC[3].u.operand;
+        int getterReg = vPC[3].u.operand;
+        int setterReg = vPC[4].u.operand;
 
         ASSERT(callFrame->r(base).jsValue().isObject());
         JSObject* baseObj = asObject(callFrame->r(base).jsValue());
         Identifier& ident = codeBlock->identifier(property);
-        ASSERT(callFrame->r(function).jsValue().isObject());
-        baseObj->methodTable()->defineGetter(baseObj, callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
 
-        vPC += OPCODE_LENGTH(op_put_getter);
-        NEXT_INSTRUCTION();
-    }
-    DEFINE_OPCODE(op_put_setter) {
-        /* put_setter base(r) property(id) function(r)
+        GetterSetter* accessor = GetterSetter::create(callFrame);
 
-           Sets register function on register base as the setter named
-           by identifier property. Base and function are assumed to be
-           objects as this op should only be used for setters defined
-           in object literal form.
+        JSValue getter = callFrame->r(getterReg).jsValue();
+        JSValue setter = callFrame->r(setterReg).jsValue();
+        ASSERT(getter.isObject() || getter.isUndefined());
+        ASSERT(setter.isObject() || setter.isUndefined());
+        ASSERT(getter.isObject() || setter.isObject());
 
-           Unlike many opcodes, this one does not write any output to
-           the register file.
-        */
-        int base = vPC[1].u.operand;
-        int property = vPC[2].u.operand;
-        int function = vPC[3].u.operand;
+        if (!getter.isUndefined())
+            accessor->setGetter(callFrame->globalData(), asObject(getter));
+        if (!setter.isUndefined())
+            accessor->setSetter(callFrame->globalData(), asObject(setter));
+        baseObj->putDirectAccessor(callFrame->globalData(), ident, accessor, Accessor);
 
-        ASSERT(callFrame->r(base).jsValue().isObject());
-        JSObject* baseObj = asObject(callFrame->r(base).jsValue());
-        Identifier& ident = codeBlock->identifier(property);
-        ASSERT(callFrame->r(function).jsValue().isObject());
-        baseObj->methodTable()->defineSetter(baseObj, callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
-
-        vPC += OPCODE_LENGTH(op_put_setter);
+        vPC += OPCODE_LENGTH(op_put_getter_setter);
         NEXT_INSTRUCTION();
     }
     DEFINE_OPCODE(op_method_check) {

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -328,10 +328,9 @@
         DEFINE_OP(op_put_by_id)
         DEFINE_OP(op_put_by_index)
         DEFINE_OP(op_put_by_val)
-        DEFINE_OP(op_put_getter)
+        DEFINE_OP(op_put_getter_setter)
         DEFINE_OP(op_put_global_var)
         DEFINE_OP(op_put_scoped_var)
-        DEFINE_OP(op_put_setter)
         DEFINE_OP(op_resolve)
         DEFINE_OP(op_resolve_base)
         DEFINE_OP(op_ensure_property_exists)

Modified: trunk/Source/_javascript_Core/jit/JIT.h (106254 => 106255)


--- trunk/Source/_javascript_Core/jit/JIT.h	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2012-01-30 18:28:39 UTC (rev 106255)
@@ -857,10 +857,9 @@
         void emit_op_put_by_id(Instruction*);
         void emit_op_put_by_index(Instruction*);
         void emit_op_put_by_val(Instruction*);
-        void emit_op_put_getter(Instruction*);
+        void emit_op_put_getter_setter(Instruction*);
         void emit_op_put_global_var(Instruction*);
         void emit_op_put_scoped_var(Instruction*);
-        void emit_op_put_setter(Instruction*);
         void emit_op_resolve(Instruction*);
         void emit_op_resolve_base(Instruction*);
         void emit_op_ensure_property_exists(Instruction*);

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -261,24 +261,16 @@
     stubCall.call();
 }
 
-void JIT::emit_op_put_getter(Instruction* currentInstruction)
+void JIT::emit_op_put_getter_setter(Instruction* currentInstruction)
 {
-    JITStubCall stubCall(this, cti_op_put_getter);
+    JITStubCall stubCall(this, cti_op_put_getter_setter);
     stubCall.addArgument(currentInstruction[1].u.operand, regT2);
     stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
     stubCall.addArgument(currentInstruction[3].u.operand, regT2);
+    stubCall.addArgument(currentInstruction[4].u.operand, regT2);
     stubCall.call();
 }
 
-void JIT::emit_op_put_setter(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_put_setter);
-    stubCall.addArgument(currentInstruction[1].u.operand, regT2);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
-    stubCall.addArgument(currentInstruction[3].u.operand, regT2);
-    stubCall.call();
-}
-
 void JIT::emit_op_del_by_id(Instruction* currentInstruction)
 {
     JITStubCall stubCall(this, cti_op_del_by_id);

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -62,32 +62,21 @@
     stubCall.call();
 }
 
-void JIT::emit_op_put_getter(Instruction* currentInstruction)
+void JIT::emit_op_put_getter_setter(Instruction* currentInstruction)
 {
     unsigned base = currentInstruction[1].u.operand;
     unsigned property = currentInstruction[2].u.operand;
-    unsigned function = currentInstruction[3].u.operand;
+    unsigned getter = currentInstruction[3].u.operand;
+    unsigned setter = currentInstruction[4].u.operand;
     
-    JITStubCall stubCall(this, cti_op_put_getter);
+    JITStubCall stubCall(this, cti_op_put_getter_setter);
     stubCall.addArgument(base);
     stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
-    stubCall.addArgument(function);
+    stubCall.addArgument(getter);
+    stubCall.addArgument(setter);
     stubCall.call();
 }
 
-void JIT::emit_op_put_setter(Instruction* currentInstruction)
-{
-    unsigned base = currentInstruction[1].u.operand;
-    unsigned property = currentInstruction[2].u.operand;
-    unsigned function = currentInstruction[3].u.operand;
-    
-    JITStubCall stubCall(this, cti_op_put_setter);
-    stubCall.addArgument(base);
-    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
-    stubCall.addArgument(function);
-    stubCall.call();
-}
-
 void JIT::emit_op_del_by_id(Instruction* currentInstruction)
 {
     unsigned dst = currentInstruction[1].u.operand;

Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/jit/JITStubs.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -3526,7 +3526,7 @@
     return JSValue::encode(jsBoolean(result));
 }
 
-DEFINE_STUB_FUNCTION(void, op_put_getter)
+DEFINE_STUB_FUNCTION(void, op_put_getter_setter)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
@@ -3534,20 +3534,20 @@
 
     ASSERT(stackFrame.args[0].jsValue().isObject());
     JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
-    ASSERT(stackFrame.args[2].jsValue().isObject());
-    baseObj->methodTable()->defineGetter(baseObj, callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()), 0);
-}
 
-DEFINE_STUB_FUNCTION(void, op_put_setter)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
+    GetterSetter* accessor = GetterSetter::create(callFrame);
 
-    CallFrame* callFrame = stackFrame.callFrame;
+    JSValue getter = stackFrame.args[2].jsValue();
+    JSValue setter = stackFrame.args[3].jsValue();
+    ASSERT(getter.isObject() || getter.isUndefined());
+    ASSERT(setter.isObject() || setter.isUndefined());
+    ASSERT(getter.isObject() || setter.isObject());
 
-    ASSERT(stackFrame.args[0].jsValue().isObject());
-    JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
-    ASSERT(stackFrame.args[2].jsValue().isObject());
-    baseObj->methodTable()->defineSetter(baseObj, callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()), 0);
+    if (!getter.isUndefined())
+        accessor->setGetter(callFrame->globalData(), asObject(getter));
+    if (!setter.isUndefined())
+        accessor->setSetter(callFrame->globalData(), asObject(setter));
+    baseObj->putDirectAccessor(callFrame->globalData(), stackFrame.args[1].identifier(), accessor, Accessor);
 }
 
 DEFINE_STUB_FUNCTION(void, op_throw_reference_error)

Modified: trunk/Source/_javascript_Core/jit/JITStubs.h (106254 => 106255)


--- trunk/Source/_javascript_Core/jit/JITStubs.h	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITStubs.h	2012-01-30 18:28:39 UTC (rev 106255)
@@ -434,8 +434,7 @@
     void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_put_by_val_byte_array(STUB_ARGS_DECLARATION);
-    void JIT_STUB cti_op_put_getter(STUB_ARGS_DECLARATION);
-    void JIT_STUB cti_op_put_setter(STUB_ARGS_DECLARATION);
+    void JIT_STUB cti_op_put_getter_setter(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION);
     void JIT_STUB cti_op_throw_reference_error(STUB_ARGS_DECLARATION);

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (106254 => 106255)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2012-01-30 18:28:39 UTC (rev 106255)
@@ -224,10 +224,28 @@
 
 void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
+    ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
     PutPropertySlot slot;
     object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value));
 }
 
+void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+    ASSERT(value.isGetterSetter() && (attributes & Accessor));
+    ASSERT(propertyName != globalData.propertyNames->underscoreProto);
+
+    PutPropertySlot slot;
+    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
+
+    // putDirect will change our Structure if we add a new property. For
+    // getters and setters, though, we also need to change our Structure
+    // if we override an existing non-getter or non-setter.
+    if (slot.type() != PutPropertySlot::NewProperty)
+        setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes));
+
+    structure()->setHasGetterSetterProperties(true);
+}
+
 bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
 {
     PropertySlot slot;
@@ -692,15 +710,11 @@
     if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
         if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
             GetterSetter* accessor = GetterSetter::create(exec);
-            if (oldDescriptor.getterPresent()) {
-                attributes |= Accessor;
+            if (oldDescriptor.getterPresent())
                 accessor->setGetter(exec->globalData(), oldDescriptor.getterObject());
-            }
-            if (oldDescriptor.setterPresent()) {
-                attributes |= Accessor;
+            if (oldDescriptor.setterPresent())
                 accessor->setSetter(exec->globalData(), oldDescriptor.setterObject());
-            }
-            target->methodTable()->putDirectVirtual(target, exec, propertyName, accessor, attributes);
+            target->putDirectAccessor(exec->globalData(), propertyName, accessor, attributes | Accessor);
             return true;
         }
         JSValue newValue = jsUndefined();
@@ -708,21 +722,32 @@
             newValue = descriptor.value();
         else if (oldDescriptor.value())
             newValue = oldDescriptor.value();
-        target->methodTable()->putDirectVirtual(target, exec, propertyName, newValue, attributes & ~Accessor);
+        target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor);
         return true;
     }
     attributes &= ~ReadOnly;
+    GetterSetter* accessor = GetterSetter::create(exec);
+
     if (descriptor.getterPresent())
-        target->methodTable()->defineGetter(target, exec, propertyName, descriptor.getterObject(), attributes);
-    if (exec->hadException())
-        return false;
+        accessor->setGetter(exec->globalData(), descriptor.getterObject());
+    else if (oldDescriptor.getterPresent())
+        accessor->setGetter(exec->globalData(), oldDescriptor.getterObject());
     if (descriptor.setterPresent())
-        target->methodTable()->defineSetter(target, exec, propertyName, descriptor.setterObject(), attributes);
-    return !exec->hadException();
+        accessor->setSetter(exec->globalData(), descriptor.setterObject());
+    else if (oldDescriptor.setterPresent())
+        accessor->setSetter(exec->globalData(), oldDescriptor.setterObject());
+
+    target->putDirectAccessor(exec->globalData(), propertyName, accessor, attributes | Accessor);
+    return true;
 }
 
 bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
 {
+    // __proto__ is magic; we don't currently support setting it as a regular property.
+    // Silent filter out calls to set __proto__ at an early stage; pretend all is okay.
+    if (propertyName == exec->propertyNames().underscoreProto)
+        return true;
+
     // If we have a new property we can just put it on normally
     PropertyDescriptor current;
     if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, propertyName, current)) {
@@ -832,9 +857,7 @@
     }
     object->methodTable()->deleteProperty(object, exec, propertyName);
     unsigned attrs = current.attributesWithOverride(descriptor);
-    if (descriptor.setterPresent() || descriptor.getterPresent())
-        attrs |= Accessor;
-    object->putDirect(exec->globalData(), propertyName, getterSetter, attrs);
+    object->putDirectAccessor(exec->globalData(), propertyName, getterSetter, attrs | Accessor);
     return true;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (106254 => 106255)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2012-01-30 18:28:39 UTC (rev 106255)
@@ -118,6 +118,7 @@
         void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
         void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
         void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
+        void putDirectAccessor(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes);
 
         bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
 
@@ -642,6 +643,7 @@
 inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction)
 {
     ASSERT(value);
+    ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
 
     if (structure()->isDictionary()) {
@@ -761,17 +763,20 @@
 
 inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
+    ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
     PutPropertySlot slot;
     putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
 }
 
 inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
+    ASSERT(!value.isGetterSetter());
     putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getJSFunction(value));
 }
 
 inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
+    ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
     size_t currentCapacity = structure()->propertyStorageCapacity();
     size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
     if (currentCapacity != structure()->propertyStorageCapacity())
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to