llint_slow_path_put_by_id can deadlock on a ConcurrentJITLock
authormhahnenberg@apple.com <mhahnenberg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 Oct 2013 23:47:45 +0000 (23:47 +0000)
committermhahnenberg@apple.com <mhahnenberg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 Oct 2013 23:47:45 +0000 (23:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=122667

Reviewed by Geoffrey Garen.

The issue this patch is attempting to fix is that there are places in our codebase
where we acquire the ConcurrentJITLock for a particular CodeBlock, then we do some
operations that can initiate a garbage collection. Garbage collection then calls
some methods of CodeBlock that also take the ConcurrentJITLock (because they don't
always necessarily run during garbage collection). This causes a deadlock.

To fix this issue, this patch adds a new RAII-style object (DisallowGC) that stores
into a thread-local field that indicates that it is unsafe to perform any operation
that could trigger garbage collection on the current thread. In debug builds,
ConcurrentJITLocker contains one of these DisallowGC objects so that we can eagerly
detect deadlocks.

This patch also adds a new type of ConcurrentJITLocker, GCSafeConcurrentJITLocker,
which uses the DeferGC mechanism to prevent collections from occurring while the
lock is held.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* heap/DeferGC.h:
(JSC::DisallowGC::DisallowGC):
(JSC::DisallowGC::~DisallowGC):
(JSC::DisallowGC::isGCDisallowedOnCurrentThread):
(JSC::DisallowGC::initialize):
* jit/Repatch.cpp:
(JSC::repatchPutByID):
(JSC::buildPutByIdList):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/ConcurrentJITLock.h:
(JSC::ConcurrentJITLockerBase::ConcurrentJITLockerBase):
(JSC::ConcurrentJITLockerBase::~ConcurrentJITLockerBase):
(JSC::ConcurrentJITLockerBase::unlockEarly):
(JSC::GCSafeConcurrentJITLocker::GCSafeConcurrentJITLocker):
(JSC::GCSafeConcurrentJITLocker::~GCSafeConcurrentJITLocker):
(JSC::GCSafeConcurrentJITLocker::NoDefer::NoDefer):
(JSC::ConcurrentJITLocker::ConcurrentJITLocker):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreadingOnce):
* runtime/JSCellInlines.h:
(JSC::allocateCell):
* runtime/JSSymbolTableObject.h:
(JSC::symbolTablePut):
* runtime/Structure.cpp: materializePropertyMapIfNecessary* now has a problem in that it
can start a garbage collection when the GCSafeConcurrentJITLocker goes out of scope, but
before the caller has a chance to use the newly created PropertyTable. The garbage collection
clears the PropertyTable, and then the caller uses it assuming it's valid. To avoid this,
we must DeferGC until the caller is done getting the newly materialized PropertyTable from
the Structure.
(JSC::Structure::materializePropertyMap):
(JSC::Structure::despecifyDictionaryFunction):
(JSC::Structure::changePrototypeTransition):
(JSC::Structure::despecifyFunctionTransition):
(JSC::Structure::attributeChangeTransition):
(JSC::Structure::toDictionaryTransition):
(JSC::Structure::preventExtensionsTransition):
(JSC::Structure::takePropertyTableOrCloneIfPinned):
(JSC::Structure::isSealed):
(JSC::Structure::isFrozen):
(JSC::Structure::addPropertyWithoutTransition):
(JSC::Structure::removePropertyWithoutTransition):
(JSC::Structure::get):
(JSC::Structure::despecifyFunction):
(JSC::Structure::despecifyAllFunctions):
(JSC::Structure::putSpecificValue):
(JSC::Structure::createPropertyMap):
(JSC::Structure::getPropertyNamesFromStructure):
* runtime/Structure.h:
(JSC::Structure::materializePropertyMapIfNecessary):
(JSC::Structure::materializePropertyMapIfNecessaryForPinning):
* runtime/StructureInlines.h:
(JSC::Structure::get):
* runtime/SymbolTable.h:
(JSC::SymbolTable::find):
(JSC::SymbolTable::end):

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

17 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/heap/DeferGC.h
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/ConcurrentJITLock.h
Source/JavaScriptCore/runtime/InitializeThreading.cpp
Source/JavaScriptCore/runtime/JSCellInlines.h
Source/JavaScriptCore/runtime/JSSymbolTableObject.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureInlines.h
Source/JavaScriptCore/runtime/SymbolTable.h

