2010-08-07 Nathan Lawrence <nlawrence@apple.com>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 8 Aug 2010 06:04:59 +0000 (06:04 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 8 Aug 2010 06:04:59 +0000 (06:04 +0000)
        Reviewed by Geoffrey Garen.

        The JIT code contains a number of direct references to GC'd objects.
        When we have movable objects, these references will need to be
        updated.

        * Android.mk:
        * CMakeLists.txt:
        * GNUmakefile.am:
        * JavaScriptCore.gypi:
        * JavaScriptCore.pro:
        * JavaScriptCore.xcodeproj/project.pbxproj:
        * assembler/AbstractMacroAssembler.h:
        (JSC::AbstractMacroAssembler::int32AtLocation):
        (JSC::AbstractMacroAssembler::pointerAtLocation):
        (JSC::AbstractMacroAssembler::jumpTarget):
        * assembler/MacroAssembler.h:
        (JSC::MacroAssembler::loadPtrWithPatch):
            Normally, loadPtr will optimize when the register is eax.  Since
            the slightly smaller instruction changes the offsets, it messes up
            our ability to repatch the code.  We added this new instruction
            that garuntees a constant size.
        * assembler/MacroAssemblerX86.h:
        (JSC::MacroAssemblerX86::load32WithPatch):
            Changed load32 in the same way described above.
        (JSC::MacroAssemblerX86::load32):
            Moved the logic to optimize laod32 from movl_mr to load32
        (JSC::MacroAssemblerX86::store32):
            Moved the logic to optimize store32 from movl_rm to store32
        * assembler/X86Assembler.h:
        (JSC::X86Assembler::movl_rm):
        (JSC::X86Assembler::movl_mr):
        (JSC::X86Assembler::int32AtLocation):
        (JSC::X86Assembler::pointerAtLocation):
        (JSC::X86Assembler::jumpTarget):
        * bytecode/CodeBlock.cpp:
        (JSC::CodeBlock::markAggregate):
        * bytecode/Instruction.h:
            As described in StructureStubInfo.h, we needed to add additional
            fields to both StructureStubInfo and
            PolymorphicAccessStructureList so that we can determine the
            structure of the JITed code at patch time.
        (JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set):
        (JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
        * bytecode/StructureStubInfo.cpp:
        (JSC::StructureStubInfo::markAggregate):
            Added this function to mark the JITed code that correosponds to
            this structure stub info.
        * bytecode/StructureStubInfo.h:
        (JSC::StructureStubInfo::initGetByIdProto):
        (JSC::StructureStubInfo::initGetByIdChain):
        (JSC::StructureStubInfo::):
        * jit/JIT.h:
        * jit/JITMarkObjects.cpp: Added.
        (JSC::JIT::patchPrototypeStructureAddress):
        (JSC::JIT::patchGetDirectOffset):
        (JSC::JIT::markGetByIdProto):
        (JSC::JIT::markGetByIdChain):
        (JSC::JIT::markGetByIdProtoList):
        (JSC::JIT::markPutByIdTransition):
        (JSC::JIT::markGlobalObjectReference):
        * jit/JITPropertyAccess.cpp:
            Added asserts for the patch offsets.
        (JSC::JIT::compileGetDirectOffset):
        (JSC::JIT::testPrototype):
        (JSC::JIT::privateCompilePutByIdTransition):
        (JSC::JIT::privateCompileGetByIdProto):
        (JSC::JIT::privateCompileGetByIdProtoList):
        (JSC::JIT::privateCompileGetByIdChainList):
        (JSC::JIT::privateCompileGetByIdChain):
        * jit/JITPropertyAccess32_64.cpp:
        (JSC::JIT::compileGetDirectOffset):
        (JSC::JIT::testPrototype):
        (JSC::JIT::privateCompilePutByIdTransition):
        (JSC::JIT::privateCompileGetByIdProto):
        (JSC::JIT::privateCompileGetByIdProtoList):
        (JSC::JIT::privateCompileGetByIdChainList):
        (JSC::JIT::privateCompileGetByIdChain):
        * jit/JITStubs.cpp:
        (JSC::setupPolymorphicProtoList):
        * wtf/Platform.h:
            Added ENABLE_MOVABLE_GC_OBJECTS flag

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

22 files changed:
JavaScriptCore/Android.mk
JavaScriptCore/CMakeLists.txt
JavaScriptCore/ChangeLog
JavaScriptCore/GNUmakefile.am
JavaScriptCore/JavaScriptCore.gypi
JavaScriptCore/JavaScriptCore.pro
JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/assembler/AbstractMacroAssembler.h
JavaScriptCore/assembler/MacroAssembler.h
JavaScriptCore/assembler/MacroAssemblerX86.h
JavaScriptCore/assembler/X86Assembler.h
JavaScriptCore/bytecode/CodeBlock.cpp
JavaScriptCore/bytecode/Instruction.h
JavaScriptCore/bytecode/StructureStubInfo.cpp
JavaScriptCore/bytecode/StructureStubInfo.h
JavaScriptCore/jit/JIT.h
JavaScriptCore/jit/JITMarkObjects.cpp [new file with mode: 0644]
JavaScriptCore/jit/JITPropertyAccess.cpp
JavaScriptCore/jit/JITPropertyAccess32_64.cpp
JavaScriptCore/jit/JITStubs.cpp
JavaScriptCore/wtf/Platform.h

index 8dd53c1..0cc11bf 100644 (file)
@@ -52,6 +52,7 @@ LOCAL_SRC_FILES := \
        jit/JITArithmetic.cpp \
        jit/JITCall.cpp \
        jit/JITCall32_64.cpp \
+       jit/JITMarkObjects.cpp \
        jit/JITOpcodes.cpp \
        jit/JITPropertyAccess.cpp \
        jit/JITStubs.cpp \
index a944363..fe726d2 100644 (file)
@@ -55,6 +55,7 @@ SET(JavaScriptCore_SOURCES
     jit/JITCall32_64.cpp
     jit/JITCall.cpp
     jit/JIT.cpp
+    jit/JITMarkObjects.cpp
     jit/JITOpcodes32_64.cpp
     jit/JITOpcodes.cpp
     jit/JITPropertyAccess32_64.cpp
index 321a2f1..b2563c8 100644 (file)
@@ -1,3 +1,88 @@
+2010-08-07  Nathan Lawrence  <nlawrence@apple.com>
+
+        Reviewed by Geoffrey Garen.
+
+        The JIT code contains a number of direct references to GC'd objects.
+        When we have movable objects, these references will need to be
+        updated.
+
+        * Android.mk:
+        * CMakeLists.txt:
+        * GNUmakefile.am:
+        * JavaScriptCore.gypi:
+        * JavaScriptCore.pro:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/AbstractMacroAssembler.h:
+        (JSC::AbstractMacroAssembler::int32AtLocation):
+        (JSC::AbstractMacroAssembler::pointerAtLocation):
+        (JSC::AbstractMacroAssembler::jumpTarget):
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::loadPtrWithPatch):
+            Normally, loadPtr will optimize when the register is eax.  Since
+            the slightly smaller instruction changes the offsets, it messes up
+            our ability to repatch the code.  We added this new instruction
+            that garuntees a constant size.
+        * assembler/MacroAssemblerX86.h:
+        (JSC::MacroAssemblerX86::load32WithPatch):
+            Changed load32 in the same way described above.
+        (JSC::MacroAssemblerX86::load32):
+            Moved the logic to optimize laod32 from movl_mr to load32
+        (JSC::MacroAssemblerX86::store32):
+            Moved the logic to optimize store32 from movl_rm to store32
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::movl_rm):
+        (JSC::X86Assembler::movl_mr):
+        (JSC::X86Assembler::int32AtLocation):
+        (JSC::X86Assembler::pointerAtLocation):
+        (JSC::X86Assembler::jumpTarget):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::markAggregate):
+        * bytecode/Instruction.h:
+            As described in StructureStubInfo.h, we needed to add additional
+            fields to both StructureStubInfo and
+            PolymorphicAccessStructureList so that we can determine the
+            structure of the JITed code at patch time.
+        (JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set):
+        (JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::markAggregate):
+            Added this function to mark the JITed code that correosponds to
+            this structure stub info.
+        * bytecode/StructureStubInfo.h:
+        (JSC::StructureStubInfo::initGetByIdProto):
+        (JSC::StructureStubInfo::initGetByIdChain):
+        (JSC::StructureStubInfo::):
+        * jit/JIT.h:
+        * jit/JITMarkObjects.cpp: Added.
+        (JSC::JIT::patchPrototypeStructureAddress):
+        (JSC::JIT::patchGetDirectOffset):
+        (JSC::JIT::markGetByIdProto):
+        (JSC::JIT::markGetByIdChain):
+        (JSC::JIT::markGetByIdProtoList):
+        (JSC::JIT::markPutByIdTransition):
+        (JSC::JIT::markGlobalObjectReference):
+        * jit/JITPropertyAccess.cpp:
+            Added asserts for the patch offsets.
+        (JSC::JIT::compileGetDirectOffset):
+        (JSC::JIT::testPrototype):
+        (JSC::JIT::privateCompilePutByIdTransition):
+        (JSC::JIT::privateCompileGetByIdProto):
+        (JSC::JIT::privateCompileGetByIdProtoList):
+        (JSC::JIT::privateCompileGetByIdChainList):
+        (JSC::JIT::privateCompileGetByIdChain):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::compileGetDirectOffset):
+        (JSC::JIT::testPrototype):
+        (JSC::JIT::privateCompilePutByIdTransition):
+        (JSC::JIT::privateCompileGetByIdProto):
+        (JSC::JIT::privateCompileGetByIdProtoList):
+        (JSC::JIT::privateCompileGetByIdChainList):
+        (JSC::JIT::privateCompileGetByIdChain):
+        * jit/JITStubs.cpp:
+        (JSC::setupPolymorphicProtoList):
+        * wtf/Platform.h:
+            Added ENABLE_MOVABLE_GC_OBJECTS flag
+
 2010-08-07  Michael Saboff  <msaboff@apple.com>
 
         Reviewed by Geoffrey Garen.
