[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.21-584-g1e41756

oliver at apple.com oliver at apple.com
Fri Feb 26 22:25:28 UTC 2010


The following commit has been merged in the webkit-1.1 branch:
commit 15b79cbfd43a7bbde5fd8da19cbbede92f75528f
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Feb 19 06:23:25 2010 +0000

    2010-02-18  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Gavin Barraclough.
    
            Improve interpreter getter performance
            https://bugs.webkit.org/show_bug.cgi?id=35138
    
            Improve the performance of getter dispatch by making it possible
            for the interpreter to cache the GetterSetter object lookup.
    
            To do this we simply need to make PropertySlot aware of getters
            as a potentially cacheable property, and record the base and this
            objects for a getter access.  This allows us to use more-or-less
            identical code to that used by the normal get_by_id caching, with
            the dispatch being the only actual difference.
    
            I'm holding off of implementing this in the JIT until I do some
            cleanup to try and making coding in the JIT not be as horrible
            as it is currently.
    
            * bytecode/CodeBlock.cpp:
            (JSC::CodeBlock::dump):
            (JSC::CodeBlock::derefStructures):
            (JSC::CodeBlock::refStructures):
            * bytecode/Opcode.h:
            * interpreter/Interpreter.cpp:
            (JSC::Interpreter::resolveGlobal):
            (JSC::Interpreter::tryCacheGetByID):
            (JSC::Interpreter::privateExecute):
            * jit/JIT.cpp:
            (JSC::JIT::privateCompileMainPass):
            * jit/JITStubs.cpp:
            (JSC::JITThunks::tryCacheGetByID):
            (JSC::DEFINE_STUB_FUNCTION):
            * runtime/JSObject.cpp:
            (JSC::JSObject::fillGetterPropertySlot):
            * runtime/PropertySlot.cpp:
            (JSC::PropertySlot::functionGetter):
            * runtime/PropertySlot.h:
            (JSC::PropertySlot::isGetter):
            (JSC::PropertySlot::isCacheable):
            (JSC::PropertySlot::isCacheableValue):
            (JSC::PropertySlot::setValueSlot):
            (JSC::PropertySlot::setGetterSlot):
            (JSC::PropertySlot::setCacheableGetterSlot):
            (JSC::PropertySlot::clearOffset):
            (JSC::PropertySlot::thisValue):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@55002 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 101b79e..fdba64c 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,51 @@
+2010-02-18  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Improve interpreter getter performance
+        https://bugs.webkit.org/show_bug.cgi?id=35138
+
+        Improve the performance of getter dispatch by making it possible
+        for the interpreter to cache the GetterSetter object lookup.
+
+        To do this we simply need to make PropertySlot aware of getters
+        as a potentially cacheable property, and record the base and this
+        objects for a getter access.  This allows us to use more-or-less
+        identical code to that used by the normal get_by_id caching, with
+        the dispatch being the only actual difference.
+
+        I'm holding off of implementing this in the JIT until I do some
+        cleanup to try and making coding in the JIT not be as horrible
+        as it is currently.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        (JSC::CodeBlock::derefStructures):
+        (JSC::CodeBlock::refStructures):
+        * bytecode/Opcode.h:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::resolveGlobal):
+        (JSC::Interpreter::tryCacheGetByID):
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::tryCacheGetByID):
+        (JSC::DEFINE_STUB_FUNCTION):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::fillGetterPropertySlot):
+        * runtime/PropertySlot.cpp:
+        (JSC::PropertySlot::functionGetter):
+        * runtime/PropertySlot.h:
+        (JSC::PropertySlot::isGetter):
+        (JSC::PropertySlot::isCacheable):
+        (JSC::PropertySlot::isCacheableValue):
+        (JSC::PropertySlot::setValueSlot):
+        (JSC::PropertySlot::setGetterSlot):
+        (JSC::PropertySlot::setCacheableGetterSlot):
+        (JSC::PropertySlot::clearOffset):
+        (JSC::PropertySlot::thisValue):
+
 2010-02-17  Geoffrey Garen  <ggaren at apple.com>
 
         Reviewed by Oliver Hunt.
diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp
index 0ec1888..68debb2 100644
--- a/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -765,6 +765,26 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printGetByIdOp(exec, location, it, "get_by_id_chain");
             break;
         }
