DFG should inline prototype chain accesses, and do the right things if the
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jun 2012 01:31:21 +0000 (01:31 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jun 2012 01:31:21 +0000 (01:31 +0000)
specific function optimization is available
https://bugs.webkit.org/show_bug.cgi?id=88594

Reviewed by Gavin Barraclough.

Looks like a 3% win on V8.

* bytecode/CodeBlock.h:
(JSC::Structure::prototypeForLookup):
(JSC):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt):
(JSC):
(JSC::GetByIdStatus::computeForChain):
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdStatus.h:
(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::isSimple):
(JSC::GetByIdStatus::chain):
(JSC::GetByIdStatus::specificValue):
(GetByIdStatus):
* bytecode/StructureSet.h:
(StructureSet):
(JSC::StructureSet::singletonStructure):
* bytecode/StructureStubInfo.h:
(JSC::StructureStubInfo::initGetByIdProto):
(JSC::StructureStubInfo::initGetByIdChain):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleGetById):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCacheGetByID):
* jit/JITStubs.cpp:
(JSC::JITThunks::tryCacheGetByID):
* runtime/JSGlobalObject.h:
(JSC::Structure::prototypeForLookup):
(JSC):
* runtime/Structure.h:
(Structure):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
Source/JavaScriptCore/bytecode/GetByIdStatus.h
Source/JavaScriptCore/bytecode/StructureSet.h
Source/JavaScriptCore/bytecode/StructureStubInfo.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGRepatch.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/Structure.h

index ff4a419..e0842dd 100644 (file)
@@ -1,3 +1,45 @@
+2012-06-07  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should inline prototype chain accesses, and do the right things if the
+        specific function optimization is available
+        https://bugs.webkit.org/show_bug.cgi?id=88594
+
+        Reviewed by Gavin Barraclough.
+        
+        Looks like a 3% win on V8.
+
+        * bytecode/CodeBlock.h:
+        (JSC::Structure::prototypeForLookup):
+        (JSC):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFromLLInt):
+        (JSC):
+        (JSC::GetByIdStatus::computeForChain):
+        (JSC::GetByIdStatus::computeFor):
+        * bytecode/GetByIdStatus.h:
+        (JSC::GetByIdStatus::GetByIdStatus):
+        (JSC::GetByIdStatus::isSimple):
+        (JSC::GetByIdStatus::chain):
+        (JSC::GetByIdStatus::specificValue):
+        (GetByIdStatus):
+        * bytecode/StructureSet.h:
+        (StructureSet):
+        (JSC::StructureSet::singletonStructure):
+        * bytecode/StructureStubInfo.h:
+        (JSC::StructureStubInfo::initGetByIdProto):
+        (JSC::StructureStubInfo::initGetByIdChain):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        * dfg/DFGRepatch.cpp:
+        (JSC::DFG::tryCacheGetByID):
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::tryCacheGetByID):
+        * runtime/JSGlobalObject.h:
+        (JSC::Structure::prototypeForLookup):
+        (JSC):
+        * runtime/Structure.h:
+        (Structure):
+
 2012-06-07  Gavin Barraclough  <barraclough@apple.com>
 
         Math.pow on iOS does not support denormal numbers.
index 7e27faf..7420e23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1499,6 +1499,11 @@ namespace JSC {
     }
 #endif
     
+    inline JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const
+    {
+        return prototypeForLookup(codeBlock->globalObject());
+    }
+
 } // namespace JSC
 
 #endif // CodeBlock_h
index 11aead3..6a9b2b6 100644 (file)
@@ -44,15 +44,61 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned
 
     Structure* structure = instruction[4].u.structure.get();
     if (!structure)
-        return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+        return GetByIdStatus(NoInformation, false);
     