index 2fee231525300bf9b9a157c9b1a01340ad2654cd..816fb1480a652454e13dd2bcfd5bbc92dc11fd63 100644 (file)
@@ -181,6 +181,7 @@ set(JavaScriptCore_SOURCES
     heap/ConservativeRoots.cpp
     heap/CopiedSpace.cpp
     heap/CopyVisitor.cpp
     heap/ConservativeRoots.cpp
     heap/CopiedSpace.cpp
     heap/CopyVisitor.cpp
+    heap/DeferGC.cpp
     heap/GCThread.cpp
     heap/GCThreadSharedData.cpp
     heap/HandleSet.cpp
     heap/GCThread.cpp
     heap/GCThreadSharedData.cpp
     heap/HandleSet.cpp
index e9f7cdcfb26e265d472d6cd27d77700128a3284c..86826ffb5c8b4e7fa9fc9fa6f35b87b93ec97308 100644 (file)
@@ -1,3 +1,88 @@
+2013-10-16  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+        llint_slow_path_put_by_id can deadlock on a ConcurrentJITLock
+        https://bugs.webkit.org/show_bug.cgi?id=122667
+
+        Reviewed by Geoffrey Garen.
+
+        The issue this patch is attempting to fix is that there are places in our codebase
+        where we acquire the ConcurrentJITLock for a particular CodeBlock, then we do some
+        operations that can initiate a garbage collection. Garbage collection then calls 
+        some methods of CodeBlock that also take the ConcurrentJITLock (because they don't
+        always necessarily run during garbage collection). This causes a deadlock.
+        To fix this issue, this patch adds a new RAII-style object (DisallowGC) that stores 
+        into a thread-local field that indicates that it is unsafe to perform any operation 
+        that could trigger garbage collection on the current thread. In debug builds, 
+        ConcurrentJITLocker contains one of these DisallowGC objects so that we can eagerly 
+        detect deadlocks.
+        This patch also adds a new type of ConcurrentJITLocker, GCSafeConcurrentJITLocker,
+        which uses the DeferGC mechanism to prevent collections from occurring while the 
+        lock is held.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * heap/DeferGC.h:
+        (JSC::DisallowGC::DisallowGC):
+        (JSC::DisallowGC::~DisallowGC):
+        (JSC::DisallowGC::isGCDisallowedOnCurrentThread):
+        (JSC::DisallowGC::initialize):
+        * jit/Repatch.cpp:
+        (JSC::repatchPutByID):
+        (JSC::buildPutByIdList):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/ConcurrentJITLock.h:
+        (JSC::ConcurrentJITLockerBase::ConcurrentJITLockerBase):
+        (JSC::ConcurrentJITLockerBase::~ConcurrentJITLockerBase):
+        (JSC::ConcurrentJITLockerBase::unlockEarly):
+        (JSC::GCSafeConcurrentJITLocker::GCSafeConcurrentJITLocker):
+        (JSC::GCSafeConcurrentJITLocker::~GCSafeConcurrentJITLocker):
+        (JSC::GCSafeConcurrentJITLocker::NoDefer::NoDefer):
+        (JSC::ConcurrentJITLocker::ConcurrentJITLocker):
+        * runtime/InitializeThreading.cpp:
+        (JSC::initializeThreadingOnce):
+        * runtime/JSCellInlines.h:
+        (JSC::allocateCell):
+        * runtime/JSSymbolTableObject.h:
+        (JSC::symbolTablePut):
+        * runtime/Structure.cpp: materializePropertyMapIfNecessary* now has a problem in that it
+        can start a garbage collection when the GCSafeConcurrentJITLocker goes out of scope, but 
+        before the caller has a chance to use the newly created PropertyTable. The garbage collection
+        clears the PropertyTable, and then the caller uses it assuming it's valid. To avoid this,
+        we must DeferGC until the caller is done getting the newly materialized PropertyTable from 
+        the Structure.
+        (JSC::Structure::materializePropertyMap):
+        (JSC::Structure::despecifyDictionaryFunction):
+        (JSC::Structure::changePrototypeTransition):
+        (JSC::Structure::despecifyFunctionTransition):
+        (JSC::Structure::attributeChangeTransition):
+        (JSC::Structure::toDictionaryTransition):
+        (JSC::Structure::preventExtensionsTransition):
+        (JSC::Structure::takePropertyTableOrCloneIfPinned):
+        (JSC::Structure::isSealed):
+        (JSC::Structure::isFrozen):
+        (JSC::Structure::addPropertyWithoutTransition):
+        (JSC::Structure::removePropertyWithoutTransition):
+        (JSC::Structure::get):
+        (JSC::Structure::despecifyFunction):
+        (JSC::Structure::despecifyAllFunctions):
+        (JSC::Structure::putSpecificValue):
+        (JSC::Structure::createPropertyMap):
+        (JSC::Structure::getPropertyNamesFromStructure):
+        * runtime/Structure.h:
+        (JSC::Structure::materializePropertyMapIfNecessary):
+        (JSC::Structure::materializePropertyMapIfNecessaryForPinning):
+        * runtime/StructureInlines.h:
+        (JSC::Structure::get):
+        * runtime/SymbolTable.h:
+        (JSC::SymbolTable::find):
+        (JSC::SymbolTable::end):
+
 2013-10-16  Daniel Bates  <dabates@apple.com>
 
         Add SPI to disable the garbage collector timer
 2013-10-16  Daniel Bates  <dabates@apple.com>
 
         Add SPI to disable the garbage collector timer
index ebdf66b85ba34ad8e2973adc6a65293fff9c0fbe..1aea5adfcec657f9aa176f1f83cae3cad6845738 100644 (file)
@@ -467,6 +467,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/heap/CopyWorkList.h \
        Source/JavaScriptCore/heap/ConservativeRoots.cpp \
        Source/JavaScriptCore/heap/ConservativeRoots.h \
        Source/JavaScriptCore/heap/CopyWorkList.h \
        Source/JavaScriptCore/heap/ConservativeRoots.cpp \
        Source/JavaScriptCore/heap/ConservativeRoots.h \
+   Source/JavaScriptCore/heap/DeferGC.cpp \
        Source/JavaScriptCore/heap/DeferGC.h \
        Source/JavaScriptCore/heap/GCAssertions.h \
        Source/JavaScriptCore/heap/GCIncomingRefCounted.h \
        Source/JavaScriptCore/heap/DeferGC.h \
        Source/JavaScriptCore/heap/GCAssertions.h \
        Source/JavaScriptCore/heap/GCIncomingRefCounted.h \
index 58fed1249cfb70f5b82e0d23dff9c6e7650caa3b..b2681e117ef7d133de8574039b01699af14a78c9 100644 (file)
     <ClCompile Include="..\heap\ConservativeRoots.cpp" />\r
     <ClCompile Include="..\heap\CopiedSpace.cpp" />\r
     <ClCompile Include="..\heap\CopyVisitor.cpp" />\r
     <ClCompile Include="..\heap\ConservativeRoots.cpp" />\r
     <ClCompile Include="..\heap\CopiedSpace.cpp" />\r
     <ClCompile Include="..\heap\CopyVisitor.cpp" />\r
+    <ClCompile Include="..\heap\DeferGC.cpp" />
     <ClCompile Include="..\heap\GCThread.cpp" />\r
     <ClCompile Include="..\heap\GCThreadSharedData.cpp" />\r
     <ClCompile Include="..\heap\HandleSet.cpp" />\r
     <ClCompile Include="..\heap\GCThread.cpp" />\r
     <ClCompile Include="..\heap\GCThreadSharedData.cpp" />\r
     <ClCompile Include="..\heap\HandleSet.cpp" />\r
     <ClInclude Include="..\heap\CopyVisitor.h" />\r
     <ClInclude Include="..\heap\CopyVisitorInlines.h" />\r
     <ClInclude Include="..\heap\CopyWorkList.h" />\r
     <ClInclude Include="..\heap\CopyVisitor.h" />\r
     <ClInclude Include="..\heap\CopyVisitorInlines.h" />\r
     <ClInclude Include="..\heap\CopyWorkList.h" />\r
+    <ClInclude Include="..\heap\DeferGC.h" />
     <ClInclude Include="..\heap\GCAssertions.h" />\r
     <ClInclude Include="..\heap\GCThread.h" />\r
     <ClInclude Include="..\heap\GCThreadSharedData.h" />\r
     <ClInclude Include="..\heap\GCAssertions.h" />\r
     <ClInclude Include="..\heap\GCThread.h" />\r
     <ClInclude Include="..\heap\GCThreadSharedData.h" />\r
index 1381c0bf0e67ccd030477692e2a976996bbe8650..27519b331f8c4b5f8fd4eb5c97499f061ddafb5a 100644 (file)
     <ClCompile Include="..\heap\CodeBlockSet.cpp">\r
       <Filter>heap</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\heap\CodeBlockSet.cpp">\r
       <Filter>heap</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\heap\DeferGC.cpp">
+      <Filter>heap</Filter>
+    </ClCompile>
     <ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp">\r
       <Filter>bytecode</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp">\r
       <Filter>bytecode</Filter>\r
     </ClCompile>\r
       <Filter>heap</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\heap\CopyWorkList.h">\r
       <Filter>heap</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\heap\CopyWorkList.h">\r
+      <Filter>heap</Filter>
+    </ClInclude>
+    <ClInclude Include="..\heap\DeferGC.h">
       <Filter>heap</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\heap\GCAssertions.h">\r
       <Filter>heap</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\heap\GCAssertions.h">\r
index 27b0b483c5010d0523dd62fafdf7f39b2b9efcf9..0cdf2ffe9d467872f4ef3bd2a663e4ad6a43d87f 100644 (file)
                0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */; };
                0FC815151405119B00CFA603 /* VTableSpectrum.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC815141405118D00CFA603 /* VTableSpectrum.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FC81516140511B500CFA603 /* VTableSpectrum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC815121405118600CFA603 /* VTableSpectrum.cpp */; };
                0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */; };
                0FC815151405119B00CFA603 /* VTableSpectrum.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC815141405118D00CFA603 /* VTableSpectrum.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FC81516140511B500CFA603 /* VTableSpectrum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC815121405118600CFA603 /* VTableSpectrum.cpp */; };