+        case op_get_by_id_getter_self: {
+            printGetByIdOp(exec, location, it, "get_by_id_getter_self");
+            break;
+        }
+        case op_get_by_id_getter_self_list: {
+            printGetByIdOp(exec, location, it, "get_by_id_getter_self_list");
+            break;
+        }
+        case op_get_by_id_getter_proto: {
+            printGetByIdOp(exec, location, it, "get_by_id_getter_proto");
+            break;
+        }
+        case op_get_by_id_getter_proto_list: {
+            printGetByIdOp(exec, location, it, "get_by_id_getter_proto_list");
+            break;
+        }
+        case op_get_by_id_getter_chain: {
+            printGetByIdOp(exec, location, it, "get_by_id_getter_chain");
+            break;
+        }
         case op_get_by_id_generic: {
             printGetByIdOp(exec, location, it, "get_by_id_generic");
             break;
@@ -1355,16 +1375,16 @@ void CodeBlock::derefStructures(Instruction* vPC) const
 {
     Interpreter* interpreter = m_globalData->interpreter;
 
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self)) {
         vPC[4].u.structure->deref();
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto)) {
         vPC[4].u.structure->deref();
         vPC[5].u.structure->deref();
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain)) {
         vPC[4].u.structure->deref();
         vPC[5].u.structureChain->deref();
         return;
@@ -1385,7 +1405,9 @@ void CodeBlock::derefStructures(Instruction* vPC) const
         return;
     }
     if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
-        || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))) {
+        || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))
+        || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto_list))
+        || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self_list))) {
         PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
         polymorphicStructures->derefStructures(vPC[5].u.operand);
         delete polymorphicStructures;
@@ -1400,16 +1422,16 @@ void CodeBlock::refStructures(Instruction* vPC) const
 {
     Interpreter* interpreter = m_globalData->interpreter;
 
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self)) {
         vPC[4].u.structure->ref();
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto)) {
         vPC[4].u.structure->ref();
         vPC[5].u.structure->ref();
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
+    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain)) {
         vPC[4].u.structure->ref();
         vPC[5].u.structureChain->ref();
         return;
diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h
index d9b2153..56555f3 100644
--- a/JavaScriptCore/bytecode/Opcode.h
+++ b/JavaScriptCore/bytecode/Opcode.h
@@ -104,6 +104,11 @@ namespace JSC {
         macro(op_get_by_id_proto, 8) \
         macro(op_get_by_id_proto_list, 8) \
         macro(op_get_by_id_chain, 8) \
+        macro(op_get_by_id_getter_self, 8) \
+        macro(op_get_by_id_getter_self_list, 8) \
+        macro(op_get_by_id_getter_proto, 8) \
+        macro(op_get_by_id_getter_proto_list, 8) \
+        macro(op_get_by_id_getter_chain, 8) \
         macro(op_get_by_id_generic, 8) \
         macro(op_get_array_length, 8) \
         macro(op_get_string_length, 8) \
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index dfe1a5c..6dbbcf9 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -40,6 +40,7 @@
 #include "DebuggerCallFrame.h"
 #include "EvalCodeCache.h"
 #include "ExceptionHelpers.h"
+#include "GetterSetter.h"
 #include "GlobalEvalFunction.h"
 #include "JSActivation.h"
 #include "JSArray.h"
@@ -169,7 +170,7 @@ NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction*
     PropertySlot slot(globalObject);
     if (globalObject->getPropertySlot(callFrame, ident, slot)) {
         JSValue result = slot.getValue(callFrame, ident);
-        if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
+        if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
             if (vPC[4].u.structure)
                 vPC[4].u.structure->deref();
             globalObject->structure()->ref();
@@ -1029,7 +1030,7 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
     // Cache hit: Specialize instruction and ref Structures.
 
     if (slot.slotBase() == baseValue) {
-        vPC[0] = getOpcode(op_get_by_id_self);
+        vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_self) : getOpcode(op_get_by_id_self);
         vPC[5] = slot.cachedOffset();
 
         codeBlock->refStructures(vPC);
@@ -1056,7 +1057,7 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
 
         ASSERT(!baseObject->structure()->isUncacheableDictionary());
 
-        vPC[0] = getOpcode(op_get_by_id_proto);
+        vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_proto) : getOpcode(op_get_by_id_proto);
         vPC[5] = baseObject->structure();
         vPC[6] = offset;
 
@@ -1071,7 +1072,7 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
         return;
     }
 
-    vPC[0] = getOpcode(op_get_by_id_chain);
+    vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_chain) : getOpcode(op_get_by_id_chain);
     vPC[4] = structure;
     vPC[5] = structure->prototypeChain(callFrame);
     vPC[6] = count;
@@ -2161,6 +2162,51 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         uncacheGetByID(callFrame->codeBlock(), vPC);
         NEXT_INSTRUCTION();
     }