-    size_t offset = structure->get(*profiledBlock->globalData(), ident);
+    unsigned attributesIgnored;
+    JSCell* specificValue;
+    size_t offset = structure->get(
+        *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
     if (offset == notFound)
-        return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+        return GetByIdStatus(NoInformation, false);
     
-    return GetByIdStatus(SimpleDirect, StructureSet(structure), offset, false);
+    return GetByIdStatus(Simple, false, StructureSet(structure), offset, specificValue);
 #else
-    return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+    return GetByIdStatus(NoInformation, false);
+#endif
+}
+
+void GetByIdStatus::computeForChain(GetByIdStatus& result, CodeBlock* profiledBlock, Identifier& ident, Structure* structure)
+{
+#if ENABLE(JIT) && ENABLE(VALUE_PROFILER)
+    // Validate the chain. If the chain is invalid, then currently the best thing
+    // we can do is to assume that TakesSlow is true. In the future, it might be
+    // worth exploring reifying the structure chain from the structure we've got
+    // instead of using the one from the cache, since that will do the right things
+    // if the structure chain has changed. But that may be harder, because we may
+    // then end up having a different type of access altogether. And it currently
+    // does not appear to be worth it to do so -- effectively, the heuristic we
+    // have now is that if the structure chain has changed between when it was
+    // cached on in the baseline JIT and when the DFG tried to inline the access,
+    // then we fall back on a polymorphic access.
+    Structure* currentStructure = structure;
+    JSObject* currentObject = 0;
+    for (unsigned i = 0; i < result.m_chain.size(); ++i) {
+        currentObject = asObject(currentStructure->prototypeForLookup(profiledBlock));
+        currentStructure = result.m_chain[i];
+        if (currentObject->structure() != currentStructure)
+            return;
+    }
+        
+    ASSERT(currentObject);
+        
+    unsigned attributesIgnored;
+    JSCell* specificValue;
+        
+    result.m_offset = currentStructure->get(
+        *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
+    if (result.m_offset == notFound)
+        return;
+        
+    result.m_structureSet.add(structure);
+    result.m_specificValue = JSValue(specificValue);
+#else
+    UNUSED_PARAM(result);
+    UNUSED_PARAM(profiledBlock);
+    UNUSED_PARAM(ident);
+    UNUSED_PARAM(structure);
+    ASSERT_NOT_REACHED();
 #endif
 }
 
@@ -89,12 +135,12 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
     }
     for (int i = 0; i < listSize; ++i) {
         if (!list->list[i].isDirect)
-            return GetByIdStatus(MakesCalls, StructureSet(), notFound, true);
+            return GetByIdStatus(MakesCalls, true);
     }
     
     // Next check if it takes slow case, in which case we want to be kind of careful.
     if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex))
-        return GetByIdStatus(TakesSlowPath, StructureSet(), notFound, true);
+        return GetByIdStatus(TakesSlowPath, true);
     
     // Finally figure out if we can derive an access strategy.
     GetByIdStatus result;
