Commit 4968e1a3 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

DFG should have a separate StoreBarrier node

https://bugs.webkit.org/show_bug.cgi?id=125530

Reviewed by Filip Pizlo.

Source/JavaScriptCore: 

This is in preparation for GenGC. We use a separate StoreBarrier node instead of making them implicitly 
part of other nodes so that it's easier to run analyses on them, e.g. for the StoreBarrierElisionPhase. 
They are inserted during the fixup phase. Initially they do not generate any code.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreter.h:
(JSC::DFG::AbstractInterpreter::isKnownNotCell):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberizeForAllocation):
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants): Whenever we insert new nodes that require StoreBarriers,
we have to add those new StoreBarriers too. It's important to note that AllocatePropertyStorage and 
ReallocatePropertyStorage nodes require their StoreBarriers to come after them since they allocate first,
which could cause a GC, and then store the resulting buffer into their JSCell, which requires the barrier.
If we ever require that write barriers occur before stores, we'll have to split these nodes into 
AllocatePropertyStorage + StoreBarrier + PutPropertyStorage.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::insertStoreBarrier):
* dfg/DFGNode.h:
(JSC::DFG::Node::isStoreBarrier):
* dfg/DFGNodeType.h:
* dfg/DFGOSRExitCompiler32_64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOSRExitCompiler64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileStoreBarrier):
(JSC::DFG::SpeculativeJIT::genericWriteBarrier): The fast path write barrier check. It loads the 
byte that contains the mark bit of the object. 
(JSC::DFG::SpeculativeJIT::storeToWriteBarrierBuffer): If the fast path check fails we try to store the 
cell in the WriteBarrierBuffer so as to avoid frequently flushing all registers in order to make a C call.
(JSC::DFG::SpeculativeJIT::writeBarrier):
(JSC::DFG::SpeculativeJIT::osrWriteBarrier): More barebones version of the write barrier to be executed 
during an OSR exit into baseline code. We must do this so that the baseline JIT object and array profiles 
are properly cleared during GC.
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compileBaseValueStoreBarrier):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::writeBarrier):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compileBaseValueStoreBarrier):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::writeBarrier):
* dfg/DFGStoreBarrierElisionPhase.cpp: Added. New DFG phase that does block-local elision of redundant
StoreBarriers. Every time a StoreBarrier on a particular object is executed, a bit is set indicating that 
that object doesn't need any more StoreBarriers. 
(JSC::DFG::StoreBarrierElisionPhase::StoreBarrierElisionPhase):
(JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): Nodes that could cause a GC reset the bits for all of the 
objects known in the current block. 
(JSC::DFG::StoreBarrierElisionPhase::allocatesFreshObject): A node that creates a new object automatically 
sets the bit for that object since if a GC occurred as the result of that object's allocation then that 
object would not need a barrier since it would be guaranteed to be a young generation object until the 
next GC point.
(JSC::DFG::StoreBarrierElisionPhase::noticeFreshObject):
(JSC::DFG::StoreBarrierElisionPhase::getBaseOfStore):
(JSC::DFG::StoreBarrierElisionPhase::shouldBeElided):
(JSC::DFG::StoreBarrierElisionPhase::elideBarrier):
(JSC::DFG::StoreBarrierElisionPhase::handleNode):
(JSC::DFG::StoreBarrierElisionPhase::handleBlock):
(JSC::DFG::StoreBarrierElisionPhase::run):
(JSC::DFG::performStoreBarrierElision):
* dfg/DFGStoreBarrierElisionPhase.h: Added.
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::flushWriteBarrierBuffer):
* heap/Heap.h:
(JSC::Heap::writeBarrier):
* heap/MarkedBlock.h:
(JSC::MarkedBlock::offsetOfMarks):
* heap/WriteBarrierBuffer.cpp: Added. The WriteBarrierBuffer buffers a set of JSCells that are awaiting 
a pending WriteBarrier. This buffer is used by the DFG to avoid the overhead of calling out to C repeatedly
to invoke a write barrier on a single JSCell. Instead the DFG has inline code to fill the WriteBarrier buffer
until its full, and then to call out to C to flush it. The WriteBarrierBuffer will also be flushed prior to 
each EdenCollection.
(JSC::WriteBarrierBuffer::WriteBarrierBuffer):
(JSC::WriteBarrierBuffer::~WriteBarrierBuffer):
(JSC::WriteBarrierBuffer::flush):
(JSC::WriteBarrierBuffer::reset):
(JSC::WriteBarrierBuffer::add):
* heap/WriteBarrierBuffer.h: Added.
(JSC::WriteBarrierBuffer::currentIndexOffset):
(JSC::WriteBarrierBuffer::capacityOffset):
(JSC::WriteBarrierBuffer::bufferOffset):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* runtime/VM.h:

Source/WTF: 

* wtf/Platform.h: Added an #define for ENABLE(GGC) which will be used for landing things related to GenGC.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160796 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 1a03c926
......@@ -172,6 +172,7 @@ set(JavaScriptCore_SOURCES
dfg/DFGSpeculativeJIT32_64.cpp
dfg/DFGSpeculativeJIT64.cpp
dfg/DFGStackLayoutPhase.cpp
dfg/DFGStoreBarrierElisionPhase.cpp
dfg/DFGStrengthReductionPhase.cpp
dfg/DFGThunks.cpp
dfg/DFGTierUpCheckInjectionPhase.cpp
......@@ -219,6 +220,7 @@ set(JavaScriptCore_SOURCES
heap/WeakBlock.cpp
heap/WeakHandleOwner.cpp
heap/WeakSet.cpp
heap/WriteBarrierBuffer.cpp
heap/WriteBarrierSupport.cpp
inspector/InspectorAgentRegistry.cpp
......
2013-12-18 Mark Hahnenberg <mhahnenberg@apple.com>
DFG should have a separate StoreBarrier node
https://bugs.webkit.org/show_bug.cgi?id=125530
Reviewed by Filip Pizlo.
This is in preparation for GenGC. We use a separate StoreBarrier node instead of making them implicitly
part of other nodes so that it's easier to run analyses on them, e.g. for the StoreBarrierElisionPhase.
They are inserted during the fixup phase. Initially they do not generate any code.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreter.h:
(JSC::DFG::AbstractInterpreter::isKnownNotCell):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberizeForAllocation):
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants): Whenever we insert new nodes that require StoreBarriers,
we have to add those new StoreBarriers too. It's important to note that AllocatePropertyStorage and
ReallocatePropertyStorage nodes require their StoreBarriers to come after them since they allocate first,
which could cause a GC, and then store the resulting buffer into their JSCell, which requires the barrier.
If we ever require that write barriers occur before stores, we'll have to split these nodes into
AllocatePropertyStorage + StoreBarrier + PutPropertyStorage.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::insertStoreBarrier):
* dfg/DFGNode.h:
(JSC::DFG::Node::isStoreBarrier):
* dfg/DFGNodeType.h:
* dfg/DFGOSRExitCompiler32_64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGOSRExitCompiler64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileStoreBarrier):
(JSC::DFG::SpeculativeJIT::genericWriteBarrier): The fast path write barrier check. It loads the
byte that contains the mark bit of the object.
(JSC::DFG::SpeculativeJIT::storeToWriteBarrierBuffer): If the fast path check fails we try to store the
cell in the WriteBarrierBuffer so as to avoid frequently flushing all registers in order to make a C call.
(JSC::DFG::SpeculativeJIT::writeBarrier):
(JSC::DFG::SpeculativeJIT::osrWriteBarrier): More barebones version of the write barrier to be executed
during an OSR exit into baseline code. We must do this so that the baseline JIT object and array profiles
are properly cleared during GC.
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compileBaseValueStoreBarrier):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::writeBarrier):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compileBaseValueStoreBarrier):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::writeBarrier):
* dfg/DFGStoreBarrierElisionPhase.cpp: Added. New DFG phase that does block-local elision of redundant
StoreBarriers. Every time a StoreBarrier on a particular object is executed, a bit is set indicating that
that object doesn't need any more StoreBarriers.
(JSC::DFG::StoreBarrierElisionPhase::StoreBarrierElisionPhase):
(JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): Nodes that could cause a GC reset the bits for all of the
objects known in the current block.
(JSC::DFG::StoreBarrierElisionPhase::allocatesFreshObject): A node that creates a new object automatically
sets the bit for that object since if a GC occurred as the result of that object's allocation then that
object would not need a barrier since it would be guaranteed to be a young generation object until the
next GC point.
(JSC::DFG::StoreBarrierElisionPhase::noticeFreshObject):
(JSC::DFG::StoreBarrierElisionPhase::getBaseOfStore):
(JSC::DFG::StoreBarrierElisionPhase::shouldBeElided):
(JSC::DFG::StoreBarrierElisionPhase::elideBarrier):
(JSC::DFG::StoreBarrierElisionPhase::handleNode):
(JSC::DFG::StoreBarrierElisionPhase::handleBlock):
(JSC::DFG::StoreBarrierElisionPhase::run):
(JSC::DFG::performStoreBarrierElision):
* dfg/DFGStoreBarrierElisionPhase.h: Added.
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::flushWriteBarrierBuffer):
* heap/Heap.h:
(JSC::Heap::writeBarrier):
* heap/MarkedBlock.h:
(JSC::MarkedBlock::offsetOfMarks):
* heap/WriteBarrierBuffer.cpp: Added. The WriteBarrierBuffer buffers a set of JSCells that are awaiting
a pending WriteBarrier. This buffer is used by the DFG to avoid the overhead of calling out to C repeatedly
to invoke a write barrier on a single JSCell. Instead the DFG has inline code to fill the WriteBarrier buffer
until its full, and then to call out to C to flush it. The WriteBarrierBuffer will also be flushed prior to
each EdenCollection.
(JSC::WriteBarrierBuffer::WriteBarrierBuffer):
(JSC::WriteBarrierBuffer::~WriteBarrierBuffer):
(JSC::WriteBarrierBuffer::flush):
(JSC::WriteBarrierBuffer::reset):
(JSC::WriteBarrierBuffer::add):
* heap/WriteBarrierBuffer.h: Added.
(JSC::WriteBarrierBuffer::currentIndexOffset):
(JSC::WriteBarrierBuffer::capacityOffset):
(JSC::WriteBarrierBuffer::bufferOffset):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* runtime/VM.h:
2013-12-18 Carlos Garcia Campos <cgarcia@igalia.com>
Unreviewed. Fix make distcheck.
......
......@@ -387,6 +387,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/dfg/DFGSSALoweringPhase.h \
Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp \
Source/JavaScriptCore/dfg/DFGStackLayoutPhase.h \
Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.cpp \
Source/JavaScriptCore/dfg/DFGStoreBarrierElisionPhase.h \
Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp \
Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.h \
Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h \
......@@ -576,6 +578,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/WeakSet.h \
Source/JavaScriptCore/heap/WeakSetInlines.h \
Source/JavaScriptCore/heap/WeakReferenceHarvester.h \
Source/JavaScriptCore/heap/WriteBarrierBuffer.cpp \
Source/JavaScriptCore/heap/WriteBarrierBuffer.h \
Source/JavaScriptCore/heap/WriteBarrierSupport.cpp \
Source/JavaScriptCore/heap/WriteBarrierSupport.h \
Source/JavaScriptCore/config.h \
......
......@@ -428,6 +428,7 @@
<ClCompile Include="..\dfg\DFGSSAConversionPhase.cpp" />
<ClCompile Include="..\dfg\DFGSSALoweringPhase.cpp" />
<ClCompile Include="..\dfg\DFGStackLayoutPhase.cpp" />
<ClCompile Include="..\dfg\DFGStoreBarrierElisionPhase.cpp" />
<ClCompile Include="..\dfg\DFGStrengthReductionPhase.cpp" />
<ClCompile Include="..\dfg\DFGThunks.cpp" />
<ClCompile Include="..\dfg\DFGTierUpCheckInjectionPhase.cpp" />
......@@ -471,6 +472,7 @@
<ClCompile Include="..\heap\WeakBlock.cpp" />
<ClCompile Include="..\heap\WeakHandleOwner.cpp" />
<ClCompile Include="..\heap\WeakSet.cpp" />
<ClCompile Include="..\heap\WriteBarrierBuffer.cpp" />
<ClCompile Include="..\heap\WriteBarrierSupport.cpp" />
<ClCompile Include="..\inspector\InspectorAgentRegistry.cpp" />
<ClCompile Include="..\inspector\InspectorBackendDispatcher.cpp" />
......@@ -948,6 +950,7 @@
<ClInclude Include="..\dfg\DFGSSAConversionPhase.h" />
<ClInclude Include="..\dfg\DFGSSALoweringPhase.h" />
<ClInclude Include="..\dfg\DFGStackLayoutPhase.h" />
<ClInclude Include="..\dfg\DFGStoreBarrierElisionPhase.h" />
<ClInclude Include="..\dfg\DFGStrengthReductionPhase.h" />
<ClInclude Include="..\dfg\DFGStructureAbstractValue.h" />
<ClInclude Include="..\dfg\DFGThunks.h" />
......@@ -1026,6 +1029,7 @@
<ClInclude Include="..\heap\WeakReferenceHarvester.h" />
<ClInclude Include="..\heap\WeakSet.h" />
<ClInclude Include="..\heap\WeakSetInlines.h" />
<ClInclude Include="..\heap\WriteBarrierBuffer.h" />
<ClInclude Include="..\heap\WriteBarrierSupport.h" />
<ClInclude Include="..\inspector\InspectorAgentBase.h" />
<ClInclude Include="..\inspector\InspectorAgentRegistry.h" />
......@@ -1384,4 +1388,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -279,6 +279,9 @@
<ClCompile Include="..\heap\WeakSet.cpp">
<Filter>heap</Filter>
</ClCompile>
<ClCompile Include="..\heap\WriteBarrierBuffer.cpp">
<Filter>heap</Filter>
</ClCompile>
<ClCompile Include="..\heap\WriteBarrierSupport.cpp">
<Filter>heap</Filter>
</ClCompile>
......@@ -1149,6 +1152,9 @@
<ClCompile Include="..\dfg\DFGStackLayoutPhase.cpp">
<Filter>dfg</Filter>
</ClCompile>
<ClCompile Include="..\dfg\DFGStoreBarrierElisionPhase.cpp">
<Filter>dfg</Filter>
</ClCompile>
<ClCompile Include="..\dfg\DFGThunks.cpp">
<Filter>dfg</Filter>
</ClCompile>
......@@ -1754,6 +1760,9 @@
<ClInclude Include="..\heap\WeakSetInlines.h">
<Filter>heap</Filter>
</ClInclude>
<ClInclude Include="..\heap\WriteBarrierBuffer.h">
<Filter>heap</Filter>
</ClInclude>
<ClInclude Include="..\heap\WriteBarrierSupport.h">
<Filter>heap</Filter>
</ClInclude>
......@@ -3057,6 +3066,9 @@
<ClInclude Include="..\dfg\DFGStackLayoutPhase.h">
<Filter>dfg</Filter>
</ClInclude>
<ClInclude Include="..\dfg\DFGStoreBarrierElisionPhase.h">
<Filter>dfg</Filter>
</ClInclude>
<ClInclude Include="..\dfg\DFGStructureAbstractValue.h">
<Filter>dfg</Filter>
</ClInclude>
......
......@@ -718,9 +718,13 @@
2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; };
2A2825D018341F2D0087FBA9 /* DelayedReleaseScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */; };
2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; };
2A4EC90B1860D6C20094F782 /* WriteBarrierBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A4EC9091860D6C20094F782 /* WriteBarrierBuffer.cpp */; };
2A4EC90C1860D6C20094F782 /* WriteBarrierBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A4EC90A1860D6C20094F782 /* WriteBarrierBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6F462517E959CE00C45C98 /* HeapOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */; };
2AAD964A18569417001F93BE /* RecursiveAllocationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AAD964918569417001F93BE /* RecursiveAllocationScope.h */; };
2ACCF3DE185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */; };
2ACCF3DF185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */; };
2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AD8932917E3868F00668276 /* HeapIterationScope.h */; };
371D842D17C98B6E00ECF994 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 371D842C17C98B6E00ECF994 /* libz.dylib */; };
41359CF30FDD89AD00206180 /* DateConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateConversion.h */; };
......@@ -2021,9 +2025,13 @@
2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringJoiner.cpp; sourceTree = "<group>"; };
2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringJoiner.h; sourceTree = "<group>"; };
2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedReleaseScope.h; sourceTree = "<group>"; };
2A4EC9091860D6C20094F782 /* WriteBarrierBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WriteBarrierBuffer.cpp; sourceTree = "<group>"; };
2A4EC90A1860D6C20094F782 /* WriteBarrierBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierBuffer.h; sourceTree = "<group>"; };
2A6F462517E959CE00C45C98 /* HeapOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapOperation.h; sourceTree = "<group>"; };
2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeferGC.cpp; sourceTree = "<group>"; };
2AAD964918569417001F93BE /* RecursiveAllocationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursiveAllocationScope.h; sourceTree = "<group>"; };
2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStoreBarrierElisionPhase.cpp; path = dfg/DFGStoreBarrierElisionPhase.cpp; sourceTree = "<group>"; };
2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStoreBarrierElisionPhase.h; path = dfg/DFGStoreBarrierElisionPhase.h; sourceTree = "<group>"; };
2AD8932917E3868F00668276 /* HeapIterationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapIterationScope.h; sourceTree = "<group>"; };
371D842C17C98B6E00ECF994 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
449097EE0F8F81B50076A327 /* FeatureDefines.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FeatureDefines.xcconfig; sourceTree = "<group>"; };
......@@ -3111,6 +3119,8 @@
142E312A134FF0A600AFADB5 /* heap */ = {
isa = PBXGroup;
children = (
2A4EC9091860D6C20094F782 /* WriteBarrierBuffer.cpp */,
2A4EC90A1860D6C20094F782 /* WriteBarrierBuffer.h */,
14816E19154CC56C00B8054C /* BlockAllocator.cpp */,
14816E1A154CC56C00B8054C /* BlockAllocator.h */,
0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */,
......@@ -3847,6 +3857,8 @@
86EC9DB31328DF44002B2AD7 /* dfg */ = {
isa = PBXGroup;
children = (
2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */,
2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */,
A77A423617A0BBFD00A8DB81 /* DFGAbstractHeap.cpp */,
A77A423717A0BBFD00A8DB81 /* DFGAbstractHeap.h */,
A704D8FE17A0BAA8006BA554 /* DFGAbstractInterpreter.h */,
......@@ -4361,6 +4373,7 @@
86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
65C0285D1717966800351E35 /* ARMv7DOpcode.h in Headers */,
2A4EC90C1860D6C20094F782 /* WriteBarrierBuffer.h in Headers */,
A532439218569709002ED692 /* CodeGeneratorInspector.py in Headers */,
A532439318569709002ED692 /* CodeGeneratorInspectorStrings.py in Headers */,
A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */,
......@@ -5050,6 +5063,7 @@
14BE7D3317135CF400D1807A /* WeakInlines.h in Headers */,
A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */,
A7CA3AEC17DA5168006538AF /* WeakMapData.h in Headers */,
2ACCF3DF185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h in Headers */,
A55D93AC18514F7900400DED /* InspectorTypeBuilder.h in Headers */,
A7CA3AE617DA41AE006538AF /* WeakMapPrototype.h in Headers */,
1420BE7B10AA6DDB00F455D2 /* WeakRandom.h in Headers */,
......@@ -5705,6 +5719,7 @@
0F24E55517F0B71C00ABB217 /* InlineCallFrameSet.cpp in Sources */,
A78853F917972629001440E4 /* IntendedStructureChain.cpp in Sources */,
147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */,
2ACCF3DE185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp in Sources */,
1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */,
1429D92F0ED22D7000B89619 /* JIT.cpp in Sources */,
86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */,
......@@ -5717,6 +5732,7 @@
0FB14E1E18124ACE009B6B4D /* JITInlineCacheGenerator.cpp in Sources */,
BCDD51EB0FB8DF74004A8BDC /* JITOpcodes.cpp in Sources */,
A71236E51195F33C00BD2174 /* JITOpcodes32_64.cpp in Sources */,
2A4EC90B1860D6C20094F782 /* WriteBarrierBuffer.cpp in Sources */,
0F24E54C17EE274900ABB217 /* JITOperations.cpp in Sources */,
86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */,
A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */,
......
......@@ -68,6 +68,7 @@ namespace JSC { namespace DFG {
macro(Variables) \
macro(TypedArrayProperties) \
macro(GCState) \
macro(BarrierState) \
macro(RegExpState) \
macro(InternalState) \
macro(Absolute) \
......
......@@ -1588,6 +1588,22 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
case CheckTierUpAtReturn:
break;
case ConditionalStoreBarrier: {
if (!needsTypeCheck(node->child2().node(), ~SpecCell))
m_state.setFoundConstants(true);
filter(node->child1(), SpecCell);
break;
}
case StoreBarrier: {
filter(node->child1(), SpecCell);
break;
}
case StoreBarrierWithNullCheck: {
break;
}
case CheckTierUpAndOSREnter:
case LoopHint:
// We pretend that it can exit because it may want to get all state.
......
......@@ -36,6 +36,15 @@
namespace JSC { namespace DFG {
template<typename ReadFunctor, typename WriteFunctor>
void clobberizeForAllocation(ReadFunctor& read, WriteFunctor& write)
{
read(GCState);
read(BarrierState);
write(GCState);
write(BarrierState);
}
template<typename ReadFunctor, typename WriteFunctor>
void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write)
{
......@@ -160,10 +169,9 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
case CreateActivation:
case CreateArguments:
clobberizeForAllocation(read, write);
write(SideState);
write(Watchpoint_fire);
read(GCState);
write(GCState);
return;
case FunctionReentryWatchpoint:
......@@ -173,8 +181,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
case ToThis:
case CreateThis:
read(MiscFields);
read(GCState);
write(GCState);
clobberizeForAllocation(read, write);
return;
case VarInjectionWatchpoint:
......@@ -435,15 +442,13 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
case AllocatePropertyStorage:
write(JSObject_butterfly);
read(GCState);
write(GCState);
clobberizeForAllocation(read, write);
return;
case ReallocatePropertyStorage:
read(JSObject_butterfly);
write(JSObject_butterfly);
read(GCState);
write(GCState);
clobberizeForAllocation(read, write);
return;
case GetButterfly:
......@@ -456,8 +461,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
read(JSObject_butterfly);
write(JSCell_structure);
write(JSObject_butterfly);
read(GCState);
write(GCState);
clobberizeForAllocation(read, write);
return;
case GetIndexedPropertyStorage:
......@@ -544,15 +548,13 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
case NewFunctionNoCheck:
case NewFunction:
case NewFunctionExpression:
read(GCState);
write(GCState);
clobberizeForAllocation(read, write);
return;
case NewTypedArray:
clobberizeForAllocation(read, write);
switch (node->child1().useKind()) {
case Int32Use:
read(GCState);
write(GCState);
return;
case UntypedUse:
read(World);
......@@ -641,8 +643,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
case ThrowReferenceError:
write(SideState);
read(GCState);
write(GCState);
clobberizeForAllocation(read, write);
return;
case CountExecution:
......@@ -650,6 +651,13 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
read(InternalState);
write(InternalState);
return;
case StoreBarrier:
case ConditionalStoreBarrier:
case StoreBarrierWithNullCheck:
read(BarrierState);
write(BarrierState);
return;
case LastNodeType:
RELEASE_ASSERT_NOT_REACHED();
......
......@@ -300,28 +300,34 @@ private:
} else if (!structure->outOfLineCapacity()) {
ASSERT(status.newStructure()->outOfLineCapacity());
ASSERT(!isInlineOffset(status.offset()));
propertyStorage = Edge(m_insertionSet.insertNode(
Node* allocatePropertyStorage = m_insertionSet.insertNode(
indexInBlock, SpecNone, AllocatePropertyStorage,
codeOrigin, OpInfo(transitionData), childEdge));
codeOrigin, OpInfo(transitionData), childEdge);
m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, codeOrigin, Edge(node->child1().node(), KnownCellUse));
propertyStorage = Edge(allocatePropertyStorage);
} else {
ASSERT(structure->outOfLineCapacity());
ASSERT(status.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity());
ASSERT(!isInlineOffset(status.offset()));
propertyStorage = Edge(m_insertionSet.insertNode(
Node* reallocatePropertyStorage = m_insertionSet.insertNode(
indexInBlock, SpecNone, ReallocatePropertyStorage, codeOrigin,
OpInfo(transitionData), childEdge,
Edge(m_insertionSet.insertNode(
indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge))));
indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge)));
m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, codeOrigin, Edge(node->child1().node(), KnownCellUse));
propertyStorage = Edge(reallocatePropertyStorage);
}
if (status.isSimpleTransition()) {
m_insertionSet.insertNode(
indexInBlock, SpecNone, PutStructure, codeOrigin,
OpInfo(transitionData), childEdge);
Node* putStructure = m_graph.addNode(SpecNone, PutStructure, codeOrigin, OpInfo(transitionData), childEdge);
m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, codeOrigin, Edge(node->child1().node(), KnownCellUse));
m_insertionSet.insert(indexInBlock, putStructure);
}
node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
m_insertionSet.insertNode(indexInBlock, SpecNone, ConditionalStoreBarrier, codeOrigin,
Edge(node->child2().node(), KnownCellUse), Edge(node->child3().node(), UntypedUse));
StorageAccessData storageAccessData;
storageAccessData.offset = status.offset();
......@@ -329,7 +335,20 @@ private:
m_graph.m_storageAccessData.append(storageAccessData);
break;
}
case ConditionalStoreBarrier: {
if (!m_interpreter.needsTypeCheck(node->child2().node(), ~SpecCell)) {
node->convertToPhantom();
eliminated = true;
}
break;
}
case StoreBarrier:
case StoreBarrierWithNullCheck: {
break;
}
default:
break;
}
......
......@@ -549,6 +549,14 @@ private:
fixEdge<Int32Use>(child2);
fixEdge<NumberUse>(child3);
break;
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
case Array::Arguments:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
insertStoreBarrier(m_indexInBlock, child1, child3);
break;
default:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
......@@ -582,6 +590,10 @@ private:
case Array::Double:
fixEdge<RealNumberUse>(node->child2());
break;
case Array::Contiguous:
case Array::ArrayStorage:
insertStoreBarrier(m_indexInBlock, node->child1(), node->child2());
break;
default:
break;
}
......@@ -767,18 +779,33 @@ private:
break;
}
case PutStructure: {
fixEdge<KnownCellUse>(node->child1());
insertStoreBarrier(m_indexInBlock, node->child1());
break;
}
case PutClosureVar: {
fixEdge<KnownCellUse>(node->child1());
insertStoreBarrier(m_indexInBlock, node->child1(), node->child3());
break;
}
case GetClosureRegisters:
case PutClosureVar:
case SkipTopScope:
case SkipScope:
case PutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
case GetScope: {
fixEdge<KnownCellUse>(node->child1());
break;
}
case AllocatePropertyStorage:
case ReallocatePropertyStorage: {
fixEdge<KnownCellUse>(node->child1());
insertStoreBarrier(m_indexInBlock + 1, node->child1());
break;
}
case GetById:
case GetByIdFlush: {
if (!node->child1()->shouldSpeculateCell())
......@@ -800,12 +827,17 @@ private:
break;
}
case PutById:
case PutByIdDirect: {
fixEdge<CellUse>(node->child1());
insertStoreBarrier(m_indexInBlock, node->child1(), node->child2());
break;
}
case CheckExecutable:
case CheckStructure:
case StructureTransitionWatchpoint:
case CheckFunction:
case PutById:
case PutByIdDirect:
case CheckHasInstance:
case CreateThis:
case GetButterfly: {
......@@ -832,6 +864,7 @@ private:
if (!node->child1()->hasStorageResult())
fixEdge<KnownCellUse>(node->child1());
fixEdge<KnownCellUse>(node->child2());
insertStoreBarrier(m_indexInBlock, node->child2(), node->child3());
break;
}
......@@ -891,6 +924,24 @@ private:
// fixup rules for them.
RELEASE_ASSERT_NOT_REACHED();
break;
case PutGlobalVar: {
Node* globalObjectNode = m_insertionSet.insertNode(m_indexInBlock, SpecNone, WeakJSConstant, node->codeOrigin,
OpInfo(m_graph.globalObjectFor(node->codeOrigin)));
Node* barrierNode = m_graph.addNode(SpecNone, ConditionalStoreBarrier, m_currentNode->codeOrigin,
Edge(globalObjectNode, KnownCellUse), Edge(node->child1().node(), UntypedUse));
fixupNode(barrierNode);
m_insertionSet.insert(m_indexInBlock, barrierNode);
break;
}
case TearOffActivation: {
Node* barrierNode = m_graph.addNode(SpecNone, StoreBarrierWithNullCheck, m_currentNode->codeOrigin,
Edge(node->child1().node(), UntypedUse));
fixupNode(barrierNode);
m_insertionSet.insert(m_indexInBlock, barrierNode);
break;
}
case IsString:
if (node->child1()->shouldSpeculateString()) {
......@@ -914,7 +965,6 @@ private:
case GetMyScope:
case GetClosureVar:
case GetGlobalVar:
case PutGlobalVar:
case NotifyWrite:
case VariableWatchpoint:
case VarInjectionWatchpoint:
......@@ -931,7 +981,6 @@ private:
case IsObject:
case IsFunction:
case CreateActivation:
case TearOffActivation:
case CreateArguments:
case PhantomArguments:
case TearOffArguments:
......@@ -951,6 +1000,9 @@ private:
case Unreachable:
case ExtractOSREntryLocal:
case LoopHint:
case StoreBarrier:
case ConditionalStoreBarrier:
case StoreBarrierWithNullCheck:
case FunctionReentryWatchpoint:
case TypedArrayWatchpoint:
break;
......@@ -1503,6 +1555,19 @@ private:
edge.setUseKind(useKind);
}
void insertStoreBarrier(unsigned indexInBlock, Edge child1, Edge child2 = Edge())
{
Node* barrierNode;
if (!child2)
barrierNode = m_graph.addNode(SpecNone, StoreBarrier, m_currentNode->codeOrigin, Edge(child1.node(), child1.useKind()));
else {
barrierNode = m_graph.addNode(SpecNone, ConditionalStoreBarrier, m_currentNode->codeOrigin,
Edge(child1.node(), child1.useKind()), Edge(child2.node(), child2.useKind()));
}
fixupNode(barrierNode);
m_insertionSet.insert(indexInBlock, barrierNode);
}
void fixIntEdge(Edge& edge)
{
Node* node = edge.node();
......
......@@ -606,7 +606,19 @@ struct Node {
ASSERT(hasPhi());
return bitwise_cast<Node*>(m_opInfo);
}
bool isStoreBarrier()