+#if HAVE(COMPUTED_GOTO)
+    goto *(&&skip_id_getter_proto);
+#endif
+    DEFINE_OPCODE(op_get_by_id_getter_proto) {
+        /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
+         
+         Cached property access: Attempts to get a cached getter property from the
+         value base's prototype. If the cache misses, op_get_by_id_getter_proto
+         reverts to op_get_by_id.
+         */
+        int base = vPC[2].u.operand;
+        JSValue baseValue = callFrame->r(base).jsValue();
+        
+        if (LIKELY(baseValue.isCell())) {
+            JSCell* baseCell = asCell(baseValue);
+            Structure* structure = vPC[4].u.structure;
+            
+            if (LIKELY(baseCell->structure() == structure)) {
+                ASSERT(structure->prototypeForLookup(callFrame).isObject());
+                JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
+                Structure* prototypeStructure = vPC[5].u.structure;
+                
+                if (LIKELY(protoObject->structure() == prototypeStructure)) {
+                    int dst = vPC[1].u.operand;
+                    int offset = vPC[6].u.operand;
+                    if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
+                        JSObject* getter = getterSetter->getter();
+                        CallData callData;
+                        CallType callType = getter->getCallData(callData);
+                        JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
+                        CHECK_FOR_EXCEPTION();
+                        callFrame->r(dst) = result;
+                    } else
+                        callFrame->r(dst) = jsUndefined();
+                    vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
+                    NEXT_INSTRUCTION();
+                }
+            }
+        }
+        uncacheGetByID(callFrame->codeBlock(), vPC);
+        NEXT_INSTRUCTION();
+    }
+#if HAVE(COMPUTED_GOTO)
+    skip_id_getter_proto:
+#endif
     DEFINE_OPCODE(op_get_by_id_self_list) {
         // Polymorphic self access caching currently only supported when JITting.
         ASSERT_NOT_REACHED();
@@ -2175,6 +2221,20 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
         NEXT_INSTRUCTION();
     }
+    DEFINE_OPCODE(op_get_by_id_getter_self_list) {
+        // Polymorphic self access caching currently only supported when JITting.
+        ASSERT_NOT_REACHED();
+        // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
+        vPC += OPCODE_LENGTH(op_get_by_id_self_list);
+        NEXT_INSTRUCTION();
+    }
+    DEFINE_OPCODE(op_get_by_id_getter_proto_list) {
+        // Polymorphic prototype access caching currently only supported when JITting.
+        ASSERT_NOT_REACHED();
+        // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
+        vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
+        NEXT_INSTRUCTION();
+    }
     DEFINE_OPCODE(op_get_by_id_chain) {
         /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
 
@@ -2221,6 +2281,49 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         uncacheGetByID(callFrame->codeBlock(), vPC);
         NEXT_INSTRUCTION();
     }
+#if HAVE(COMPUTED_GOTO)
+    goto *(&&skip_id_getter_self);
+#endif
+    DEFINE_OPCODE(op_get_by_id_getter_self) {
+        /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
+         
+         Cached property access: Attempts to get a cached property from the
+         value base. If the cache misses, op_get_by_id_getter_self reverts to
+         op_get_by_id.
+         */
+        int base = vPC[2].u.operand;
+        JSValue baseValue = callFrame->r(base).jsValue();
+        
+        if (LIKELY(baseValue.isCell())) {
+            JSCell* baseCell = asCell(baseValue);
+            Structure* structure = vPC[4].u.structure;
+            
+            if (LIKELY(baseCell->structure() == structure)) {
+                ASSERT(baseCell->isObject());
+                JSObject* baseObject = asObject(baseCell);
+                int dst = vPC[1].u.operand;
+                int offset = vPC[5].u.operand;
+
+                if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
+                    JSObject* getter = getterSetter->getter();
+                    CallData callData;
+                    CallType callType = getter->getCallData(callData);
+                    JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
+                    CHECK_FOR_EXCEPTION();
+                    callFrame->r(dst) = result;
+                } else
+                    callFrame->r(dst) = jsUndefined();
+
+                vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
+                NEXT_INSTRUCTION();
+            }
+        }
+        uncacheGetByID(callFrame->codeBlock(), vPC);
+        NEXT_INSTRUCTION();
+    }
+#if HAVE(COMPUTED_GOTO)
+    skip_id_getter_self:
+#endif
     DEFINE_OPCODE(op_get_by_id_generic) {
         /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
 
@@ -2241,6 +2344,61 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         vPC += OPCODE_LENGTH(op_get_by_id_generic);
         NEXT_INSTRUCTION();
     }