@@ -105,10 +151,15 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
         
     case access_get_by_id_self: {
         Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
-        result.m_offset = structure->get(*profiledBlock->globalData(), ident);
+        unsigned attributesIgnored;
+        JSCell* specificValue;
+        result.m_offset = structure->get(
+            *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
         
-        if (result.m_offset != notFound)
+        if (result.m_offset != notFound) {
             result.m_structureSet.add(structure);
+            result.m_specificValue = JSValue(specificValue);
+        }
         
         if (result.m_offset != notFound)
             ASSERT(result.m_structureSet.size());
@@ -116,29 +167,32 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
     }
         
     case access_get_by_id_self_list: {
-        PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList;
-        unsigned size = stubInfo.u.getByIdProtoList.listSize;
-        for (unsigned i = 0; i < size; ++i) {
+        for (int i = 0; i < listSize; ++i) {
             ASSERT(list->list[i].isDirect);
             
             Structure* structure = list->list[i].base.get();
             if (result.m_structureSet.contains(structure))
                 continue;
             
-            size_t myOffset = structure->get(*profiledBlock->globalData(), ident);
+            unsigned attributesIgnored;
+            JSCell* specificValue;
+            size_t myOffset = structure->get(
+                *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
             
             if (myOffset == notFound) {
                 result.m_offset = notFound;
                 break;
             }
                     
-            if (!i)
+            if (!i) {
                 result.m_offset = myOffset;
-            else if (result.m_offset != myOffset) {
+                result.m_specificValue = JSValue(specificValue);
+            } else if (result.m_offset != myOffset) {
                 result.m_offset = notFound;
                 break;
-            }
-                    
+            } else if (result.m_specificValue != JSValue(specificValue))
+                result.m_specificValue = JSValue();
+            
             result.m_structureSet.add(structure);
         }
                     
@@ -147,6 +201,27 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
         break;
     }
         
+    case access_get_by_id_proto: {
+        if (!stubInfo.u.getByIdProto.isDirect)
+            return GetByIdStatus(MakesCalls, true);
+        result.m_chain.append(stubInfo.u.getByIdProto.prototypeStructure.get());
+        computeForChain(
+            result, profiledBlock, ident,
+            stubInfo.u.getByIdProto.baseObjectStructure.get());
+        break;
+    }
+        
+    case access_get_by_id_chain: {
+        if (!stubInfo.u.getByIdChain.isDirect)
+            return GetByIdStatus(MakesCalls, true);
+        for (unsigned i = 0; i < stubInfo.u.getByIdChain.count; ++i)
+            result.m_chain.append(stubInfo.u.getByIdChain.chain->head()[i].get());
+        computeForChain(
+            result, profiledBlock, ident,
+            stubInfo.u.getByIdChain.baseObjectStructure.get());
+        break;
+    }
+        
     default:
         ASSERT(result.m_offset == notFound);
         break;
@@ -155,12 +230,14 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
     if (result.m_offset == notFound) {
         result.m_state = TakesSlowPath;
         result.m_structureSet.clear();
+        result.m_chain.clear();
+        result.m_specificValue = JSValue();
     } else
-        result.m_state = SimpleDirect;
+        result.m_state = Simple;
     
     return result;
 #else // ENABLE(JIT)
-    return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+    return GetByIdStatus(NoInformation, false);
 #endif // ENABLE(JIT)
 }
 
index 39476c0..42eadfd 100644 (file)
@@ -38,7 +38,8 @@ class GetByIdStatus {
 public:
     enum State {
         NoInformation,  // It's uncached so we have no information.
-        SimpleDirect,   // It's cached for a direct access to a known object property.
+        Simple,         // It's cached for a simple access to a known object property with
+                        // a possible structure chain and a possible specific value.
         TakesSlowPath,  // It's known to often take slow path.
         MakesCalls      // It's known to take paths that make calls.
     };
@@ -49,13 +50,17 @@ public:
     {
     }
     
-    GetByIdStatus(State state, const StructureSet& structureSet, size_t offset, bool wasSeenInJIT)
+    GetByIdStatus(
+        State state, bool wasSeenInJIT, const StructureSet& structureSet = StructureSet(),
+        size_t offset = notFound, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>())
         : m_state(state)
         , m_structureSet(structureSet)
+        , m_chain(chain)
+        , m_specificValue(specificValue)
         , m_offset(offset)
         , m_wasSeenInJIT(wasSeenInJIT)
     {
-        ASSERT((state == SimpleDirect) == (offset != notFound));
+        ASSERT((state == Simple) == (offset != notFound));
     }
     
     static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
@@ -64,20 +69,25 @@ public:
     
     bool isSet() const { return m_state != NoInformation; }
     bool operator!() const { return !isSet(); }
-    bool isSimpleDirect() const { return m_state == SimpleDirect; }
+    bool isSimple() const { return m_state == Simple; }
     bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
     bool makesCalls() const { return m_state == MakesCalls; }
     
     const StructureSet& structureSet() const { return m_structureSet; }
+    const Vector<Structure*>& chain() const { return m_chain; } // Returns empty vector if this is a direct access.
+    JSValue specificValue() const { return m_specificValue; } // Returns JSValue() if there is no specific value.
     size_t offset() const { return m_offset; }
     
     bool wasSeenInJIT() const { return m_wasSeenInJIT; }
     
 private:
+    static void computeForChain(GetByIdStatus& result, CodeBlock*, Identifier&, Structure*);
     static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, Identifier&);
     
     State m_state;
     StructureSet m_structureSet;
+    Vector<Structure*> m_chain;
+    JSValue m_specificValue;
     size_t m_offset;
     bool m_wasSeenInJIT;
 };
index 14fcf04..e2299ac 100644 (file)
@@ -115,6 +115,14 @@ public:
         return true;
     }
     