+       0FCEFAAB1804C13E00472CE4 /* FTLSaveRestore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAA91804C13E00472CE4 /* FTLSaveRestore.cpp */; };
+       0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCCAE4516D0CF7400D0C65B /* ParserError.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCCAE4316D0CF6E00D0C65B /* ParserError.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCEFAB01805CA6D00472CE4 /* InitializeLLVM.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAE1805CA6D00472CE4 /* InitializeLLVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCEFAB11805CA6D00472CE4 /* InitializeLLVMMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAAF1805CA6D00472CE4 /* InitializeLLVMMac.mm */; };
                0FCCAE4516D0CF7400D0C65B /* ParserError.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCCAE4316D0CF6E00D0C65B /* ParserError.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCEFAB01805CA6D00472CE4 /* InitializeLLVM.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAE1805CA6D00472CE4 /* InitializeLLVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCEFAB11805CA6D00472CE4 /* InitializeLLVMMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAAF1805CA6D00472CE4 /* InitializeLLVMMac.mm */; };
                1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A28D4A7177B71C80007FA3C /* JSStringRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACF7376171CA6FB00C9BB1E /* Weak.cpp */; };
                2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */; };
                1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A28D4A7177B71C80007FA3C /* JSStringRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACF7376171CA6FB00C9BB1E /* Weak.cpp */; };
                2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */; };