index 2ead8e0..82bcb59 100644 (file)
@@ -165,6 +165,7 @@ javascriptcore_sources += \
        JavaScriptCore/jit/JIT.cpp \
        JavaScriptCore/jit/JIT.h \
        JavaScriptCore/jit/JITInlineMethods.h \
+       JavaScriptCore/jit/JITMarkObjects.cpp \
        JavaScriptCore/jit/JITOpcodes32_64.cpp \
        JavaScriptCore/jit/JITOpcodes.cpp \
        JavaScriptCore/jit/JITPropertyAccess32_64.cpp \
index a85d11c..b845c59 100644 (file)
             'jit/JITCall32_64.cpp',
             'jit/JITCode.h',
             'jit/JITInlineMethods.h',
+            'jit/JITMarkObjects.cpp',
             'jit/JITOpcodes.cpp',
             'jit/JITOpcodes32_64.cpp',
             'jit/JITPropertyAccess.cpp',
index d6c4420..2826c6b 100644 (file)
@@ -100,6 +100,7 @@ SOURCES += \
     jit/JITCall.cpp \
     jit/JITCall32_64.cpp \
     jit/JIT.cpp \
+    jit/JITMarkObjects.cpp \
     jit/JITOpcodes.cpp \
     jit/JITOpcodes32_64.cpp \
     jit/JITPropertyAccess.cpp \
index 83d34e3..5efa58c 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\jit\JITMarkObjects.cpp"\r
+                               >\r
+                       <File\r
                                RelativePath="..\..\jit\JITOpcodes.cpp"\r
                                >\r
                        </File>\r