+    // Call this if you know that the structure set must consist of exactly
+    // one structure.
+    Structure* singletonStructure() const
+    {
+        ASSERT(m_structures.size() == 1);
+        return m_structures[0];
+    }
+    
     Structure* at(size_t i) const { return m_structures.at(i); }
     
     Structure* operator[](size_t i) const { return at(i); }
index 9aa4053..573f6e9 100644 (file)
@@ -102,20 +102,23 @@ namespace JSC {
             u.getByIdSelf.baseObjectStructure.set(globalData, owner, baseObjectStructure);
         }
 
-        void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure)
+        void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure, bool isDirect)
         {
             accessType = access_get_by_id_proto;
 
             u.getByIdProto.baseObjectStructure.set(globalData, owner, baseObjectStructure);
             u.getByIdProto.prototypeStructure.set(globalData, owner, prototypeStructure);
+            u.getByIdProto.isDirect = isDirect;
         }
 
-        void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain)
+        void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect)
         {
             accessType = access_get_by_id_chain;
 
             u.getByIdChain.baseObjectStructure.set(globalData, owner, baseObjectStructure);
             u.getByIdChain.chain.set(globalData, owner, chain);
+            u.getByIdChain.count = count;
+            u.getByIdChain.isDirect = isDirect;
         }
 
         void initGetByIdSelfList(PolymorphicAccessStructureList* structureList, int listSize)
@@ -251,10 +254,13 @@ namespace JSC {
             struct {
                 WriteBarrierBase<Structure> baseObjectStructure;
                 WriteBarrierBase<Structure> prototypeStructure;
+                bool isDirect;
             } getByIdProto;
             struct {
                 WriteBarrierBase<Structure> baseObjectStructure;
                 WriteBarrierBase<StructureChain> chain;
+                unsigned count : 31;
+                bool isDirect : 1;
             } getByIdChain;
             struct {
                 PolymorphicAccessStructureList* structureList;
index eea55e0..6defb37 100644 (file)
@@ -1547,41 +1547,64 @@ void ByteCodeParser::handleGetById(
     int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
     const GetByIdStatus& getByIdStatus)
 {
-    if (getByIdStatus.isSimpleDirect()
-        && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
-        ASSERT(getByIdStatus.structureSet().size());
-                
-        // The implementation of GetByOffset does not know to terminate speculative
-        // execution if it doesn't have a prediction, so we do it manually.
-        if (prediction == SpecNone)
-            addToGraph(ForceOSRExit);
-                
-        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base);
-        NodeIndex propertyStorage;
-        size_t offsetOffset;
-        if (getByIdStatus.structureSet().allAreUsingInlinePropertyStorage()) {
-            propertyStorage = base;
-            ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
-            offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
-        } else {
-            propertyStorage = addToGraph(GetPropertyStorage, base);
-            offsetOffset = 0;
-        }
-        set(destinationOperand,
-            addToGraph(
-                GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
-                propertyStorage));
-        
-        StorageAccessData storageAccessData;
-        storageAccessData.offset = getByIdStatus.offset() + offsetOffset;
-        storageAccessData.identifierNumber = identifierNumber;
-        m_graph.m_storageAccessData.append(storageAccessData);
-    } else {
+    if (!getByIdStatus.isSimple()
+        || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
         set(destinationOperand,
             addToGraph(
                 getByIdStatus.makesCalls() ? GetByIdFlush : GetById,
                 OpInfo(identifierNumber), OpInfo(prediction), base));
+        return;
     }
+    
+    ASSERT(getByIdStatus.structureSet().size());
+                
+    // The implementation of GetByOffset does not know to terminate speculative
+    // execution if it doesn't have a prediction, so we do it manually.
+    if (prediction == SpecNone)
+        addToGraph(ForceOSRExit);
+                
+    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base);
+    
+    bool useInlineStorage;
+    if (!getByIdStatus.chain().isEmpty()) {
+        Structure* currentStructure = getByIdStatus.structureSet().singletonStructure();
+        JSObject* currentObject = 0;
+        for (unsigned i = 0; i < getByIdStatus.chain().size(); ++i) {
+            currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock));
+            currentStructure = getByIdStatus.chain()[i];
+            base = addToGraph(WeakJSConstant, OpInfo(currentObject));
+            addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(currentStructure)), base);
+        }
+        useInlineStorage = currentStructure->isUsingInlineStorage();
+    } else
+        useInlineStorage = getByIdStatus.structureSet().allAreUsingInlinePropertyStorage();
+    
+    if (getByIdStatus.specificValue()) {
+        ASSERT(getByIdStatus.specificValue().isCell());
+        set(destinationOperand,
+            addToGraph(WeakJSConstant, OpInfo(getByIdStatus.specificValue().asCell())));
+        return;
+    }
+    
+    NodeIndex propertyStorage;
+    size_t offsetOffset;
+    if (useInlineStorage) {
+        propertyStorage = base;
+        ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
+        offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
+    } else {
+        propertyStorage = addToGraph(GetPropertyStorage, base);
+        offsetOffset = 0;
+    }
+    set(destinationOperand,
+        addToGraph(
+            GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
+            propertyStorage));
+        
+    StorageAccessData storageAccessData;
+    storageAccessData.offset = getByIdStatus.offset() + offsetOffset;
+    storageAccessData.identifierNumber = identifierNumber;
+    m_graph.m_storageAccessData.append(storageAccessData);
 }
 
 void ByteCodeParser::prepareToParseBlock()
