2008-11-21 Gavin Barraclough <barraclough@apple.com>
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 22 Nov 2008 03:34:43 +0000 (03:34 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 22 Nov 2008 03:34:43 +0000 (03:34 +0000)
        Reviewed by Oliver Hunt.

        Add (really) polymorphic caching for get by id self.
        Very similar to caching of prototype accesses, described below.

        Oh, also, probably shouldn't have been leaking those structure list objects.

        4% preogression on deltablue.

        * bytecode/CodeBlock.cpp:
        (JSC::CodeBlock::dump):
        (JSC::CodeBlock::derefStructures):
        (JSC::PrototypeStructureList::derefStructures):
        * bytecode/Instruction.h:
        * bytecode/Opcode.h:
        * interpreter/Interpreter.cpp:
        (JSC::Interpreter::privateExecute):
        (JSC::Interpreter::cti_op_get_by_id_self_fail):
        * jit/JIT.cpp:
        (JSC::JIT::privateCompileMainPass):
        (JSC::JIT::privateCompileGetByIdSelfList):
        (JSC::JIT::patchGetByIdSelf):
        * jit/JIT.h:
        (JSC::JIT::compileGetByIdSelfList):

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

JavaScriptCore/ChangeLog
JavaScriptCore/bytecode/CodeBlock.cpp
JavaScriptCore/bytecode/Instruction.h
JavaScriptCore/bytecode/Opcode.h
JavaScriptCore/interpreter/Interpreter.cpp
JavaScriptCore/jit/JIT.cpp
JavaScriptCore/jit/JIT.h

index a3c0971..3268b27 100644 (file)
@@ -1,3 +1,30 @@
+2008-11-21  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Add (really) polymorphic caching for get by id self.
+        Very similar to caching of prototype accesses, described below.
+
+        Oh, also, probably shouldn't have been leaking those structure list objects.
+        
+        4% preogression on deltablue.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        (JSC::CodeBlock::derefStructures):
+        (JSC::PrototypeStructureList::derefStructures):
+        * bytecode/Instruction.h:
+        * bytecode/Opcode.h:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        (JSC::Interpreter::cti_op_get_by_id_self_fail):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileGetByIdSelfList):
+        (JSC::JIT::patchGetByIdSelf):
+        * jit/JIT.h:
+        (JSC::JIT::compileGetByIdSelfList):
+
 2008-11-21  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Sam Weinig.
index e4e2fab..ad783e2 100644 (file)
@@ -642,6 +642,10 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printGetByIdOp(location, it, identifiers, "get_by_id_self");
             break;
         }
+        case op_get_by_id_self_list: {
+            printGetByIdOp(location, it, identifiers, "get_by_id_self_list");
+            break;
+        }
         case op_get_by_id_proto: {
             printGetByIdOp(location, it, identifiers, "get_by_id_proto");
             break;
@@ -1023,18 +1027,11 @@ void CodeBlock::derefStructures(Instruction* vPC) const
             vPC[4].u.structure->deref();
         return;
     }
-    if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list)) {
-        PrototypeStructureList* prototypeStructures = vPC[4].u.prototypeStructure;
-        int count = vPC[5].u.operand;
-        for (int i = 0; i < count; ++i) {
-            PrototypeStructureList::ProtoStubInfo& info = prototypeStructures->list[i];
-            ASSERT(info.base);
-            ASSERT(info.proto);
-            ASSERT(info.stubRoutine);
-            info.base->deref();
-            info.proto->deref();
-            WTF::fastFreeExecutable(info.stubRoutine);
-        }
+    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))) {
+        PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
+        polymorphicStructures->derefStructures(vPC[5].u.operand);
+        delete polymorphicStructures;
         return;
     }
 
index cb29d91..7f8f088 100644 (file)
@@ -33,7 +33,7 @@
 #include "ResultType.h"
 #include <wtf/VectorTraits.h>
 