+#if HAVE(COMPUTED_GOTO)
+    goto *(&&skip_id_getter_chain);
+#endif
+    DEFINE_OPCODE(op_get_by_id_getter_chain) {
+        /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
+         
+         Cached property access: Attempts to get a cached property from the
+         value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
+         reverts to op_get_by_id.
+         */
+        int base = vPC[2].u.operand;
+        JSValue baseValue = callFrame->r(base).jsValue();
+        
+        if (LIKELY(baseValue.isCell())) {
+            JSCell* baseCell = asCell(baseValue);
+            Structure* structure = vPC[4].u.structure;
+            
+            if (LIKELY(baseCell->structure() == structure)) {
+                RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+                size_t count = vPC[6].u.operand;
+                RefPtr<Structure>* end = it + count;
+                
+                while (true) {
+                    JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
+                    
+                    if (UNLIKELY(baseObject->structure() != (*it).get()))
+                        break;
+                    
+                    if (++it == end) {
+                        int dst = vPC[1].u.operand;
+                        int offset = vPC[7].u.operand;
+                        if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
+                            JSObject* getter = getterSetter->getter();
+                            CallData callData;
+                            CallType callType = getter->getCallData(callData);
+                            JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
+                            CHECK_FOR_EXCEPTION();
+                            callFrame->r(dst) = result;
+                        } else
+                            callFrame->r(dst) = jsUndefined();
+                        vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
+                        NEXT_INSTRUCTION();
+                    }
+                    
+                    // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
+                    baseCell = baseObject;
+                }
+            }
+        }
+        uncacheGetByID(callFrame->codeBlock(), vPC);
+        NEXT_INSTRUCTION();
+    }
+#if HAVE(COMPUTED_GOTO)
+    skip_id_getter_chain:
+#endif
     DEFINE_OPCODE(op_get_array_length) {
         /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
 
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index a846fb9..78c5153 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -322,6 +322,11 @@ void JIT::privateCompileMainPass()
         case op_get_by_id_proto_list:
         case op_get_by_id_self:
         case op_get_by_id_self_list:
+        case op_get_by_id_getter_chain:
+        case op_get_by_id_getter_proto:
+        case op_get_by_id_getter_proto_list:
+        case op_get_by_id_getter_self:
+        case op_get_by_id_getter_self_list:
         case op_get_string_length:
         case op_put_by_id_generic:
         case op_put_by_id_replace:
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index 9636995..bf430a6 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -856,10 +856,11 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
     }
 
     // Uncacheable: give up.
-    if (!slot.isCacheable()) {
+    if (!slot.isCacheableValue()) {
         ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
         return;
     }
+    ASSERT(!slot.isGetter());
 
     JSCell* baseCell = asCell(baseValue);
     Structure* structure = baseCell->structure();
@@ -1289,7 +1290,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check)
     // If we successfully got something, then the base from which it is being accessed must
     // be an object.  (Assertion to ensure asObject() call below is safe, which comes after
     // an isCacheable() chceck.
-    ASSERT(!slot.isCacheable() || slot.slotBase().isObject());
+    ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject());
 
     // Check that:
     //   * We're dealing with a JSCell,
@@ -1300,7 +1301,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check)
     JSCell* specific;
     JSObject* slotBaseObject;
     if (baseValue.isCell()
-        && slot.isCacheable()
+        && slot.isCacheableValue()
         && !(structure = asCell(baseValue)->structure())->isUncacheableDictionary()
         && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific)
         && specific
@@ -1374,7 +1375,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
     CHECK_FOR_EXCEPTION();
 
     if (baseValue.isCell()
-        && slot.isCacheable()
+        && slot.isCacheableValue()
         && !asCell(baseValue)->structure()->isUncacheableDictionary()
         && slot.slotBase() == baseValue) {
 
@@ -1447,7 +1448,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
 
     CHECK_FOR_EXCEPTION();
 
-    if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) {
+    if (!baseValue.isCell() || !slot.isCacheableValue() || asCell(baseValue)->structure()->isDictionary()) {
         ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
         return JSValue::encode(result);
     }
@@ -2303,7 +2304,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
     PropertySlot slot(globalObject);
     if (globalObject->getPropertySlot(callFrame, ident, slot)) {
         JSValue result = slot.getValue(callFrame, ident);
-        if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
+        if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
             GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex);
             if (globalResolveInfo.structure)
                 globalResolveInfo.structure->deref();
diff --git a/JavaScriptCore/runtime/JSObject.cpp b/JavaScriptCore/runtime/JSObject.cpp
index d9500aa..61d3bb1 100644
--- a/JavaScriptCore/runtime/JSObject.cpp
+++ b/JavaScriptCore/runtime/JSObject.cpp
@@ -516,9 +516,12 @@ void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunct
 
 NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location)
 {
-    if (JSObject* getterFunction = asGetterSetter(*location)->getter())
-        slot.setGetterSlot(getterFunction);
-    else
+    if (JSObject* getterFunction = asGetterSetter(*location)->getter()) {
+        if (!structure()->isDictionary())
+            slot.setCacheableGetterSlot(this, getterFunction, offsetForLocation(location));
+        else
+            slot.setGetterSlot(getterFunction);
+    } else
         slot.setUndefined();
 }
 