index 7945381..43ff3e9 100644 (file)
@@ -261,7 +261,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
     repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
     repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList);
     
-    stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain);
+    stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true);
     return true;
 }
 
index 4aad7c9..dd9d22d 100644 (file)
@@ -945,7 +945,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
             offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName);
         }
         
-        stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure());
+        stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure(), slot.cachedPropertyType() == PropertySlot::Value);
 
         ASSERT(!structure->isDictionary());
         ASSERT(!slotBaseObject->structure()->isDictionary());
@@ -961,7 +961,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
     }
 
     StructureChain* prototypeChain = structure->prototypeChain(callFrame);
-    stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain);
+    stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain, count, slot.cachedPropertyType() == PropertySlot::Value);
     JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress);
 }
 
index 702ebfd..2396142 100644 (file)
@@ -381,13 +381,18 @@ namespace JSC {
         return !entry.isNull();
     }
 
-    inline JSValue Structure::prototypeForLookup(ExecState* exec) const
+    inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
     {
         if (isObject())
             return m_prototype.get();
 
         ASSERT(typeInfo().type() == StringType);
-        return exec->lexicalGlobalObject()->stringPrototype();
+        return globalObject->stringPrototype();
+    }
+
+    inline JSValue Structure::prototypeForLookup(ExecState* exec) const
+    {
+        return prototypeForLookup(exec->lexicalGlobalObject());
     }
 
     inline StructureChain* Structure::prototypeChain(ExecState* exec) const
index d9f4d1f..c1d4c96 100644 (file)
@@ -127,6 +127,8 @@ namespace JSC {
         
         JSValue storedPrototype() const { return m_prototype.get(); }
         JSValue prototypeForLookup(ExecState*) const;
+        JSValue prototypeForLookup(JSGlobalObject*) const;
+        JSValue prototypeForLookup(CodeBlock*) const;
         StructureChain* prototypeChain(ExecState*) const;
         static void visitChildren(JSCell*, SlotVisitor&);