-#define PROTOTYPE_LIST_CACHE_SIZE 4
+#define POLYMORPHIC_LIST_CACHE_SIZE 4
 
 namespace JSC {
 
@@ -42,8 +42,8 @@ namespace JSC {
     class StructureChain;
 
     // Structure used by op_get_by_id_proto_list instruction to hold data off the main opcode stream.
-    struct PrototypeStructureList {
-        struct ProtoStubInfo {
+    struct PolymorphicAccessStructureList {
+        struct PolymorphicStubInfo {
             Structure* base;
             Structure* proto;
             int cachedOffset;
@@ -56,12 +56,28 @@ namespace JSC {
                 cachedOffset = _cachedOffset;
                 stubRoutine = _stubRoutine;
             }
-        } list[PROTOTYPE_LIST_CACHE_SIZE];
+        } list[POLYMORPHIC_LIST_CACHE_SIZE];
         
-        PrototypeStructureList(Structure* firstBase, Structure* firstProto, int cachedOffset, void* stubRoutine)
+        PolymorphicAccessStructureList(Structure* firstBase, Structure* firstProto, int cachedOffset, void* stubRoutine)
         {
             list[0].set(firstBase, firstProto, cachedOffset, stubRoutine);
         }
+
+        void derefStructures(int count)
+        {
+            for (int i = 0; i < count; ++i) {
+                PolymorphicStubInfo& info = list[i];
+
+                ASSERT(info.base);
+                info.base->deref();
+
+                if (info.proto)
+                    info.proto->deref();
+
+                if (info.stubRoutine)
+                    WTF::fastFreeExecutable(info.stubRoutine);
+            }
+        }
     };
 
     struct Instruction {
@@ -77,7 +93,7 @@ namespace JSC {
         Instruction(Structure* structure) { u.structure = structure; }
         Instruction(StructureChain* structureChain) { u.structureChain = structureChain; }
         Instruction(JSCell* jsCell) { u.jsCell = jsCell; }
-        Instruction(PrototypeStructureList* prototypeStructure) { u.prototypeStructure = prototypeStructure; }
+        Instruction(PolymorphicAccessStructureList* polymorphicStructures) { u.polymorphicStructures = polymorphicStructures; }
 
         union {
             Opcode opcode;
@@ -86,7 +102,7 @@ namespace JSC {
             StructureChain* structureChain;
             JSCell* jsCell;
             ResultType::Type resultType;
-            PrototypeStructureList* prototypeStructure;
+            PolymorphicAccessStructureList* polymorphicStructures;
         } u;
     };
 
index 0d78845..de8827a 100644 (file)
@@ -101,6 +101,7 @@ namespace JSC {
         macro(op_resolve_func) \
         macro(op_get_by_id) \
         macro(op_get_by_id_self) \
+        macro(op_get_by_id_self_list) \
         macro(op_get_by_id_proto) \
         macro(op_get_by_id_proto_list) \
         macro(op_get_by_id_chain) \
index b01ff4d..1c214ef 100644 (file)
@@ -2586,6 +2586,13 @@ JSValue* Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerF
         uncacheGetByID(callFrame->codeBlock(), vPC);
         NEXT_INSTRUCTION();
     }
+    DEFINE_OPCODE(op_get_by_id_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 += 8;
+        NEXT_INSTRUCTION();
+    }
     DEFINE_OPCODE(op_get_by_id_proto_list) {
         // Polymorphic prototype access caching currently only supported when JITting.
         ASSERT_NOT_REACHED();
@@ -4593,7 +4600,45 @@ JSValue* Interpreter::cti_op_get_by_id_self_fail(CTI_ARGS)
     PropertySlot slot(baseValue);
     JSValue* result = baseValue->get(callFrame, ident, slot);
 
-    CHECK_FOR_EXCEPTION_AT_END();
+    CHECK_FOR_EXCEPTION();
+
+    if (baseValue->isObject()
+        && slot.isCacheable()
+        && !asCell(baseValue)->structure()->isDictionary()
+        && slot.slotBase() == baseValue) {
+
+        CodeBlock* codeBlock = callFrame->codeBlock();
+        unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
+        Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
+
+        ASSERT(slot.slotBase()->isObject());
+
+        StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
+
+        PolymorphicAccessStructureList* polymorphicStructureList;
+        int listIndex = 1;
+
+        if (vPC[0].u.opcode == ARG_globalData->interpreter->getOpcode(op_get_by_id_self)) {
+            ASSERT(!stubInfo->stubRoutine);
+            polymorphicStructureList = new PolymorphicAccessStructureList(vPC[4].u.structure, 0, vPC[5].u.operand, 0);
+
+            vPC[0] = ARG_globalData->interpreter->getOpcode(op_get_by_id_self_list);
+            vPC[4] = polymorphicStructureList;
+            vPC[5] = 2;
+        } else {
+            polymorphicStructureList = vPC[4].u.polymorphicStructures;
+            listIndex = vPC[5].u.operand;
+
+            vPC[5] = listIndex + 1;
+        }
+
+        JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset());
+
+        if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
+            ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
+    } else {
+        ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
+    }
     return result;
 }
 
@@ -4634,18 +4679,18 @@ JSValue* Interpreter::cti_op_get_by_id_proto_list(CTI_ARGS)
 
         StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
 
-        PrototypeStructureList* prototypeStructureList;
+        PolymorphicAccessStructureList* prototypeStructureList;
         int listIndex = 1;
 
         if (vPC[0].u.opcode == ARG_globalData->interpreter->getOpcode(op_get_by_id_proto)) {
-            prototypeStructureList = new PrototypeStructureList(vPC[4].u.structure, vPC[5].u.structure, vPC[6].u.operand, stubInfo->stubRoutine);
+            prototypeStructureList = new PolymorphicAccessStructureList(vPC[4].u.structure, vPC[5].u.structure, vPC[6].u.operand, stubInfo->stubRoutine);
             stubInfo->stubRoutine = 0;
 
             vPC[0] = ARG_globalData->interpreter->getOpcode(op_get_by_id_proto_list);
             vPC[4] = prototypeStructureList;
             vPC[5] = 2;
         } else {
-            prototypeStructureList = vPC[4].u.prototypeStructure;
+            prototypeStructureList = vPC[4].u.polymorphicStructures;
             listIndex = vPC[5].u.operand;
 
             vPC[5] = listIndex + 1;
@@ -4653,7 +4698,7 @@ JSValue* Interpreter::cti_op_get_by_id_proto_list(CTI_ARGS)
 
         JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.cachedOffset());
 
-        if (listIndex == (PROTOTYPE_LIST_CACHE_SIZE - 1))
+        if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_list_full));
     } else {
         ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
index a5ae73a..85f1d25 100644 (file)
@@ -2359,6 +2359,7 @@ void JIT::privateCompileMainPass()
         case op_get_by_id_proto:
         case op_get_by_id_proto_list:
         case op_get_by_id_self:
+        case op_get_by_id_self_list:
         case op_get_string_length:
         case op_put_by_id_generic:
         case op_put_by_id_replace:
@@ -3230,7 +3231,36 @@ void JIT::privateCompileGetByIdProto(Structure* structure, Structure* prototypeS
 }
 
 #if USE(CTI_REPATCH_PIC)
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PrototypeStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset)
+{
+    JmpSrc failureCase = checkStructure(X86::eax, structure);
+    __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
+    __ movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
+    JmpSrc success = __ jmp();
+
+    void* code = __ executableCopy();
+    ASSERT(code);
+
+    // Use the repatch information to link the failure cases back to the original slow case routine.
+    void* lastProtoBegin = polymorphicStructures->list[currentIndex - 1].stubRoutine;
+    if (!lastProtoBegin)
+        lastProtoBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
+
+    X86Assembler::link(code, failureCase, lastProtoBegin);
+
+    // On success return back to the hot patch code, at a point it will perform the store to dest for us.
+    intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
+    X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
+
+    structure->ref();
+    polymorphicStructures->list[currentIndex].set(structure, 0, cachedOffset, 0/*code*/);
+
+    // Finally repatch the jump to slow case back in the hot path to jump here instead.
+    intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
+    X86Assembler::repatchBranchOffset(jmpLocation, code);
+}
+
+void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame)
 {
     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
     // referencing the prototype object - let's speculatively load it's table nice and early!)
@@ -3666,7 +3696,7 @@ void JIT::patchGetByIdSelf(CodeBlock* codeBlock, Structure* structure, size_t ca
 
     // We don't want to repatch more than once - in future go to cti_op_get_by_id_generic.
     // Should probably go to Interpreter::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
-    ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_generic));
+    ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
 
     // Repatch the offset into the propoerty map to load from, then repatch the Structure to look for.
     X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(info.hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
index 8f3e649..f72d33d 100644 (file)
@@ -109,7 +109,7 @@ namespace JSC {
     struct CallLinkInfo;
     struct Instruction;
     struct OperandTypes;
-    struct PrototypeStructureList;
+    struct PolymorphicAccessStructureList;
     struct StructureStubInfo;
 
     typedef JSValue* (SFX_CALL *CTIHelper_j)(CTI_ARGS);
@@ -320,7 +320,12 @@ namespace JSC {
         }
 
 #if USE(CTI_REPATCH_PIC)
-        static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PrototypeStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset)
+        static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset)
+        {
+            JIT jit(globalData, codeBlock);
+            jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, cachedOffset);
+        }
+        static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset)
         {
             JIT jit(globalData, codeBlock);
             jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, cachedOffset, callFrame);
@@ -379,7 +384,8 @@ namespace JSC {
         void privateCompileGetByIdSelf(Structure*, size_t cachedOffset, void* returnAddress);
         void privateCompileGetByIdProto(Structure*, Structure* prototypeStructure, size_t cachedOffset, void* returnAddress, CallFrame* callFrame);
 #if USE(CTI_REPATCH_PIC)
-        void privateCompileGetByIdProtoList(StructureStubInfo*, PrototypeStructureList*, int, Structure*, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame);
+        void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, size_t cachedOffset);
+        void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame);
 #endif
         void privateCompileGetByIdChain(Structure*, StructureChain*, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame);
         void privateCompilePutByIdReplace(Structure*, size_t cachedOffset, void* returnAddress);