diff --git a/JavaScriptCore/runtime/PropertySlot.cpp b/JavaScriptCore/runtime/PropertySlot.cpp
index a0a2f48..8b6ceb9 100644
--- a/JavaScriptCore/runtime/PropertySlot.cpp
+++ b/JavaScriptCore/runtime/PropertySlot.cpp
@@ -35,10 +35,10 @@ JSValue PropertySlot::functionGetter(ExecState* exec, const Identifier&, const P
     CallData callData;
     CallType callType = slot.m_data.getterFunc->getCallData(callData);
     if (callType == CallTypeHost)
-        return callData.native.function(exec, slot.m_data.getterFunc, slot.slotBase(), exec->emptyList());
+        return callData.native.function(exec, slot.m_data.getterFunc, slot.thisValue(), exec->emptyList());
     ASSERT(callType == CallTypeJS);
     // FIXME: Can this be done more efficiently using the callData?
-    return asFunction(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList());
+    return asFunction(slot.m_data.getterFunc)->call(exec, slot.thisValue(), exec->emptyList());
 }
 
 } // namespace JSC
diff --git a/JavaScriptCore/runtime/PropertySlot.h b/JavaScriptCore/runtime/PropertySlot.h
index 15d9034..a364e42 100644
--- a/JavaScriptCore/runtime/PropertySlot.h
+++ b/JavaScriptCore/runtime/PropertySlot.h
@@ -71,7 +71,9 @@ namespace JSC {
             return m_getValue(exec, Identifier::from(exec, propertyName), *this);
         }
 
-        bool isCacheable() const { return m_offset != WTF::notFound; }
+        bool isGetter() const { return m_isGetter; }
+        bool isCacheable() const { return m_isCacheable; }
+        bool isCacheableValue() const { return m_isCacheable && !m_isGetter; }
         size_t cachedOffset() const
         {
             ASSERT(isCacheable());
@@ -102,6 +104,8 @@ namespace JSC {
             m_slotBase = slotBase;
             m_data.valueSlot = valueSlot;
             m_offset = offset;
+            m_isCacheable = true;
+            m_isGetter = false;
         }
         
         void setValue(JSValue value)
@@ -139,14 +143,28 @@ namespace JSC {
             m_slotBase = slotBase;
             m_data.index = index;
         }
-        
+
         void setGetterSlot(JSObject* getterFunc)
         {
             ASSERT(getterFunc);
+            m_thisValue = m_slotBase;
             m_getValue = functionGetter;
             m_data.getterFunc = getterFunc;
+            m_isGetter = true;
         }
-        
+
+        void setCacheableGetterSlot(JSValue slotBase, JSObject* getterFunc, unsigned offset)
+        {
+            ASSERT(getterFunc);
+            m_getValue = functionGetter;
+            m_thisValue = m_slotBase;
+            m_slotBase = slotBase;
+            m_data.getterFunc = getterFunc;
+            m_offset = offset;
+            m_isCacheable = true;
+            m_isGetter = true;
+        }
+
         void setUndefined()
         {
             setValue(jsUndefined());
@@ -182,11 +200,14 @@ namespace JSC {
         {
             // Clear offset even in release builds, in case this PropertySlot has been used before.
             // (For other data members, we don't need to clear anything because reuse would meaningfully overwrite them.)
-            m_offset = WTF::notFound;
+            m_offset = 0;
+            m_isCacheable = false;
+            m_isGetter = false;
         }
 
         unsigned index() const { return m_data.index; }
 
+        JSValue thisValue() const { return m_thisValue; }
     private:
         static JSValue functionGetter(ExecState*, const Identifier&, const PropertySlot&);
 
@@ -201,8 +222,11 @@ namespace JSC {
         } m_data;
 
         JSValue m_value;
+        JSValue m_thisValue;
 
         size_t m_offset;
+        bool m_isCacheable : 1;
+        bool m_isGetter : 1;
     };
 
 } // namespace JSC

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list