Commit 195d7b84 authored by fpizlo@apple.com's avatar fpizlo@apple.com

CodeBlock::jettison() should be implicit

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

Reviewed by Oliver Hunt.
        
This is a risky change from a performance standpoint, but I believe it's
necessary. This makes all CodeBlocks get swept by GC. Nobody but the GC
can delete CodeBlocks because the GC always holds a reference to them.
Once a CodeBlock reaches just one reference (i.e. the one from the GC)
then the GC will free it only if it's not on the stack.
        
This allows me to get rid of the jettisoning logic. We need this for FTL
tier-up. Well; we don't need it, but it will help prevent a lot of bugs.
Previously, if you wanted to to replace one code block with another, you
had to remember to tell the GC that the previous code block is
"jettisoned". We would need to do this when tiering up from DFG to FTL
and when dealing with DFG-to-FTL OSR entry code blocks. There are a lot
of permutations here - tiering up to the FTL, OSR entering into the FTL,
deciding that an OSR entry code block is not relevant anymore - just to
name a few. In each of these cases we'd have to jettison the previous
code block. It smells like a huge source of future bugs.
        
So I made jettisoning implicit by making the GC always watch out for a
CodeBlock being owned solely by the GC.
        
This change is performance neutral.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::visitAggregate):
(JSC::CodeBlock::jettison):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::setJITCode):
(JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan):
(JSC::CodeBlockSet::mark):
* dfg/DFGCommonData.h:
(JSC::DFG::CommonData::CommonData):
* heap/CodeBlockSet.cpp: Added.
(JSC::CodeBlockSet::CodeBlockSet):
(JSC::CodeBlockSet::~CodeBlockSet):
(JSC::CodeBlockSet::add):
(JSC::CodeBlockSet::clearMarks):
(JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced):
(JSC::CodeBlockSet::traceMarked):
* heap/CodeBlockSet.h: Added.
* heap/ConservativeRoots.cpp:
(JSC::ConservativeRoots::add):
* heap/ConservativeRoots.h:
* heap/DFGCodeBlocks.cpp: Removed.
* heap/DFGCodeBlocks.h: Removed.
* heap/Heap.cpp:
(JSC::Heap::markRoots):
(JSC::Heap::deleteAllCompiledCode):
(JSC::Heap::deleteUnmarkedCompiledCode):
* heap/Heap.h:
* interpreter/JSStack.cpp:
(JSC::JSStack::gatherConservativeRoots):
* interpreter/JSStack.h:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode):
* runtime/Executable.h:
* runtime/VM.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154986 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent e698dbbd
......@@ -169,30 +169,10 @@ set(JavaScriptCore_SOURCES
disassembler/X86Disassembler.cpp
heap/BlockAllocator.cpp
heap/CopiedSpace.cpp
heap/CopyVisitor.cpp
heap/ConservativeRoots.cpp
heap/DFGCodeBlocks.cpp
heap/GCIncomingRefCountedSet.h
heap/GCIncomingRefCounted.h
heap/GCIncomingRefCountedSetInlines.h
heap/GCIncomingRefCountedInlines.h
heap/GCThread.cpp
heap/GCThreadSharedData.cpp
heap/HandleSet.cpp
heap/HandleStack.cpp
heap/Heap.cpp
heap/HeapStatistics.cpp
heap/HeapTimer.cpp
heap/IncrementalSweeper.cpp
heap/JITStubRoutineSet.cpp
heap/MachineStackMarker.cpp
heap/BlockAllocator.cpp
heap/CodeBlockSet.cpp
heap/ConservativeRoots.cpp
heap/CopiedSpace.cpp
heap/CopyVisitor.cpp
heap/DFGCodeBlocks.cpp
heap/GCThread.cpp
heap/GCThreadSharedData.cpp
heap/HandleSet.cpp
......@@ -200,6 +180,7 @@ set(JavaScriptCore_SOURCES
heap/Heap.cpp
heap/HeapStatistics.cpp
heap/HeapTimer.cpp
heap/IncrementalSweeper.cpp
heap/JITStubRoutineSet.cpp
heap/MachineStackMarker.cpp
heap/MarkStack.cpp
......
2013-09-02 Filip Pizlo <fpizlo@apple.com>
CodeBlock::jettison() should be implicit
https://bugs.webkit.org/show_bug.cgi?id=120567
Reviewed by Oliver Hunt.
This is a risky change from a performance standpoint, but I believe it's
necessary. This makes all CodeBlocks get swept by GC. Nobody but the GC
can delete CodeBlocks because the GC always holds a reference to them.
Once a CodeBlock reaches just one reference (i.e. the one from the GC)
then the GC will free it only if it's not on the stack.
This allows me to get rid of the jettisoning logic. We need this for FTL
tier-up. Well; we don't need it, but it will help prevent a lot of bugs.
Previously, if you wanted to to replace one code block with another, you
had to remember to tell the GC that the previous code block is
"jettisoned". We would need to do this when tiering up from DFG to FTL
and when dealing with DFG-to-FTL OSR entry code blocks. There are a lot
of permutations here - tiering up to the FTL, OSR entering into the FTL,
deciding that an OSR entry code block is not relevant anymore - just to
name a few. In each of these cases we'd have to jettison the previous
code block. It smells like a huge source of future bugs.
So I made jettisoning implicit by making the GC always watch out for a
CodeBlock being owned solely by the GC.
This change is performance neutral.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::visitAggregate):
(JSC::CodeBlock::jettison):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::setJITCode):
(JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan):
(JSC::CodeBlockSet::mark):
* dfg/DFGCommonData.h:
(JSC::DFG::CommonData::CommonData):
* heap/CodeBlockSet.cpp: Added.
(JSC::CodeBlockSet::CodeBlockSet):
(JSC::CodeBlockSet::~CodeBlockSet):
(JSC::CodeBlockSet::add):
(JSC::CodeBlockSet::clearMarks):
(JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced):
(JSC::CodeBlockSet::traceMarked):
* heap/CodeBlockSet.h: Added.
* heap/ConservativeRoots.cpp:
(JSC::ConservativeRoots::add):
* heap/ConservativeRoots.h:
* heap/DFGCodeBlocks.cpp: Removed.
* heap/DFGCodeBlocks.h: Removed.
* heap/Heap.cpp:
(JSC::Heap::markRoots):
(JSC::Heap::deleteAllCompiledCode):
(JSC::Heap::deleteUnmarkedCompiledCode):
* heap/Heap.h:
* interpreter/JSStack.cpp:
(JSC::JSStack::gatherConservativeRoots):
* interpreter/JSStack.h:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode):
* runtime/Executable.h:
* runtime/VM.h:
2013-09-02 Darin Adler <darin@apple.com>
[Mac] No need for HardAutorelease, which is same as CFBridgingRelease
......
......@@ -442,6 +442,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/ftl/FTLValueFromBlock.h \
Source/JavaScriptCore/ftl/FTLValueSource.cpp \
Source/JavaScriptCore/ftl/FTLValueSource.h \
Source/JavaScriptCore/heap/CodeBlockSet.cpp \
Source/JavaScriptCore/heap/CodeBlockSet.h \
Source/JavaScriptCore/heap/CopiedAllocator.h \
Source/JavaScriptCore/heap/CopiedBlock.h \
Source/JavaScriptCore/heap/CopiedBlockInlines.h \
......@@ -456,8 +458,6 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/ConservativeRoots.cpp \
Source/JavaScriptCore/heap/ConservativeRoots.h \
Source/JavaScriptCore/heap/DeferGC.h \
Source/JavaScriptCore/heap/DFGCodeBlocks.cpp \
Source/JavaScriptCore/heap/DFGCodeBlocks.h \
Source/JavaScriptCore/heap/GCAssertions.h \
Source/JavaScriptCore/heap/GCIncomingRefCounted.h \
Source/JavaScriptCore/heap/GCIncomingRefCountedInlines.h \
......
......@@ -330,10 +330,10 @@
<ClCompile Include="..\dfg\DFGDriver.cpp" />
<ClCompile Include="..\disassembler\Disassembler.cpp" />
<ClCompile Include="..\heap\BlockAllocator.cpp" />
<ClCompile Include="..\heap\CodeBlockSet.cpp" />
<ClCompile Include="..\heap\ConservativeRoots.cpp" />
<ClCompile Include="..\heap\CopiedSpace.cpp" />
<ClCompile Include="..\heap\CopyVisitor.cpp" />
<ClCompile Include="..\heap\DFGCodeBlocks.cpp" />
<ClCompile Include="..\heap\GCThread.cpp" />
<ClCompile Include="..\heap\GCThreadSharedData.cpp" />
<ClCompile Include="..\heap\HandleSet.cpp" />
......@@ -679,6 +679,7 @@
<ClInclude Include="..\dfg\DFGOSREntry.h" />
<ClInclude Include="..\disassembler\Disassembler.h" />
<ClInclude Include="..\heap\BlockAllocator.h" />
<ClInclude Include="..\heap\CodeBlockSet.h" />
<ClInclude Include="..\heap\ConservativeRoots.h" />
<ClInclude Include="..\heap\CopiedAllocator.h" />
<ClInclude Include="..\heap\CopiedBlock.h" />
......@@ -689,7 +690,6 @@
<ClInclude Include="..\heap\CopyVisitor.h" />
<ClInclude Include="..\heap\CopyVisitorInlines.h" />
<ClInclude Include="..\heap\CopyWorkList.h" />
<ClInclude Include="..\heap\DFGCodeBlocks.h" />
<ClInclude Include="..\heap\GCAssertions.h" />
<ClInclude Include="..\heap\GCThread.h" />
<ClInclude Include="..\heap\GCThreadSharedData.h" />
......
......@@ -178,8 +178,6 @@
0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */; };
0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */; };
0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */; };
0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */; };
0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 65987F2F16828A7E003C2F8D /* UnusedPointer.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */; };
......@@ -369,6 +367,8 @@
0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */; };
0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */; };
0FD8A31317D4326C00CA2C40 /* CodeBlockSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */; };
0FD8A31417D4326C00CA2C40 /* CodeBlockSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD8A31217D4326C00CA2C40 /* CodeBlockSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FDB2CC9173DA520007B3C1B /* FTLAbbreviatedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CC7173DA51E007B3C1B /* FTLAbbreviatedTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FDB2CCA173DA523007B3C1B /* FTLValueFromBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CC8173DA51E007B3C1B /* FTLValueFromBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FDB2CE7174830A2007B3C1B /* DFGWorklist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */; };
......@@ -1354,8 +1354,6 @@
0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedNode.cpp; path = dfg/DFGMinifiedNode.cpp; sourceTree = "<group>"; };
0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValueSource.cpp; path = dfg/DFGValueSource.cpp; sourceTree = "<group>"; };
0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = "<group>"; };
0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = "<group>"; };
0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGCodeBlocks.h; sourceTree = "<group>"; };
0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDCEPhase.cpp; path = dfg/DFGDCEPhase.cpp; sourceTree = "<group>"; };
0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDCEPhase.h; path = dfg/DFGDCEPhase.h; sourceTree = "<group>"; };
0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGUseKind.cpp; path = dfg/DFGUseKind.cpp; sourceTree = "<group>"; };
......@@ -1558,6 +1556,8 @@
0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSREntry.cpp; path = dfg/DFGOSREntry.cpp; sourceTree = "<group>"; };
0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSREntry.h; path = dfg/DFGOSREntry.h; sourceTree = "<group>"; };
0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeculatedType.cpp; sourceTree = "<group>"; };
0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeBlockSet.cpp; sourceTree = "<group>"; };
0FD8A31217D4326C00CA2C40 /* CodeBlockSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockSet.h; sourceTree = "<group>"; };
0FDB2CC7173DA51E007B3C1B /* FTLAbbreviatedTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLAbbreviatedTypes.h; path = ftl/FTLAbbreviatedTypes.h; sourceTree = "<group>"; };
0FDB2CC8173DA51E007B3C1B /* FTLValueFromBlock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLValueFromBlock.h; path = ftl/FTLValueFromBlock.h; sourceTree = "<group>"; };
0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGWorklist.cpp; path = dfg/DFGWorklist.cpp; sourceTree = "<group>"; };
......@@ -2715,6 +2715,8 @@
children = (
14816E19154CC56C00B8054C /* BlockAllocator.cpp */,
14816E1A154CC56C00B8054C /* BlockAllocator.h */,
0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */,
0FD8A31217D4326C00CA2C40 /* CodeBlockSet.h */,
146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */,
149DAAF212EB559D0083B12B /* ConservativeRoots.h */,
C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */,
......@@ -2729,8 +2731,6 @@
C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */,
C218D13F1655CFD50062BB81 /* CopyWorkList.h */,
0F136D4B174AD69B0075B354 /* DeferGC.h */,
0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */,
0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */,
BCBE2CAD14E985AA000593AD /* GCAssertions.h */,
0F2B66A817B6B53D00A7AE3F /* GCIncomingRefCounted.h */,
0F2B66A917B6B53D00A7AE3F /* GCIncomingRefCountedInlines.h */,
......@@ -3891,7 +3891,6 @@
0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */,
A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */,
A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */,
0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */,
0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */,
0FEA0A32170D40BF00BB722C /* DFGCommonData.h in Headers */,
0F38B01817CFE75500B144D3 /* DFGCompilationKey.h in Headers */,
......@@ -3964,6 +3963,7 @@
A77A424317A0BBFD00A8DB81 /* DFGSafeToExecute.h in Headers */,
A741017F179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h in Headers */,
86ECA3FA132DF25A002B2AD7 /* DFGScoreBoard.h in Headers */,
0FD8A31417D4326C00CA2C40 /* CodeBlockSet.h in Headers */,
0F766D4615B3701F008F363E /* DFGScratchRegisterAllocator.h in Headers */,
0F1E3A67153A21E2000F9456 /* DFGSilentRegisterSavePlan.h in Headers */,
0FFB921D16D02F300055A5DB /* DFGSlowPathGenerator.h in Headers */,
......@@ -4825,7 +4825,6 @@
0F3B3A271544C995003ED0FF /* DFGCFGSimplificationPhase.cpp in Sources */,
A77A423F17A0BBFD00A8DB81 /* DFGClobberize.cpp in Sources */,
A77A424117A0BBFD00A8DB81 /* DFGClobberSet.cpp in Sources */,
0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */,
0FF0F19D16B72A08005DF95B /* DFGCommon.cpp in Sources */,
0FEA0A31170D40BF00BB722C /* DFGCommonData.cpp in Sources */,
0F38B01717CFE75500B144D3 /* DFGCompilationKey.cpp in Sources */,
......@@ -4987,6 +4986,7 @@
147F39D6107EC37600427A48 /* JSCJSValue.cpp in Sources */,
1440FCE40A51E46B0005F061 /* JSClassRef.cpp in Sources */,
86E3C616167BABEE006D760A /* JSContext.mm in Sources */,
0FD8A31317D4326C00CA2C40 /* CodeBlockSet.cpp in Sources */,
14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */,
A72028B61797601E0098028C /* JSCTestRunnerUtils.cpp in Sources */,
0F2B66EB17B6B5AB00A7AE3F /* JSDataView.cpp in Sources */,
......
......@@ -82,11 +82,11 @@ SOURCES += \
bytecode/Watchpoint.cpp \
bytecompiler/BytecodeGenerator.cpp \
bytecompiler/NodesCodegen.cpp \
heap/CodeBlockSet.cpp \
heap/CopiedSpaceInlines.h \
heap/CopiedSpace.cpp \
heap/CopyVisitor.cpp \
heap/ConservativeRoots.cpp \
heap/DFGCodeBlocks.cpp \
heap/Weak.cpp \
heap/WeakBlock.cpp \
heap/WeakHandleOwner.cpp \
......
......@@ -1504,6 +1504,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
, m_capabilityLevelState(DFG::CapabilityLevelNotSet)
#endif
{
ASSERT(m_heap->isDeferred());
setNumParameters(other.numParameters());
optimizeAfterWarmUp();
jitAfterWarmUp();
......@@ -1516,6 +1517,9 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
m_rareData->m_switchJumpTables = other.m_rareData->m_switchJumpTables;
m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
}
m_heap->m_codeBlocks.add(this);
m_heap->reportExtraMemoryCost(sizeof(CodeBlock));
}
CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset)
......@@ -1544,7 +1548,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
, m_capabilityLevelState(DFG::CapabilityLevelNotSet)
#endif
{
m_vm->startedCompiling(this);
ASSERT(m_heap->isDeferred());
ASSERT(m_source);
setNumParameters(unlinkedCodeBlock->numParameters());
......@@ -1842,7 +1846,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
if (Options::dumpGeneratedBytecodes())
dumpBytecode();
m_vm->finishedCompiling(this);
m_heap->m_codeBlocks.add(this);
m_heap->reportExtraMemoryCost(sizeof(CodeBlock));
}
CodeBlock::~CodeBlock()
......@@ -1850,12 +1855,6 @@ CodeBlock::~CodeBlock()
if (m_vm->m_perBytecodeProfiler)
m_vm->m_perBytecodeProfiler->notifyDestruction(this);
#if ENABLE(DFG_JIT)
// Remove myself from the set of DFG code blocks. Note that I may not be in this set
// (because I'm not a DFG code block), in which case this is a no-op anyway.
m_vm->heap.m_dfgCodeBlocks.m_set.remove(this);
#endif
#if ENABLE(VERBOSE_VALUE_PROFILE)
dumpValueProfiles();
#endif
......@@ -1905,33 +1904,29 @@ void EvalCodeCache::visitAggregate(SlotVisitor& visitor)
void CodeBlock::visitAggregate(SlotVisitor& visitor)
{
#if ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
if (JITCode::isOptimizingJIT(jitType())) {
DFG::CommonData* dfgCommon = m_jitCode->dfgCommon();
// I may be asked to scan myself more than once, and it may even happen concurrently.
// To this end, use a CAS loop to check if I've been called already. Only one thread
// may proceed past this point - whichever one wins the CAS race.
unsigned oldValue;
do {
oldValue = dfgCommon->visitAggregateHasBeenCalled;
if (oldValue) {
// Looks like someone else won! Return immediately to ensure that we don't
// trace the same CodeBlock concurrently. Doing so is hazardous since we will
// be mutating the state of ValueProfiles, which contain JSValues, which can
// have word-tearing on 32-bit, leading to awesome timing-dependent crashes
// that are nearly impossible to track down.
// Also note that it must be safe to return early as soon as we see the
// value true (well, (unsigned)1), since once a GC thread is in this method
// and has won the CAS race (i.e. was responsible for setting the value true)
// it will definitely complete the rest of this method before declaring
// termination.
return;
}
} while (!WTF::weakCompareAndSwap(&dfgCommon->visitAggregateHasBeenCalled, 0, 1));
}
#endif // ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
#if ENABLE(PARALLEL_GC)
// I may be asked to scan myself more than once, and it may even happen concurrently.
// To this end, use a CAS loop to check if I've been called already. Only one thread
// may proceed past this point - whichever one wins the CAS race.
unsigned oldValue;
do {
oldValue = m_visitAggregateHasBeenCalled;
if (oldValue) {
// Looks like someone else won! Return immediately to ensure that we don't
// trace the same CodeBlock concurrently. Doing so is hazardous since we will
// be mutating the state of ValueProfiles, which contain JSValues, which can
// have word-tearing on 32-bit, leading to awesome timing-dependent crashes
// that are nearly impossible to track down.
// Also note that it must be safe to return early as soon as we see the
// value true (well, (unsigned)1), since once a GC thread is in this method
// and has won the CAS race (i.e. was responsible for setting the value true)
// it will definitely complete the rest of this method before declaring
// termination.
return;
}
} while (!WTF::weakCompareAndSwap(&m_visitAggregateHasBeenCalled, 0, 1));
#endif // ENABLE(PARALLEL_GC)
if (!!m_alternative)
m_alternative->visitAggregate(visitor);
......@@ -2740,28 +2735,14 @@ DFG::CapabilityLevel FunctionCodeBlock::capabilityLevelInternal()
void CodeBlock::jettison()
{
DeferGC deferGC(*m_heap);
ASSERT(JITCode::isOptimizingJIT(jitType()));
ASSERT(this == replacement());
alternative()->optimizeAfterWarmUp();
tallyFrequentExitSites();
if (DFG::shouldShowDisassembly())
dataLog("Jettisoning ", *this, ".\n");
jettisonImpl();
}
void ProgramCodeBlock::jettisonImpl()
{
static_cast<ProgramExecutable*>(ownerExecutable())->jettisonOptimizedCode(*vm());
}
void EvalCodeBlock::jettisonImpl()
{
static_cast<EvalExecutable*>(ownerExecutable())->jettisonOptimizedCode(*vm());
}
void FunctionCodeBlock::jettisonImpl()
{
static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*vm(), m_isConstructor ? CodeForConstruct : CodeForCall);
alternative()->install();
}
#endif
......
......@@ -36,11 +36,11 @@
#include "CallLinkInfo.h"
#include "CallReturnOffsetToBytecodeOffset.h"
#include "CodeBlockHash.h"
#include "CodeBlockSet.h"
#include "ConcurrentJITLock.h"
#include "CodeOrigin.h"
#include "CodeType.h"
#include "CompactJITCodeMap.h"
#include "DFGCodeBlocks.h"
#include "DFGCommon.h"
#include "DFGCommonData.h"
#include "DFGExitProfile.h"
......@@ -83,7 +83,6 @@
namespace JSC {
class DFGCodeBlocks;
class ExecState;
class LLIntOffsetsExtractor;
class RepatchBuffer;
......@@ -273,14 +272,12 @@ public:
void setJITCode(PassRefPtr<JITCode> code, MacroAssemblerCodePtr codeWithArityCheck)
{
ASSERT(m_heap->isDeferred());
m_heap->reportExtraMemoryCost(code->size());
ConcurrentJITLocker locker(m_lock);
WTF::storeStoreFence(); // This is probably not needed because the lock will also do something similar, but it's good to be paranoid.
m_jitCode = code;
m_jitCodeWithArityCheck = codeWithArityCheck;
#if ENABLE(DFG_JIT)
if (JITCode::isOptimizingJIT(JITCode::jitTypeFor(m_jitCode)))
m_vm->heap.m_dfgCodeBlocks.m_set.add(this);
#endif
}
PassRefPtr<JITCode> jitCode() { return m_jitCode; }
MacroAssemblerCodePtr jitCodeWithArityCheck() { return m_jitCodeWithArityCheck; }
......@@ -961,9 +958,6 @@ public:
bool m_allTransitionsHaveBeenMarked; // Initialized and used on every GC.
protected:
#if ENABLE(JIT)
virtual void jettisonImpl() = 0;
#endif
virtual void visitWeakReferences(SlotVisitor&);
virtual void finalizeUnconditionally();
......@@ -974,7 +968,7 @@ protected:
#endif
private:
friend class DFGCodeBlocks;
friend class CodeBlockSet;
void noticeIncomingCall(ExecState* callerFrame);
......@@ -1017,17 +1011,16 @@ private:
#if ENABLE(DFG_JIT)
bool shouldImmediatelyAssumeLivenessDuringScan()
{
// Null m_dfgData means that this is a baseline JIT CodeBlock. Baseline JIT
// CodeBlocks don't need to be jettisoned when their weak references go
// stale. So if a basline JIT CodeBlock gets scanned, we can assume that
// this means that it's live.
// Interpreter and Baseline JIT CodeBlocks don't need to be jettisoned when
// their weak references go stale. So if a basline JIT CodeBlock gets
// scanned, we can assume that this means that it's live.
if (!JITCode::isOptimizingJIT(jitType()))
return true;
// For simplicity, we don't attempt to jettison code blocks during GC if
// they are executing. Instead we strongly mark their weak references to
// allow them to continue to execute soundly.
if (m_jitCode->dfgCommon()->mayBeExecuting)
if (m_mayBeExecuting)
return true;
if (Options::forceDFGCodeBlockLiveness())
......@@ -1067,6 +1060,8 @@ private:
bool m_isStrictMode;
bool m_needsActivation;
bool m_mayBeExecuting;
uint8_t m_visitAggregateHasBeenCalled;
RefPtr<SourceProvider> m_source;
unsigned m_sourceOffset;
......@@ -1186,7 +1181,6 @@ public:
#if ENABLE(JIT)
protected:
virtual void jettisonImpl();
virtual CodeBlock* replacement();
virtual DFG::CapabilityLevel capabilityLevelInternal();
#endif
......@@ -1209,7 +1203,6 @@ public:
#if ENABLE(JIT)
protected:
virtual void jettisonImpl();
virtual CodeBlock* replacement();
virtual DFG::CapabilityLevel capabilityLevelInternal();
#endif
......@@ -1232,7 +1225,6 @@ public:
#if ENABLE(JIT)
protected:
virtual void jettisonImpl();
virtual CodeBlock* replacement();
virtual DFG::CapabilityLevel capabilityLevelInternal();
#endif
......@@ -1291,8 +1283,7 @@ inline JSValue ExecState::argumentAfterCapture(size_t argument)
return this[codeBlock()->argumentIndexAfterCapture(argument)].jsValue();
}
#if ENABLE(DFG_JIT)
inline void DFGCodeBlocks::mark(void* candidateCodeBlock)
inline void CodeBlockSet::mark(void* candidateCodeBlock)
{
// We have to check for 0 and -1 because those are used by the HashMap as markers.
uintptr_t value = reinterpret_cast<uintptr_t>(candidateCodeBlock);
......@@ -1307,9 +1298,8 @@ inline void DFGCodeBlocks::mark(void* candidateCodeBlock)
if (iter == m_set.end())
return;
(*iter)->m_jitCode->dfgCommon()->mayBeExecuting = true;
(*iter)->m_mayBeExecuting = true;
}
#endif
} // namespace JSC
......
......@@ -66,11 +66,7 @@ struct WeakReferenceTransition {
class CommonData {
WTF_MAKE_NONCOPYABLE(CommonData);
public:
CommonData()
: mayBeExecuting(false)
, isJettisoned(false)
{
}
CommonData() { }
void notifyCompilingStructureTransition(Plan&, CodeBlock*, Node*);
......@@ -81,11 +77,8 @@ public:
Vector<WriteBarrier<JSCell> > weakReferences;
RefPtr<Profiler::Compilation> compilation;
bool mayBeExecuting;
bool isJettisoned;
bool livenessHasBeenProved; // Initialized and used on every GC.
bool allTransitionsHaveBeenMarked; // Initialized and used on every GC.
unsigned visitAggregateHasBeenCalled; // Unsigned to make it work seamlessly with the broadest set of CAS implementations.
};
} } // namespace JSC::DFG
......
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -24,79 +24,86 @@
*/
#include "config.h"
#include "DFGCodeBlocks.h"
#include "CodeBlockSet.h"
#include "CodeBlock.h"
#include "SlotVisitor.h"
#include <wtf/Vector.h>
namespace JSC {
#if ENABLE(DFG_JIT)
static const bool verbose = false;
DFGCodeBlocks::DFGCodeBlocks() { }
CodeBlockSet::CodeBlockSet() { }
DFGCodeBlocks::~DFGCodeBlocks()
CodeBlockSet::~CodeBlockSet()
{
Vector<RefPtr<CodeBlock>, 16> toRemove;
for (HashSet<CodeBlock*>::iterator iter = m_set.begin(); iter != m_set.end(); ++iter) {
if ((*iter)->jitCode()->dfgCommon()->isJettisoned)
toRemove.append(adoptRef(*iter));
}
HashSet<CodeBlock*>::iterator iter = m_set.begin();
HashSet<CodeBlock*>::iterator end = m_set.end();
for (; iter != end; ++iter)
(*iter)->deref();
}
void DFGCodeBlocks::jettison(PassRefPtr<CodeBlock> codeBlockPtr)
void CodeBlockSet::add(PassRefPtr<CodeBlock> codeBlock)
{
// We don't want to delete it now; we just want its pointer.
CodeBlock* codeBlock = codeBlockPtr.leakRef();
ASSERT(codeBlock);
ASSERT(JITCode::isOptimizingJIT(codeBlock->jitType()));
// It should not have already been jettisoned.
ASSERT(!codeBlock->jitCode()->dfgCommon()->isJettisoned);
// We should have this block already.
ASSERT(m_set.find(codeBlock) != m_set.end());
codeBlock->jitCode()->dfgCommon()->isJettisoned = true;
bool isNewEntry = m_set.add(codeBlock.leakRef()).isNewEntry;
ASSERT_UNUSED(isNewEntry, isNewEntry);
}
void DFGCodeBlocks::clearMarks()
void CodeBlockSet::clearMarks()
{
for (HashSet<CodeBlock*>::iterator iter = m_set.begin(); iter != m_set.end(); ++iter) {
(*iter)->jitCode()->dfgCommon()->mayBeExecuting = false;
(*iter)->jitCode()->dfgCommon()->visitAggregateHasBeenCalled = false;
HashSet<CodeBlock*>::iterator iter = m_set.begin();
HashSet<CodeBlock*>::iterator end = m_set.end();
for (; iter != end; ++iter) {
CodeBlock* codeBlock = *iter;
codeBlock->m_mayBeExecuting = false;
codeBlock->m_visitAggregateHasBeenCalled = false;
}
}
void DFGCodeBlocks::deleteUnmarkedJettisonedCodeBlocks()
void CodeBlockSet::deleteUnmarkedAndUnreferenced()
{
Vector<RefPtr<CodeBlock>, 16> toRemove;
for (HashSet<CodeBlock*>::iterator iter = m_set.begin(); iter != m_set.end(); ++iter) {
if ((*iter)->jitCode()->dfgCommon()->isJettisoned && !(*iter)->jitCode()->dfgCommon()->mayBeExecuting)
toRemove.append(adoptRef(*iter));
// This needs to be a fixpoint because code blocks that are unmarked may
// refer to each other. For example, a DFG code block that is owned by
// the GC may refer to an FTL for-entry code block that is also owned by
// the GC.
Vector<CodeBlock*, 16> toRemove;
if (verbose)