index 4809218..6edc0c8 100644 (file)
                BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCFD8C900EEB2EE700283848 /* JumpTable.cpp */; };
                BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; };
                C0A272630E50A06300E96E15 /* NotFound.h in Headers */ = {isa = PBXBuildFile; fileRef = C0A2723F0E509F1E00E96E15 /* NotFound.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               DD23669811DBB22D00AF47C8 /* JITMarkObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD23669711DBB22D00AF47C8 /* JITMarkObjects.cpp */; };
                DD2724681208D1FF00F9ABE7 /* AlignedMemoryAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = DD2724671208D1FF00F9ABE7 /* AlignedMemoryAllocator.h */; };
                DD2724691208D1FF00F9ABE7 /* AlignedMemoryAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = DD2724671208D1FF00F9ABE7 /* AlignedMemoryAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DD377CBC12072C18006A2517 /* Bitmap.h in Headers */ = {isa = PBXBuildFile; fileRef = DD377CBB12072C18006A2517 /* Bitmap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C0A2723F0E509F1E00E96E15 /* NotFound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotFound.h; sourceTree = "<group>"; };
                D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; };
                D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; };
+               DD23669711DBB22D00AF47C8 /* JITMarkObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITMarkObjects.cpp; sourceTree = "<group>"; };
                DD2724671208D1FF00F9ABE7 /* AlignedMemoryAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlignedMemoryAllocator.h; sourceTree = "<group>"; };
                DD377CBB12072C18006A2517 /* Bitmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bitmap.h; sourceTree = "<group>"; };
                DDE82AD11209D955005C1756 /* GCHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCHandle.cpp; sourceTree = "<group>"; };
                1429D92C0ED22D7000B89619 /* jit */ = {
                        isa = PBXGroup;
                        children = (
+                               DD23669711DBB22D00AF47C8 /* JITMarkObjects.cpp */,
                                A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */,
                                A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */,
                                86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */,
                                86D08D5311793613006E5ED0 /* WTFThreadData.cpp in Sources */,
                                DDF7ABD511F60ED200108E36 /* GCActivityCallbackCF.cpp in Sources */,
                                8627E5EB11F1281900A313B5 /* PageAllocation.cpp in Sources */,
+                               DD23669811DBB22D00AF47C8 /* JITMarkObjects.cpp in Sources */,
                                DDE82AD71209D955005C1756 /* GCHandle.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
index aab9089..50997ac 100644 (file)
@@ -521,6 +521,21 @@ protected:
         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
     }
 
+    static int32_t int32AtLocation(CodeLocationDataLabel32 dataLabel32)
+    {
+        return AssemblerType::int32AtLocation(dataLabel32.dataLocation());
+    }
+
+    static void* pointerAtLocation(CodeLocationDataLabelPtr dataLabelPtr)
+    {
+        return AssemblerType::pointerAtLocation(dataLabelPtr.dataLocation());
+    }
+
+    static void* jumpTarget(CodeLocationJump jump)
+    {
+        return AssemblerType::jumpTarget(jump.dataLocation());
+    }
+
     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
     {
         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
index ce1be78..1632764 100644 (file)
@@ -209,6 +209,10 @@ public:
         xor32(imm, srcDest);
     }
 
+    void loadPtrWithPatch(void* address, RegisterID dest)
+    {
+        load32WithPatch(address, dest);
+    }
 
     void loadPtr(ImplicitAddress address, RegisterID dest)
     {
index 0918996..d2a794d 100644 (file)
@@ -82,11 +82,19 @@ public:
         m_assembler.subl_im(imm.m_value, address.m_ptr);
     }
 
-    void load32(void* address, RegisterID dest)
+    void load32WithPatch(void* address, RegisterID dest)
     {
         m_assembler.movl_mr(address, dest);
     }
 
+    void load32(void* address, RegisterID dest)
+    {
+        if (dest == X86Registers::eax)
+            m_assembler.movl_mEAX(address);
+        else
+            m_assembler.movl_mr(address, dest);
+    }
+
     void loadDouble(const void* address, FPRegisterID dest)
     {
         ASSERT(isSSE2Present());
@@ -105,7 +113,10 @@ public:
 
     void store32(RegisterID src, void* address)
     {
-        m_assembler.movl_rm(src, address);
+        if (src == X86Registers::eax)
+            m_assembler.movl_EAXm(address);
+        else
+            m_assembler.movl_rm(src, address);
     }
 
     Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
index a1fae0c..822f27c 100644 (file)
@@ -1154,18 +1154,12 @@ public:
 #else
     void movl_rm(RegisterID src, void* addr)
     {
-        if (src == X86Registers::eax)
-            movl_EAXm(addr);
-        else 
-            m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
+        m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
     }
     
     void movl_mr(void* addr, RegisterID dst)
     {
-        if (dst == X86Registers::eax)
-            movl_mEAX(addr);
-        else
-            m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
+        m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
     }
 
     void movl_i32m(int imm, void* addr)
@@ -1559,6 +1553,23 @@ public:
         setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
     }
 
+    static int32_t int32AtLocation(void* where)
+    {
+        return static_cast<int32_t*>(where)[-1];
+    }
+
+    static void* pointerAtLocation(void* where)
+    {
+        return static_cast<void**>(where)[-1];
+    }
+
+    static void* jumpTarget(void* jump)
+    {
+        intptr_t src = reinterpret_cast<intptr_t>(jump);
+        int32_t offset = static_cast<int32_t*>(jump)[-1];
+        return reinterpret_cast<void*>(src + offset);
+    }
+
     static void relinkJump(void* from, void* to)
     {
         setRel32(from, to);
index 9a8c332..d9a84d9 100644 (file)
@@ -1520,6 +1520,14 @@ void CodeBlock::markAggregate(MarkStack& markStack)
     for (size_t i = 0; i < m_functionDecls.size(); ++i)
         m_functionDecls[i]->markAggregate(markStack);
     markStack.append(m_globalObject);
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    // This is the code that is responsible for marking the actual pointers
+    // to JSCell*s in the JIT'ed code.  Normally, these pointers are marked
+    // elsewhere, however when we have movable objects, we will need to update
+    // all of the references.
+    for (size_t i = 0; i < m_structureStubInfos.size(); ++i)
+        m_structureStubInfos[i].markAggregate(markStack, this);
+#endif
 }
 
 bool CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
index c6468a5..96bf604 100644 (file)
@@ -63,6 +63,10 @@ namespace JSC {
                 Structure* proto;
                 StructureChain* chain;
             } u;
+#if ENABLE(MOVABLE_GC_OBJECTS)
+            int count;
+            PropertySlot::CachedPropertyType propertyType;
+#endif
 
             void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base)
             {
@@ -72,20 +76,35 @@ namespace JSC {
                 isChain = false;
             }
             
+#if ENABLE(MOVABLE_GC_OBJECTS)
+            void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto, PropertySlot::CachedPropertyType _propertyType)
+#else
             void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto)
+#endif
             {
                 stubRoutine = _stubRoutine;
                 base = _base;
                 u.proto = _proto;
                 isChain = false;
+#if ENABLE(MOVABLE_GC_OBJECTS)
+                propertyType = _propertyType;
+#endif
             }
             
+#if ENABLE(MOVABLE_GC_OBJECTS)
+            void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain, int _count, PropertySlot::CachedPropertyType _propertyType)
+#else
             void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain)
+#endif
             {
                 stubRoutine = _stubRoutine;
                 base = _base;
                 u.chain = _chain;
                 isChain = true;
+#if ENABLE(MOVABLE_GC_OBJECTS)
+                count = _count;
+                propertyType = _propertyType;
+#endif
             }
         } list[POLYMORPHIC_LIST_CACHE_SIZE];
         
@@ -94,15 +113,29 @@ namespace JSC {
             list[0].set(stubRoutine, firstBase);
         }
 
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto, PropertySlot::CachedPropertyType propertyType)
+        {
+            list[0].set(stubRoutine, firstBase, firstProto, propertyType);
+        }
+#else
         PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto)
         {
             list[0].set(stubRoutine, firstBase, firstProto);
         }
+#endif
 
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain, int count, PropertySlot::CachedPropertyType propertyType)
+        {
+            list[0].set(stubRoutine, firstBase, firstChain, count, propertyType);
+        }
+#else
         PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain)
         {
             list[0].set(stubRoutine, firstBase, firstChain);
         }
+#endif
 
         void derefStructures(int count)
         {
index 018d832..1f36de2 100644 (file)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "StructureStubInfo.h"
 
+#include "JIT.h"
+
 namespace JSC {
 
 #if ENABLE(JIT)
@@ -75,6 +77,39 @@ void StructureStubInfo::deref()
         ASSERT_NOT_REACHED();
     }
 }
+
+#if ENABLE(MOVABLE_GC_OBJECTS)
+void StructureStubInfo::markAggregate(MarkStack& markStack, CodeBlock* codeBlock)
+{
+    switch (accessType) {
+    case access_get_by_id_proto:
+        JIT::markGetByIdProto(markStack, codeBlock, this);
+        return;
+    case access_get_by_id_chain:
+        JIT::markGetByIdChain(markStack, codeBlock, this);
+        return;
+    case access_get_by_id_proto_list:
+        JIT::markGetByIdProtoList(markStack, codeBlock, this);
+        return;
+    case access_put_by_id_transition:
+        JIT::markPutByIdTransition(markStack, codeBlock, this);
+        return;
+    case access_get_by_id_self:
+    case access_get_by_id_self_list:
+    case access_put_by_id_replace:
+    case access_get_by_id:
+    case access_put_by_id:
+    case access_get_by_id_generic:
+    case access_put_by_id_generic:
+    case access_get_array_length:
+    case access_get_string_length:
+        return;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+#endif
+
 #endif
 
 } // namespace JSC
index 8578171..271ee01 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "Instruction.h"
 #include "MacroAssembler.h"
+#include "PropertySlot.h"
 #include "Opcode.h"
 #include "Structure.h"
 
@@ -66,7 +67,11 @@ namespace JSC {
             baseObjectStructure->ref();
         }
 
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        void initGetByIdProto(Structure* baseObjectStructure, Structure* prototypeStructure, CodeLocationLabel routine, PropertySlot::CachedPropertyType propertyType)
+#else
         void initGetByIdProto(Structure* baseObjectStructure, Structure* prototypeStructure, CodeLocationLabel routine)
+#endif
         {
             accessType = access_get_by_id_proto;
 
@@ -77,9 +82,17 @@ namespace JSC {
             prototypeStructure->ref();
 
             stubRoutine = routine;
+
+#if ENABLE(MOVABLE_GC_OBJECTS)
+            u.getByIdProto.propertyType = propertyType;
+#endif
         }
 
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        void initGetByIdChain(Structure* baseObjectStructure, StructureChain* chain, CodeLocationLabel routine, int count, PropertySlot::CachedPropertyType propertyType)
+#else
         void initGetByIdChain(Structure* baseObjectStructure, StructureChain* chain, CodeLocationLabel routine)
+#endif
         {
             accessType = access_get_by_id_chain;
 
@@ -90,6 +103,11 @@ namespace JSC {
             chain->ref();
 
             stubRoutine = routine;
+
+#if ENABLE(MOVABLE_GC_OBJECTS)
+            u.getByIdChain.count = count;
+            u.getByIdChain.propertyType = propertyType;
+#endif
         }
 
         void initGetByIdSelfList(PolymorphicAccessStructureList* structureList)
@@ -139,6 +157,9 @@ namespace JSC {
         }
 
         void deref();
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        void markAggregate(MarkStack&, CodeBlock*);
+#endif
 
         bool seenOnce()
         {
@@ -160,10 +181,24 @@ namespace JSC {
             struct {
                 Structure* baseObjectStructure;
                 Structure* prototypeStructure;
+#if ENABLE(MOVABLE_GC_OBJECTS)
+                // The propertyType is required to properly determine the
+                // structure of the underlying code so that we may patch it
+                // correctly.  Different code is generated for different
+                // property types, and therefore, the offsets that we need to
+                // patch at will change.
+                PropertySlot::CachedPropertyType propertyType;
+#endif
             } getByIdProto;
             struct {
                 Structure* baseObjectStructure;
                 StructureChain* chain;
+#if ENABLE(MOVABLE_GC_OBJECTS)
+                // We need the count so that we can iterate over the prototype
+                // chain, marking all of the references to objects.
+                int count;
+                PropertySlot::CachedPropertyType propertyType;
+#endif
             } getByIdChain;
             struct {
                 PolymorphicAccessStructureList* structureList;
index f3c4b6a..5dd9f71 100644 (file)
@@ -237,6 +237,18 @@ namespace JSC {
         static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct);
         static void patchMethodCallProto(CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr);
 
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        static void patchPrototypeStructureAddress(CodeLocationDataLabelPtr, MarkStack&, RepatchBuffer&);
+        static void patchGetDirectOffset(CodeLocationLabel, MarkStack&, RepatchBuffer&, PropertySlot::CachedPropertyType);
+        static void markGetByIdChainInternal(CodeLocationLabel, MarkStack&, RepatchBuffer&, PropertySlot::CachedPropertyType);
+
+        static void markGetByIdProto(MarkStack&, CodeBlock*, StructureStubInfo*);
+        static void markGetByIdChain(MarkStack&, CodeBlock*, StructureStubInfo*);
+        static void markGetByIdProtoList(MarkStack&, CodeBlock*, StructureStubInfo*);
+        static void markPutByIdTransition(MarkStack&, CodeBlock*, StructureStubInfo*);
+        static void markGlobalObjectReference(MarkStack&, CodeBlock*, CodeLocationDataLabelPtr);
+#endif
+
         static bool compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress)
         {
             JIT jit(globalData, codeBlock);
@@ -295,7 +307,7 @@ namespace JSC {
         void emitLoadDouble(unsigned index, FPRegisterID value);
         void emitLoadInt32ToDouble(unsigned index, FPRegisterID value);
 
-        void testPrototype(JSValue, JumpList& failureCases);
+        unsigned testPrototype(JSValue, JumpList& failureCases);
 
 #if USE(JSVALUE32_64)
         bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant);
@@ -366,6 +378,13 @@ namespace JSC {
         static const int patchOffsetMethodCheckProtoObj = 11;
         static const int patchOffsetMethodCheckProtoStruct = 18;
         static const int patchOffsetMethodCheckPutFunction = 29;
+
+        static const int patchOffsetGetByIdProtoStruct = 19;
+        static const int patchOffsetPutByIdProtoStruct = 12;
+        static const int patchLengthTestPrototype = 16;
+        static const int patchLengthBranchPtr = 10;
+        static const int patchLengthMove = 6;
+        static const int patchLengthStore = 10;
 #elif CPU(ARM_TRADITIONAL)
         // These architecture specific value are used to enable patching - see comment on op_put_by_id.
         static const int patchOffsetPutByIdStructure = 4;
@@ -536,6 +555,13 @@ namespace JSC {
         static const int patchOffsetMethodCheckProtoObj = 20;
         static const int patchOffsetMethodCheckProtoStruct = 30;
         static const int patchOffsetMethodCheckPutFunction = 50;
+
+        static const int patchOffsetGetByIdProtoStruct = 40;
+        static const int patchOffsetPutByIdProtoStruct = 20;
+        static const int patchLengthTestPrototype = 29;
+        static const int patchLengthBranchPtr = 9;
+        static const int patchLengthMove = 10;
+        static const int patchLengthStore = 13;
 #elif CPU(X86)
         // These architecture specific value are used to enable patching - see comment on op_put_by_id.
         static const int patchOffsetPutByIdStructure = 7;
diff --git a/JavaScriptCore/jit/JITMarkObjects.cpp b/JavaScriptCore/jit/JITMarkObjects.cpp
new file mode 100644 (file)
index 0000000..7eb3788
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+
+#if ENABLE(JIT)
+#if ENABLE(MOVABLE_GC_OBJECTS)
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+#include "JIT.h"
+
+#include "CodeBlock.h"
+#include "Interpreter.h"
+#include "JITInlineMethods.h"
+#include "JITStubCall.h"
+#include "JSArray.h"
+#include "JSFunction.h"
+#include "JSObject.h"
+#include "JSPropertyNameIterator.h"
+#include "LinkBuffer.h"
+#include "PropertySlot.h"
+#include "RepatchBuffer.h"
+#include "ResultType.h"
+#include "SamplingTool.h"
+
+using namespace std;
+
+namespace JSC {
+
+typedef PropertySlot::CachedPropertyType PropertyType;
+
+void JIT::patchPrototypeStructureAddress(CodeLocationDataLabelPtr where, MarkStack& markStack, RepatchBuffer& repatchBuffer)
+{
+    uintptr_t prototypeStructureAddress = reinterpret_cast<uintptr_t>(pointerAtLocation(where));
+    JSCell* cell = reinterpret_cast<JSCell*>(prototypeStructureAddress & CELL_ALIGN_MASK);
+
+    ASSERT(&(cell->m_structure) == pointerAtLocation(where));
+    markStack.append(cell);
+    repatchBuffer.repatch(where, &(cell->m_structure));
+}
+
+void JIT::patchGetDirectOffset(CodeLocationLabel patchStart, MarkStack& markStack, RepatchBuffer& repatchBuffer, PropertyType propertyType)
+{
+    CodeLocationDataLabelPtr where;
+    switch (propertyType) {
+    case PropertySlot::Getter:
+        where = patchStart.dataLabelPtrAtOffset(patchLengthStore);
+        break;
+    case PropertySlot::Custom:
+        where = patchStart.dataLabelPtrAtOffset(patchLengthMove);
+        break;
+    default:
+        where = patchStart.dataLabelPtrAtOffset(patchLengthMove);
+        break;
+    }
+
+    uintptr_t propertyAddress;
+    uintptr_t newPropertyAddress;
+    ptrdiff_t offset;
+    JSObject* object;
+
+#if USE(JSVALUE32_64)
+    // JSVALUE32_64 will need to repatch two pointers for 32 bit code
+    propertyAddress = reinterpret_cast<uintptr_t>(pointerAtLocation(where));
+    object = reinterpret_cast<JSObject*>(propertyAddress & CELL_ALIGN_MASK);
+    offset = propertyAddress & CELL_MASK;
+    markStack.append(object);
+    newPropertyAddress = reinterpret_cast<uintptr_t>(object) + offset;
+    repatchBuffer.repatch(where, reinterpret_cast<void*>(newPropertyAddress));
+
+    if (offset == OBJECT_OFFSETOF(JSObject, m_externalStorage))
+        return;
+
+    ASSERT(object->isUsingInlineStorage());
+    ASSERT(offset >= OBJECT_OFFSETOF(JSObject, m_inlineStorage));
+    ASSERT(offset < OBJECT_OFFSETOF(JSObject, m_inlineStorage[JSObject::inlineStorageCapacity]));
+
+    where = where.dataLabelPtrAtOffset(patchLengthMove);
+#endif
+
+    propertyAddress = reinterpret_cast<uintptr_t>(pointerAtLocation(where));
+    object = reinterpret_cast<JSObject*>(propertyAddress & CELL_ALIGN_MASK);
+    offset = propertyAddress & CELL_MASK;
+    markStack.append(object);
+    newPropertyAddress = reinterpret_cast<uintptr_t>(object) + offset;
+    repatchBuffer.repatch(where, reinterpret_cast<void*>(newPropertyAddress));
+}
+
+void JIT::markGetByIdProto(MarkStack& markStack, CodeBlock* codeBlock, StructureStubInfo* stubInfo)
+{
+    CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
+    CodeLocationLabel patchStart(jumpTarget(jumpLocation));
+
+    RepatchBuffer repatchBuffer(codeBlock);
+
+    CodeLocationDataLabelPtr where = patchStart.dataLabelPtrAtOffset(patchOffsetGetByIdProtoStruct);
+    patchPrototypeStructureAddress(patchStart.dataLabelPtrAtOffset(patchOffsetGetByIdProtoStruct), markStack, repatchBuffer);
+
+    patchGetDirectOffset(where.labelAtOffset(patchLengthBranchPtr), markStack, repatchBuffer, stubInfo->u.getByIdProto.propertyType);
+}
+
+void JIT::markGetByIdChain(MarkStack& markStack, CodeBlock* codeBlock, StructureStubInfo* stubInfo)
+{
+    CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
+    CodeLocationLabel patchStart(jumpTarget(jumpLocation));
+
+    RepatchBuffer repatchBuffer(codeBlock);
+
+    int count = stubInfo->u.getByIdChain.count;
+    for (int i = 0; i < count; ++i) {
+        CodeLocationDataLabelPtr where = patchStart.dataLabelPtrAtOffset(patchOffsetGetByIdProtoStruct + patchLengthTestPrototype * i);
+        patchPrototypeStructureAddress(where, markStack, repatchBuffer);
+    }
+    CodeLocationLabel where =
+            patchStart.labelAtOffset(patchOffsetGetByIdProtoStruct + patchLengthBranchPtr + patchLengthTestPrototype * (count - 1));
+    patchGetDirectOffset(where, markStack, repatchBuffer, stubInfo->u.getByIdChain.propertyType);
+}
+
+void JIT::markGetByIdProtoList(MarkStack& markStack, CodeBlock* codeBlock, StructureStubInfo* stubInfo)
+{
+    RepatchBuffer repatchBuffer(codeBlock);
+
+    for (int i = 0; i < stubInfo->u.getByIdSelfList.listSize; ++i) {
+        CodeLocationLabel patchStart = stubInfo->u.getByIdProtoList.structureList->list[i].stubRoutine;
+
+        PolymorphicAccessStructureList::PolymorphicStubInfo info =
+            stubInfo->u.getByIdProtoList.structureList->list[i];
+
+        if (!info.u.proto)
+            continue;
+
+        if (info.isChain) {
+            int count = info.count;
+            for (int j = 0; j < count; ++j) {
+                CodeLocationDataLabelPtr where = patchStart.dataLabelPtrAtOffset(patchOffsetGetByIdProtoStruct + patchLengthTestPrototype * j);
+                patchPrototypeStructureAddress(where, markStack, repatchBuffer);
+            }
+            CodeLocationLabel where =
+                    patchStart.labelAtOffset(patchOffsetGetByIdProtoStruct + patchLengthBranchPtr + patchLengthTestPrototype * (count - 1));
+            patchGetDirectOffset(where, markStack, repatchBuffer, info.propertyType);
+        } else {
+            CodeLocationDataLabelPtr where = patchStart.dataLabelPtrAtOffset(patchOffsetGetByIdProtoStruct);
+            patchPrototypeStructureAddress(where, markStack, repatchBuffer);
+
+            patchGetDirectOffset(where.labelAtOffset(patchLengthBranchPtr), markStack, repatchBuffer, info.propertyType);
+        }
+    }
+}
+
+void JIT::markPutByIdTransition(MarkStack& markStack, CodeBlock* codeBlock, StructureStubInfo* stubInfo)
+{
+    CodeLocationLabel patchStart = stubInfo->stubRoutine;
+
+    RepatchBuffer repatchBuffer(codeBlock);
+
+    RefPtr<Structure>* it = stubInfo->u.putByIdTransition.chain->head();
+    JSValue protoObject = stubInfo->u.putByIdTransition.structure->storedPrototype();
+
+    do {
+        if (protoObject.isNull())
+            continue;
+
+        CodeLocationDataLabelPtr where = patchStart.dataLabelPtrAtOffset(patchOffsetPutByIdProtoStruct + patchLengthTestPrototype);
+        patchPrototypeStructureAddress(where, markStack, repatchBuffer);
+
+        protoObject = it->get()->storedPrototype();
+        patchStart = patchStart.labelAtOffset(patchLengthTestPrototype);
+    } while (*it++);
+}
+
+void JIT::markGlobalObjectReference(MarkStack& markStack, CodeBlock* codeBlock, CodeLocationDataLabelPtr ref)
+{
+    RepatchBuffer repatchBuffer(codeBlock);
+    JSCell* globalObject = reinterpret_cast<JSCell*>(pointerAtLocation(ref));
+
+    ASSERT(!(reinterpret_cast<uintptr_t>(globalObject) & CELL_MASK));
+
+    markStack.append(globalObject);
+    repatchBuffer.repatch(ref, globalObject);
+}
+
+} // namespace JSC
+
+#endif
+
+#endif // ENABLE(MOVABLE_GC_OBJECTS) 
+#endif // ENABLE(JIT)
index 540e079..e1130e6 100644 (file)
@@ -573,22 +573,23 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, Structure*
     loadPtr(Address(base, offset), result);
 }
 
-void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset)
+void JIT::compileGetDirectOffset(JSObject* base, RegisterID, RegisterID result, size_t cachedOffset)
 {
     if (base->isUsingInlineStorage())
         loadPtr(static_cast<void*>(&base->m_inlineStorage[cachedOffset]), result);
     else {
         PropertyStorage* protoPropertyStorage = &base->m_externalStorage;
-        loadPtr(static_cast<void*>(protoPropertyStorage), temp);
-        loadPtr(Address(temp, cachedOffset * sizeof(JSValue)), result);
+        loadPtr(static_cast<void*>(protoPropertyStorage), result);
+        loadPtr(Address(result, cachedOffset * sizeof(JSValue)), result);
     } 
 }
 
-void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
+unsigned JIT::testPrototype(JSValue prototype, JumpList& failureCases)
 {
     if (prototype.isNull())
-        return;
+        return 0;
 
+    Label testPrototypeBegin(this);
     // We have a special case for X86_64 here because X86 instructions that take immediate values
     // only take 32 bit immediate values, wheras the pointer constants we are using here are 64 bit
     // values.  In the non X86_64 case, the generated code is slightly more efficient because it uses
@@ -599,20 +600,31 @@ void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
 #else
     failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), ImmPtr(asCell(prototype)->structure())));
 #endif
+    ASSERT_JIT_OFFSET(differenceBetween(testPrototypeBegin, Label(this)), patchLengthTestPrototype);
+
+    return patchLengthTestPrototype;
 }
 
 bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
 {
+    Label putByIdTransitionBegin(this);
     JumpList failureCases;
     // Check eax is an object of the right Structure.
     failureCases.append(emitJumpIfNotJSCell(regT0));
     failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure)));
-    testPrototype(oldStructure->storedPrototype(), failureCases);
+
+    unsigned offset = patchOffsetPutByIdProtoStruct + patchLengthBranchPtr;
+    ASSERT_JIT_OFFSET(differenceBetween(putByIdTransitionBegin, Label(this)), offset);
+
+    offset += testPrototype(oldStructure->storedPrototype(), failureCases);
+    ASSERT_JIT_OFFSET(differenceBetween(putByIdTransitionBegin, Label(this)), offset);
 
     // ecx = baseObject->m_structure
     if (!direct) {
-        for (RefPtr<Structure>* it = chain->head(); *it; ++it)
-            testPrototype((*it)->storedPrototype(), failureCases);
+        for (RefPtr<Structure>* it = chain->head(); *it; ++it) {
+            offset += testPrototype((*it)->storedPrototype(), failureCases);
+            ASSERT_JIT_OFFSET(differenceBetween(putByIdTransitionBegin, Label(this)), offset);
+        }
     }
 
     Call callTarget;
@@ -771,6 +783,7 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA
 
 bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
 {
+    Label getByIdProtoBegin(this);
     // 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!)
     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
@@ -787,6 +800,7 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
 
+    ASSERT_JIT_OFFSET(differenceBetween(getByIdProtoBegin, Label(this)), patchOffsetGetByIdProtoStruct + patchLengthBranchPtr);
     bool needsStubLink = false;
     
     // Checks out okay!
@@ -837,7 +851,11 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
 
     // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel, slot.cachedPropertyType());
+#else
     stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel);
+#endif
     return true;
 }
 
@@ -908,6 +926,7 @@ bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure*
 
 bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
 {
+    Label getByIdProtoListBegin(this);
     PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList;
     int currentIndex = stubInfo->u.getByIdProtoList.listSize;
 
@@ -927,6 +946,8 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure*
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
 
+    ASSERT_JIT_OFFSET(differenceBetween(getByIdProtoListBegin, Label(this)), patchOffsetGetByIdProtoStruct + patchLengthBranchPtr);
+
     // Checks out okay!
     bool needsStubLink = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
@@ -973,7 +994,11 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure*
 
     structure->ref();
     prototypeStructure->ref();
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure, slot.cachedPropertyType());
+#else
     prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure);
+#endif
 
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -989,6 +1014,8 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
     int currentIndex = stubInfo->u.getByIdProtoList.listSize;
 
     ASSERT(count);
+
+    Label getByIdChainListBegin(this);
     JumpList bucketsOfFail;
 
     // Check eax is an object of the right Structure.
@@ -1002,6 +1029,8 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
         currStructure = it->get();
         testPrototype(protoObject, bucketsOfFail);
+        ASSERT_JIT_OFFSET(differenceBetween(getByIdChainListBegin, Label(this)),
+            patchOffsetGetByIdProtoStruct + patchLengthBranchPtr + i * patchLengthTestPrototype);
     }
     ASSERT(protoObject);
     
@@ -1050,7 +1079,11 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
     // Track the stub we have created so that it will be deleted later.
     structure->ref();
     chain->ref();
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    prototypeStructures->list[currentIndex].set(entryLabel, structure, chain, count, slot.cachedPropertyType());
+#else
     prototypeStructures->list[currentIndex].set(entryLabel, structure, chain);
+#endif
 
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -1064,6 +1097,7 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
 {
     ASSERT(count);
 
+    Label getByIdChainBegin(this);
     JumpList bucketsOfFail;
 
     // Check eax is an object of the right Structure.
@@ -1076,6 +1110,8 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
         currStructure = it->get();
         testPrototype(protoObject, bucketsOfFail);
+        ASSERT_JIT_OFFSET(differenceBetween(getByIdChainBegin, Label(this)),
+            patchOffsetGetByIdProtoStruct + patchLengthBranchPtr + i * patchLengthTestPrototype);
     }
     ASSERT(protoObject);
 
@@ -1127,7 +1163,12 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
 
     // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    stubInfo->initGetByIdChain(structure, chain, entryLabel, count, slot.cachedPropertyType());
+#else
     stubInfo->initGetByIdChain(structure, chain, entryLabel);
+#endif
+
     return true;
 }
 
index bbffd7d..5127e85 100644 (file)
@@ -574,8 +574,12 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register
 
 void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset)
 {
+    Label directOffsetBegin(this);
     if (base->isUsingInlineStorage()) {
-        load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload), resultPayload);
+        // On X86, load32 will optimize for a slightly smaller instruction in the case that resultPayoad is regT0
+        // Since we want this instruction to always be the same length, we use load32WithPatch to avoid this problem
+        load32WithPatch(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload), resultPayload);
+        ASSERT_JIT_OFFSET(differenceBetween(directOffsetBegin, Label(this)), patchLengthMove);
         load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag), resultTag);
         return;
     }
@@ -583,16 +587,18 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res
     size_t offset = cachedOffset * sizeof(JSValue);
     
     PropertyStorage* protoPropertyStorage = &base->m_externalStorage;
-    loadPtr(static_cast<void*>(protoPropertyStorage), temp);
+    loadPtrWithPatch(static_cast<void*>(protoPropertyStorage), temp);
+    ASSERT_JIT_OFFSET(differenceBetween(directOffsetBegin, Label(this)), patchLengthMove);
     load32(Address(temp, offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
     load32(Address(temp, offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
 }
 
-void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
+unsigned JIT::testPrototype(JSValue prototype, JumpList& failureCases)
 {
     if (prototype.isNull())
-        return;
+        return 0;
     
+    Label testPrototypeBegin(this);
     // We have a special case for X86_64 here because X86 instructions that take immediate values
     // only take 32 bit immediate values, wheras the pointer constants we are using here are 64 bit
     // values.  In the non X86_64 case, the generated code is slightly more efficient because it uses
@@ -603,23 +609,34 @@ void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
 #else
     failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), ImmPtr(asCell(prototype)->structure())));
 #endif
+    ASSERT_JIT_OFFSET(differenceBetween(testPrototypeBegin, Label(this)), patchLengthTestPrototype);
+
+    return patchLengthTestPrototype;
 }
 
 bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
 {
     // It is assumed that regT0 contains the basePayload and regT1 contains the baseTag.  The value can be found on the stack.
     
+    Label putByIdTransitionBegin(this);
     JumpList failureCases;
     failureCases.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure)));
-    testPrototype(oldStructure->storedPrototype(), failureCases);
+
+    int offset = patchOffsetPutByIdProtoStruct + patchLengthBranchPtr;
+    ASSERT_JIT_OFFSET(differenceBetween(putByIdTransitionBegin, Label(this)), offset);
+
+    offset += testPrototype(oldStructure->storedPrototype(), failureCases);
+    ASSERT_JIT_OFFSET(differenceBetween(putByIdTransitionBegin, Label(this)), offset);
     
     if (!direct) {
         // Verify that nothing in the prototype chain has a setter for this property. 
-        for (RefPtr<Structure>* it = chain->head(); *it; ++it)
-            testPrototype((*it)->storedPrototype(), failureCases);
+        for (RefPtr<Structure>* it = chain->head(); *it; ++it) {
+            offset += testPrototype((*it)->storedPrototype(), failureCases);
+            ASSERT_JIT_OFFSET(differenceBetween(putByIdTransitionBegin, Label(this)), offset);
+        }
     }
-
+    
     // Reallocate property storage if needed.
     Call callTarget;
     bool willNeedStorageRealloc = oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
@@ -782,6 +799,7 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
 {
     // regT0 holds a JSCell*
     
+    Label getByIdProtoBegin(this);
     // 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!)
     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
@@ -796,6 +814,8 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
 #else
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
+    ASSERT_JIT_OFFSET(differenceBetween(getByIdProtoBegin, Label(this)), patchOffsetGetByIdProtoStruct + patchLengthBranchPtr);
+
     bool needsStubLink = false;
     // Checks out okay!
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
@@ -848,7 +868,11 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
     
     // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel, slot.cachedPropertyType());
+#else
     stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel);
+#endif
     return true;
 }
 
@@ -926,6 +950,7 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure*
 
     // regT0 holds a JSCell*
     
+    Label getByIdProtoListBegin(this);
     // 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!)
     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
@@ -941,6 +966,7 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure*
 #else
     Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
 #endif
+    ASSERT_JIT_OFFSET(differenceBetween(getByIdProtoListBegin, Label(this)), patchOffsetGetByIdProtoStruct + patchLengthBranchPtr);
     
     bool needsStubLink = false;
     if (slot.cachedPropertyType() == PropertySlot::Getter) {
@@ -961,7 +987,7 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure*
         stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
-    
+
     Jump success = jump();
     
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
@@ -986,8 +1012,12 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure*
     
     structure->ref();
     prototypeStructure->ref();
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure, slot.cachedPropertyType());
+#else
     prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure);
-    
+#endif
+
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
     RepatchBuffer repatchBuffer(m_codeBlock);
@@ -1004,6 +1034,7 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
     // regT0 holds a JSCell*
     ASSERT(count);
     
+    Label getByIdChainListBegin(this);
     JumpList bucketsOfFail;
     
     // Check eax is an object of the right Structure.
@@ -1016,6 +1047,9 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
         currStructure = it->get();
         testPrototype(protoObject, bucketsOfFail);
+
+        ASSERT_JIT_OFFSET(differenceBetween(getByIdChainListBegin, Label(this)),
+            patchOffsetGetByIdProtoStruct + patchLengthBranchPtr + static_cast<int>(i) * patchLengthTestPrototype);
     }
     ASSERT(protoObject);
     
@@ -1038,7 +1072,7 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
         stubCall.call();
     } else
         compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
-
+    
     Jump success = jump();
     
     LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
@@ -1064,8 +1098,12 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure*
     // Track the stub we have created so that it will be deleted later.
     structure->ref();
     chain->ref();
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    prototypeStructures->list[currentIndex].set(entryLabel, structure, chain, count, slot.cachedPropertyType());
+#else
     prototypeStructures->list[currentIndex].set(entryLabel, structure, chain);
-    
+#endif
+
     // Finally patch the jump to slow case back in the hot path to jump here instead.
     CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
     RepatchBuffer repatchBuffer(m_codeBlock);
@@ -1079,6 +1117,7 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
     // regT0 holds a JSCell*
     ASSERT(count);
     
+    Label getByIdChainBegin(this);
     JumpList bucketsOfFail;
     
     // Check eax is an object of the right Structure.
@@ -1091,6 +1130,9 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
         currStructure = it->get();
         testPrototype(protoObject, bucketsOfFail);
+
+        ASSERT_JIT_OFFSET(differenceBetween(getByIdChainBegin, Label(this)),
+            patchOffsetGetByIdProtoStruct + patchLengthBranchPtr + static_cast<int>(i) * patchLengthTestPrototype);
     }
     ASSERT(protoObject);
     
@@ -1141,7 +1183,11 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
     
     // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
     repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+#if ENABLE(MOVABLE_GC_OBJECTS)
+    stubInfo->initGetByIdChain(structure, chain, entryLabel, count, slot.cachedPropertyType());
+#else
     stubInfo->initGetByIdChain(structure, chain, entryLabel);
+#endif
     return true;
 }
 
index c4ff0ca..7d94e76 100644 (file)
@@ -1597,9 +1597,17 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
 static void setupPolymorphicProtoList(StructureStubInfo* stubInfo)
 {
     if (stubInfo->accessType == access_get_by_id_proto)
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure, stubInfo->u.getByIdProto.propertyType));
+#else
         stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure));
+#endif
     else if (stubInfo->accessType == access_get_by_id_chain)
+#if ENABLE(MOVABLE_GC_OBJECTS)
+        stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain, stubInfo->u.getByIdChain.count, stubInfo->u.getByIdChain.propertyType));
+#else
         stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain));
+#endif
     ASSERT(stubInfo->accessType == access_get_by_id_proto_list);
 }
 
index f40f834..d00c557 100644 (file)
@@ -1082,6 +1082,8 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 
 #define ENABLE_JSC_ZOMBIES 0
 
+#define ENABLE_MOVABLE_GC_OBJECTS 0
+
 /* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
 #if PLATFORM(MAC) || PLATFORM(WIN)
 #define WTF_USE_PLATFORM_STRATEGIES 1