+       2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */; };
                2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; };
                2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; };
                2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6F462517E959CE00C45C98 /* HeapOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; };
                2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; };
                2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6F462517E959CE00C45C98 /* HeapOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FC712E017CD878F008CC93C /* JITToDFGDeferredCompilationCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JITToDFGDeferredCompilationCallback.cpp; sourceTree = "<group>"; };
                0FC712E117CD878F008CC93C /* JITToDFGDeferredCompilationCallback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JITToDFGDeferredCompilationCallback.h; sourceTree = "<group>"; };
                0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WriteBarrierSupport.cpp; sourceTree = "<group>"; };
                0FC712E017CD878F008CC93C /* JITToDFGDeferredCompilationCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JITToDFGDeferredCompilationCallback.cpp; sourceTree = "<group>"; };
                0FC712E117CD878F008CC93C /* JITToDFGDeferredCompilationCallback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JITToDFGDeferredCompilationCallback.h; sourceTree = "<group>"; };
                0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WriteBarrierSupport.cpp; sourceTree = "<group>"; };
+       0FCEFAA91804C13E00472CE4 /* FTLSaveRestore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLSaveRestore.cpp; path = ftl/FTLSaveRestore.cpp; sourceTree = "<group>"; };
+       0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSaveRestore.h; path = ftl/FTLSaveRestore.h; sourceTree = "<group>"; };
                0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; };
                0FC815121405118600CFA603 /* VTableSpectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VTableSpectrum.cpp; sourceTree = "<group>"; };
                0FC815141405118D00CFA603 /* VTableSpectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTableSpectrum.h; sourceTree = "<group>"; };
                0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; };
                0FC815121405118600CFA603 /* VTableSpectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VTableSpectrum.cpp; sourceTree = "<group>"; };
                0FC815141405118D00CFA603 /* VTableSpectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTableSpectrum.h; sourceTree = "<group>"; };
                1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = JavaScriptCore.xcconfig; sourceTree = "<group>"; };
                1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
                1C9051450BA9E8A70081E9D0 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
                1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = JavaScriptCore.xcconfig; sourceTree = "<group>"; };
                1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
                1C9051450BA9E8A70081E9D0 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
+       2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeferGC.cpp; sourceTree = "<group>"; };
                1CAA8B4A0D32C39A0041BCFF /* JavaScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScript.h; sourceTree = "<group>"; };
                1CAA8B4B0D32C39A0041BCFF /* JavaScriptCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCore.h; sourceTree = "<group>"; };
                2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringJoiner.cpp; sourceTree = "<group>"; };
                1CAA8B4A0D32C39A0041BCFF /* JavaScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScript.h; sourceTree = "<group>"; };
                1CAA8B4B0D32C39A0041BCFF /* JavaScriptCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCore.h; sourceTree = "<group>"; };
                2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringJoiner.cpp; sourceTree = "<group>"; };
                142E312A134FF0A600AFADB5 /* heap */ = {
                        isa = PBXGroup;
                        children = (
                142E312A134FF0A600AFADB5 /* heap */ = {
                        isa = PBXGroup;
                        children = (
+               2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */,
                                14816E19154CC56C00B8054C /* BlockAllocator.cpp */,
                                14816E1A154CC56C00B8054C /* BlockAllocator.h */,
                                0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */,
                                14816E19154CC56C00B8054C /* BlockAllocator.cpp */,
                                14816E1A154CC56C00B8054C /* BlockAllocator.h */,
                                0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */,
                                8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */,
                                0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */,
                                14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */,
                                8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */,
                                0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */,
                                14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */,
+               2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */,
                                8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */,
                                14280843107EC0930013E7B2 /* RegExpObject.cpp in Sources */,
                                14280844107EC0930013E7B2 /* RegExpPrototype.cpp in Sources */,
                                8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */,
                                14280843107EC0930013E7B2 /* RegExpObject.cpp in Sources */,
                                14280844107EC0930013E7B2 /* RegExpPrototype.cpp in Sources */,
index 81695184235b263c4a80d56610d31efb1f387aa0..02a1489cd51f270c35c6964426af09d4c7fe4908 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "Heap.h"
 #include <wtf/Noncopyable.h>
 
 #include "Heap.h"
 #include <wtf/Noncopyable.h>
+#include <wtf/ThreadSpecific.h>
 
 namespace JSC {
 
 
 namespace JSC {
 
@@ -67,6 +68,34 @@ private:
     Heap& m_heap;
 };
 
     Heap& m_heap;
 };
 
+#ifndef NDEBUG
+class DisallowGC {
+    WTF_MAKE_NONCOPYABLE(DisallowGC);
+public:
+    DisallowGC()
+    {
+        WTF::threadSpecificSet(s_isGCDisallowedOnCurrentThread, reinterpret_cast<void*>(true));
+    }
+
+    ~DisallowGC()
+    {
+        WTF::threadSpecificSet(s_isGCDisallowedOnCurrentThread, reinterpret_cast<void*>(false));
+    }
+
+    static bool isGCDisallowedOnCurrentThread()
+    {
+        return !!WTF::threadSpecificGet(s_isGCDisallowedOnCurrentThread);
+    }
+    static void initialize()
+    {
+        WTF::threadSpecificKeyCreate(&s_isGCDisallowedOnCurrentThread, 0);
+    }
+
+private:
+    JS_EXPORT_PRIVATE static WTF::ThreadSpecificKey s_isGCDisallowedOnCurrentThread;
+};
+#endif // NDEBUG
+
 } // namespace JSC
 
 #endif // DeferGC_h
 } // namespace JSC
 
 #endif // DeferGC_h
index 27e7cc46c42e3d545b1a3b21da851b6f36d21cde..75386a42b373b08d862020c141e62c26107e2b87 100644 (file)
@@ -360,7 +360,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
 
 void repatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
 
 void repatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
-    ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
+    GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
     bool cached = tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo);
     if (!cached)
     
     bool cached = tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo);
     if (!cached)
@@ -601,7 +601,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
 
 void buildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
 
 void buildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
-    ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
+    GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
     bool dontChangeCall = tryBuildGetByIDList(exec, baseValue, propertyName, slot, stubInfo);
     if (!dontChangeCall)
     
     bool dontChangeCall = tryBuildGetByIDList(exec, baseValue, propertyName, slot, stubInfo);
     if (!dontChangeCall)
@@ -1006,7 +1006,7 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
 
 void repatchPutByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
 
 void repatchPutByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
-    ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
+    GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
     bool cached = tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind);
     if (!cached)
     
     bool cached = tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind);
     if (!cached)
@@ -1101,7 +1101,7 @@ static bool tryBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identi
 
 void buildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
 
 void buildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
-    ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
+    GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
     bool cached = tryBuildPutByIdList(exec, baseValue, propertyName, slot, stubInfo, putKind);
     if (!cached)
     
     bool cached = tryBuildPutByIdList(exec, baseValue, propertyName, slot, stubInfo, putKind);
     if (!cached)
index 371ab5c33fc01c677f53224c2fc20de6a228090e..38dd2eb06da100e0136b7a7c86e6bfc28eeb13f7 100644 (file)
@@ -596,7 +596,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_id)
             && baseCell == slot.base()) {
             
             if (slot.type() == PutPropertySlot::NewProperty) {
             && baseCell == slot.base()) {
             
             if (slot.type() == PutPropertySlot::NewProperty) {
-                ConcurrentJITLocker locker(codeBlock->m_lock);
+                GCSafeConcurrentJITLocker locker(codeBlock->m_lock, vm.heap);
             
                 if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) {
                     ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated());
             
                 if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) {
                     ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated());
index 112dd350610e451acb1fa00ab31f2072a21ca627..84233d035682e922607f8d962f3f39b1fb19f82b 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef ConcurrentJITLock_h
 #define ConcurrentJITLock_h
 
 #ifndef ConcurrentJITLock_h
 #define ConcurrentJITLock_h
 
+#include "DeferGC.h"
 #include <wtf/ByteSpinLock.h>
 #include <wtf/NoLock.h>
 
 #include <wtf/ByteSpinLock.h>
 #include <wtf/NoLock.h>
 
@@ -33,13 +34,90 @@ namespace JSC {
 
 #if ENABLE(CONCURRENT_JIT)
 typedef ByteSpinLock ConcurrentJITLock;
 
 #if ENABLE(CONCURRENT_JIT)
 typedef ByteSpinLock ConcurrentJITLock;
-typedef ByteSpinLocker ConcurrentJITLocker;
+typedef ByteSpinLocker ConcurrentJITLockerImpl;
 #else
 typedef NoLock ConcurrentJITLock;
 #else
 typedef NoLock ConcurrentJITLock;
-typedef NoLockLocker ConcurrentJITLocker;
+typedef NoLockLocker ConcurrentJITLockerImpl;
 #endif
 
 #endif
 
+class ConcurrentJITLockerBase {
+    WTF_MAKE_NONCOPYABLE(ConcurrentJITLockerBase);
+public:
+    explicit ConcurrentJITLockerBase(ConcurrentJITLock& lockable)
+        : m_locker(&lockable)
+    {
+    }
+    explicit ConcurrentJITLockerBase(ConcurrentJITLock* lockable)
+        : m_locker(lockable)
+    {
+    }
+
+    ~ConcurrentJITLockerBase()
+    {
+    }
+    
+    void unlockEarly()
+    {
+        m_locker.unlockEarly();
+    }
+
+private:
+    ConcurrentJITLockerImpl m_locker;
+};
+
+class GCSafeConcurrentJITLocker : public ConcurrentJITLockerBase {
+public:
+    GCSafeConcurrentJITLocker(ConcurrentJITLock& lockable, Heap& heap)
+        : ConcurrentJITLockerBase(lockable)
+        , m_deferGC(heap)
+    {
+    }
+
+    GCSafeConcurrentJITLocker(ConcurrentJITLock* lockable, Heap& heap)
+        : ConcurrentJITLockerBase(lockable)
+        , m_deferGC(heap)
+    {
+    }
+
+    ~GCSafeConcurrentJITLocker()
+    {
+        // We have to unlock early due to the destruction order of base
+        // vs. derived classes. If we didn't, then we would destroy the 
+        // DeferGC object before unlocking the lock which could cause a GC
+        // and resulting deadlock.
+        unlockEarly();
+    }
+
+private:
+#if ENABLE(CONCURRENT_JIT)
+    DeferGC m_deferGC;
+#else
+    struct NoDefer {
+        NoDefer(Heap& heap) : m_heap(heap) { }
+        Heap& m_heap;
+    };
+    NoDefer m_deferGC;
+#endif
+};
+
+class ConcurrentJITLocker : public ConcurrentJITLockerBase {
+public:
+    ConcurrentJITLocker(ConcurrentJITLock& lockable)
+        : ConcurrentJITLockerBase(lockable)
+    {
+    }
+
+    ConcurrentJITLocker(ConcurrentJITLock* lockable)
+        : ConcurrentJITLockerBase(lockable)
+    {
+    }
+
+#if ENABLE(CONCURRENT_JIT) && !defined(NDEBUG)
+private:
+    DisallowGC m_disallowGC;
+#endif
+};
+
 } // namespace JSC
 
 #endif // ConcurrentJITLock_h
 } // namespace JSC
 
 #endif // ConcurrentJITLock_h
-
index 1a6c845140c2397af482de71b13228d9b1f154a4..dc8bddc44d4dbb412e8382312bcfa2ff48bc0259 100644 (file)
@@ -69,6 +69,9 @@ static void initializeThreadingOnce()
 #if ENABLE(LLINT)
     LLInt::initialize();
 #endif
 #if ENABLE(LLINT)
     LLInt::initialize();
 #endif
+#ifndef NDEBUG
+    DisallowGC::initialize();
+#endif
 }
 
 void initializeThreading()
 }
 
 void initializeThreading()
index 85c1922219614920dd7906ad41c95a1fedf48a57..139b8622bb851d0c0f8f60263656ab48e887c53e 100644 (file)
@@ -27,6 +27,7 @@
 #define JSCellInlines_h
 
 #include "CallFrame.h"
 #define JSCellInlines_h
 
 #include "CallFrame.h"
+#include "DeferGC.h"
 #include "Handle.h"
 #include "JSCell.h"
 #include "JSObject.h"
 #include "Handle.h"
 #include "JSCell.h"
 #include "JSObject.h"
@@ -85,6 +86,7 @@ inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
 template<typename T>
 void* allocateCell(Heap& heap, size_t size)
 {
 template<typename T>
 void* allocateCell(Heap& heap, size_t size)
 {
+    ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread());
     ASSERT(size >= sizeof(T));
 #if ENABLE(GC_VALIDATION)
     ASSERT(!heap.vm()->isInitializingObject());
     ASSERT(size >= sizeof(T));
 #if ENABLE(GC_VALIDATION)
     ASSERT(!heap.vm()->isInitializingObject());
index 671bb83996f7835869b1c097a2c62bedb292f03b..3d69a0451e1d16d0cb73dae9b66051752770e2e4 100644 (file)
@@ -125,7 +125,7 @@ inline bool symbolTablePut(
     WriteBarrierBase<Unknown>* reg;
     {
         SymbolTable& symbolTable = *object->symbolTable();
     WriteBarrierBase<Unknown>* reg;
     {
         SymbolTable& symbolTable = *object->symbolTable();
-        ConcurrentJITLocker locker(symbolTable.m_lock);
+        GCSafeConcurrentJITLocker locker(symbolTable.m_lock, exec->vm().heap);
         SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
         if (iter == symbolTable.end(locker))
             return false;
         SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
         if (iter == symbolTable.end(locker))
             return false;
index be653d7d4e2668eb121d8c1ef19ad9d86101b76a..ba403129713dab773c94fe61d134f4186e51e778 100644 (file)
@@ -280,7 +280,7 @@ void Structure::materializePropertyMap(VM& vm)
     // Must hold the lock on this structure, since we will be modifying this structure's
     // property map. We don't want getConcurrently() to see the property map in a half-baked
     // state.
     // Must hold the lock on this structure, since we will be modifying this structure's
     // property map. We don't want getConcurrently() to see the property map in a half-baked
     // state.
-    ConcurrentJITLocker locker(m_lock);
+    GCSafeConcurrentJITLocker locker(m_lock, vm.heap);
     if (!table)
         createPropertyMap(locker, vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
     else
     if (!table)
         createPropertyMap(locker, vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
     else
@@ -313,7 +313,8 @@ void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName)
 {
     StringImpl* rep = propertyName.uid();
 
 {
     StringImpl* rep = propertyName.uid();
 
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
 
     ASSERT(isDictionary());
     ASSERT(propertyTable());
 
     ASSERT(isDictionary());
     ASSERT(propertyTable());
@@ -451,7 +452,8 @@ Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JS
 
     transition->m_prototype.set(vm, transition, prototype);
 
 
     transition->m_prototype.set(vm, transition, prototype);
 
-    structure->materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    structure->materializePropertyMapIfNecessary(vm, deferGC);
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->pin();
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->pin();
@@ -467,7 +469,8 @@ Structure* Structure::despecifyFunctionTransition(VM& vm, Structure* structure,
 
     ++transition->m_specificFunctionThrashCount;
 
 
     ++transition->m_specificFunctionThrashCount;
 
-    structure->materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    structure->materializePropertyMapIfNecessary(vm, deferGC);
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->pin();
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->pin();
@@ -485,10 +488,11 @@ Structure* Structure::despecifyFunctionTransition(VM& vm, Structure* structure,
 
 Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes)
 {
 
 Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes)
 {
+    DeferGC deferGC(vm.heap);
     if (!structure->isUncacheableDictionary()) {
         Structure* transition = create(vm, structure);
 
     if (!structure->isUncacheableDictionary()) {
         Structure* transition = create(vm, structure);
 
-        structure->materializePropertyMapIfNecessary(vm);
+        structure->materializePropertyMapIfNecessary(vm, deferGC);
         transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
         transition->m_offset = structure->m_offset;
         transition->pin();
         transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
         transition->m_offset = structure->m_offset;
         transition->pin();
@@ -511,7 +515,8 @@ Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, Dicti
     
     Structure* transition = create(vm, structure);
 
     
     Structure* transition = create(vm, structure);
 
-    structure->materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    structure->materializePropertyMapIfNecessary(vm, deferGC);
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->m_dictionaryKind = kind;
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->m_dictionaryKind = kind;
@@ -571,7 +576,8 @@ Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure)
 
     // Don't set m_offset, as one can not transition to this.
 
 
     // Don't set m_offset, as one can not transition to this.
 
-    structure->materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    structure->materializePropertyMapIfNecessary(vm, deferGC);
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->m_preventExtensions = true;
     transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
     transition->m_offset = structure->m_offset;
     transition->m_preventExtensions = true;
@@ -583,7 +589,8 @@ Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure)
 
 PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm, Structure* owner)
 {
 
 PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm, Structure* owner)
 {
-    materializePropertyMapIfNecessaryForPinning(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessaryForPinning(vm, deferGC);
     
     if (m_isPinnedPropertyTable)
         return propertyTable()->copy(vm, owner, propertyTable()->size() + 1);
     
     if (m_isPinnedPropertyTable)
         return propertyTable()->copy(vm, owner, propertyTable()->size() + 1);
@@ -640,7 +647,8 @@ bool Structure::isSealed(VM& vm)
     if (isExtensible())
         return false;
 
     if (isExtensible())
         return false;
 
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return true;
 
     if (!propertyTable())
         return true;
 
@@ -658,7 +666,8 @@ bool Structure::isFrozen(VM& vm)
     if (isExtensible())
         return false;
 
     if (isExtensible())
         return false;
 
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return true;
 
     if (!propertyTable())
         return true;
 
@@ -718,7 +727,8 @@ PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName prop
     if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
         specificValue = 0;
 
     if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
         specificValue = 0;
 
-    materializePropertyMapIfNecessaryForPinning(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessaryForPinning(vm, deferGC);
     
     pin();
 
     
     pin();
 
@@ -730,7 +740,8 @@ PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName p
     ASSERT(isUncacheableDictionary());
     ASSERT(!enumerationCache());
 
     ASSERT(isUncacheableDictionary());
     ASSERT(!enumerationCache());
 
-    materializePropertyMapIfNecessaryForPinning(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessaryForPinning(vm, deferGC);
 
     pin();
     return remove(propertyName);
 
     pin();
     return remove(propertyName);
@@ -840,7 +851,8 @@ PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attri
     ASSERT(!isCompilationThread());
     ASSERT(structure()->classInfo() == info());
 
     ASSERT(!isCompilationThread());
     ASSERT(structure()->classInfo() == info());
 
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return invalidOffset;
 
     if (!propertyTable())
         return invalidOffset;
 
@@ -855,7 +867,8 @@ PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attri
 
 bool Structure::despecifyFunction(VM& vm, PropertyName propertyName)
 {
 
 bool Structure::despecifyFunction(VM& vm, PropertyName propertyName)
 {
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return false;
 
     if (!propertyTable())
         return false;
 
@@ -870,7 +883,8 @@ bool Structure::despecifyFunction(VM& vm, PropertyName propertyName)
 
 void Structure::despecifyAllFunctions(VM& vm)
 {
 
 void Structure::despecifyAllFunctions(VM& vm)
 {
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return;
 
     if (!propertyTable())
         return;
 
@@ -881,7 +895,7 @@ void Structure::despecifyAllFunctions(VM& vm)
 
 PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
 {
 
 PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
 {
-    ConcurrentJITLocker locker(m_lock);
+    GCSafeConcurrentJITLocker locker(m_lock, vm.heap);
     
     ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
 
     
     ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
 
@@ -926,7 +940,7 @@ PropertyOffset Structure::remove(PropertyName propertyName)
     return offset;
 }
 
     return offset;
 }
 
-void Structure::createPropertyMap(const ConcurrentJITLocker&, VM& vm, unsigned capacity)
+void Structure::createPropertyMap(const GCSafeConcurrentJITLocker&, VM& vm, unsigned capacity)
 {
     ASSERT(!propertyTable());
 
 {
     ASSERT(!propertyTable());
 
@@ -936,7 +950,8 @@ void Structure::createPropertyMap(const ConcurrentJITLocker&, VM& vm, unsigned c
 
 void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
 
 void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return;
 
     if (!propertyTable())
         return;
 
index 8d77ce7a179149eaf10fe91a04feecff55838a1d..231de8922710de352324f0127e89c3dadb4c47fc 100644 (file)
@@ -51,6 +51,7 @@
 
 namespace JSC {
 
 
 namespace JSC {
 
+class DeferGC;
 class LLIntOffsetsExtractor;
 class PropertyNameArray;
 class PropertyNameArrayData;
 class LLIntOffsetsExtractor;
 class PropertyNameArray;
 class PropertyNameArrayData;
@@ -393,7 +394,7 @@ private:
     PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
     PropertyOffset remove(PropertyName);
 
     PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
     PropertyOffset remove(PropertyName);
 
-    void createPropertyMap(const ConcurrentJITLocker&, VM&, unsigned keyCount = 0);
+    void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0);
     void checkConsistency();
 
     bool despecifyFunction(VM&, PropertyName);
     void checkConsistency();
 
     bool despecifyFunction(VM&, PropertyName);
@@ -404,7 +405,7 @@ private:
     PropertyTable* copyPropertyTable(VM&, Structure* owner);
     PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner);
     JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
     PropertyTable* copyPropertyTable(VM&, Structure* owner);
     PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner);
     JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
-    void materializePropertyMapIfNecessary(VM& vm)
+    void materializePropertyMapIfNecessary(VM& vm, DeferGC&)
     {
         ASSERT(!isCompilationThread());
         ASSERT(structure()->classInfo() == info());
     {
         ASSERT(!isCompilationThread());
         ASSERT(structure()->classInfo() == info());
@@ -412,7 +413,7 @@ private:
         if (!propertyTable() && previousID())
             materializePropertyMap(vm);
     }
         if (!propertyTable() && previousID())
             materializePropertyMap(vm);
     }
-    void materializePropertyMapIfNecessaryForPinning(VM& vm)
+    void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&)
     {
         ASSERT(structure()->classInfo() == info());
         checkOffsetConsistency();
     {
         ASSERT(structure()->classInfo() == info());
         checkOffsetConsistency();
index 5db6d31a787394b102552aa446cd09ad5692748f..0e4a9604d71727bf419e9aca60adf599659abb9d 100644 (file)
@@ -77,7 +77,8 @@ inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
 {
     ASSERT(!isCompilationThread());
     ASSERT(structure()->classInfo() == info());
 {
     ASSERT(!isCompilationThread());
     ASSERT(structure()->classInfo() == info());
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return invalidOffset;
 
     if (!propertyTable())
         return invalidOffset;
 
@@ -89,7 +90,8 @@ inline PropertyOffset Structure::get(VM& vm, const WTF::String& name)
 {
     ASSERT(!isCompilationThread());
     ASSERT(structure()->classInfo() == info());
 {
     ASSERT(!isCompilationThread());
     ASSERT(structure()->classInfo() == info());
-    materializePropertyMapIfNecessary(vm);
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
     if (!propertyTable())
         return invalidOffset;
 
     if (!propertyTable())
         return invalidOffset;
 
index 932056806ac497847a082a732ae4a56cfbba363d..f40daa2b30bb436f581542fd9ca9fa006e27d14d 100644 (file)
@@ -354,6 +354,11 @@ public:
         return m_map.find(key);
     }
     
         return m_map.find(key);
     }
     
+    Map::iterator find(const GCSafeConcurrentJITLocker&, StringImpl* key)
+    {
+        return m_map.find(key);
+    }
+    
     SymbolTableEntry get(const ConcurrentJITLocker&, StringImpl* key)
     {
         return m_map.get(key);
     SymbolTableEntry get(const ConcurrentJITLocker&, StringImpl* key)
     {
         return m_map.get(key);
@@ -386,6 +391,11 @@ public:
         return m_map.end();
     }
     
         return m_map.end();
     }
     
+    Map::iterator end(const GCSafeConcurrentJITLocker&)
+    {
+        return m_map.end();
+    }
+    
     size_t size(const ConcurrentJITLocker&) const
     {
         return m_map.size();
     size_t size(const ConcurrentJITLocker&) const
     {
         return m_map.size();