Commit 706f5f34 authored by fpizlo@apple.com's avatar fpizlo@apple.com

DFG should support continuous optimization

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

Reviewed by Geoffrey Garen.
        
This adds the ability to reoptimize a code block if speculation
failures happen frequently. 6% speed-up on Kraken, 1% slow-down
on V8, neutral on SunSpider.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.pro:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcproj/WTF/WTF.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::ProgramCodeBlock::jettison):
(JSC::EvalCodeBlock::jettison):
(JSC::FunctionCodeBlock::jettison):
(JSC::CodeBlock::shouldOptimizeNow):
(JSC::CodeBlock::dumpValueProfiles):
* bytecode/CodeBlock.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getStrongPrediction):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::exitSpeculativeWithOSR):
(JSC::DFG::JITCompiler::compileEntry):
(JSC::DFG::JITCompiler::compileBody):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::noticeOSREntry):
* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* dfg/DFGOSREntry.h:
(JSC::DFG::getOSREntryDataBytecodeIndex):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* heap/ConservativeRoots.cpp:
(JSC::ConservativeRoots::ConservativeRoots):
(JSC::ConservativeRoots::~ConservativeRoots):
(JSC::DummyMarkHook::mark):
(JSC::ConservativeRoots::genericAddPointer):
(JSC::ConservativeRoots::genericAddSpan):
(JSC::ConservativeRoots::add):
* heap/ConservativeRoots.h:
* heap/Heap.cpp:
(JSC::Heap::addJettisonCodeBlock):
(JSC::Heap::markRoots):
* heap/Heap.h:
* heap/JettisonedCodeBlocks.cpp: Added.
(JSC::JettisonedCodeBlocks::JettisonedCodeBlocks):
(JSC::JettisonedCodeBlocks::~JettisonedCodeBlocks):
(JSC::JettisonedCodeBlocks::addCodeBlock):
(JSC::JettisonedCodeBlocks::clearMarks):
(JSC::JettisonedCodeBlocks::deleteUnmarkedCodeBlocks):
(JSC::JettisonedCodeBlocks::traceCodeBlocks):
* heap/JettisonedCodeBlocks.h: Added.
(JSC::JettisonedCodeBlocks::mark):
* interpreter/RegisterFile.cpp:
(JSC::RegisterFile::gatherConservativeRoots):
* interpreter/RegisterFile.h:
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.cpp:
(JSC::jettisonCodeBlock):
(JSC::EvalExecutable::jettisonOptimizedCode):
(JSC::ProgramExecutable::jettisonOptimizedCode):
(JSC::FunctionExecutable::jettisonOptimizedCodeForCall):
(JSC::FunctionExecutable::jettisonOptimizedCodeForConstruct):
* runtime/Executable.h:
(JSC::FunctionExecutable::jettisonOptimizedCodeFor):
* wtf/BitVector.h: Added.
(WTF::BitVector::BitVector):
(WTF::BitVector::~BitVector):
(WTF::BitVector::operator=):
(WTF::BitVector::size):
(WTF::BitVector::ensureSize):
(WTF::BitVector::resize):
(WTF::BitVector::clearAll):
(WTF::BitVector::get):
(WTF::BitVector::set):
(WTF::BitVector::clear):
(WTF::BitVector::bitsInPointer):
(WTF::BitVector::maxInlineBits):
(WTF::BitVector::byteCount):
(WTF::BitVector::makeInlineBits):
(WTF::BitVector::OutOfLineBits::numBits):
(WTF::BitVector::OutOfLineBits::numWords):
(WTF::BitVector::OutOfLineBits::bits):
(WTF::BitVector::OutOfLineBits::create):
(WTF::BitVector::OutOfLineBits::destroy):
(WTF::BitVector::OutOfLineBits::OutOfLineBits):
(WTF::BitVector::isInline):
(WTF::BitVector::outOfLineBits):
(WTF::BitVector::resizeOutOfLine):
(WTF::BitVector::bits):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95681 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 8f02f079
......@@ -49,6 +49,7 @@ SET(JavaScriptCore_SOURCES
heap/Heap.cpp
heap/HandleHeap.cpp
heap/HandleStack.cpp
heap/JettisonedCodeBlocks.cpp
heap/MachineStackMarker.cpp
heap/MarkedBlock.cpp
heap/MarkedSpace.cpp
......
2011-09-21 Filip Pizlo <fpizlo@apple.com>
DFG should support continuous optimization
https://bugs.webkit.org/show_bug.cgi?id=68329
Reviewed by Geoffrey Garen.
This adds the ability to reoptimize a code block if speculation
failures happen frequently. 6% speed-up on Kraken, 1% slow-down
on V8, neutral on SunSpider.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.pro:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcproj/WTF/WTF.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::ProgramCodeBlock::jettison):
(JSC::EvalCodeBlock::jettison):
(JSC::FunctionCodeBlock::jettison):
(JSC::CodeBlock::shouldOptimizeNow):
(JSC::CodeBlock::dumpValueProfiles):
* bytecode/CodeBlock.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getStrongPrediction):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::exitSpeculativeWithOSR):
(JSC::DFG::JITCompiler::compileEntry):
(JSC::DFG::JITCompiler::compileBody):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::noticeOSREntry):
* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* dfg/DFGOSREntry.h:
(JSC::DFG::getOSREntryDataBytecodeIndex):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* heap/ConservativeRoots.cpp:
(JSC::ConservativeRoots::ConservativeRoots):
(JSC::ConservativeRoots::~ConservativeRoots):
(JSC::DummyMarkHook::mark):
(JSC::ConservativeRoots::genericAddPointer):
(JSC::ConservativeRoots::genericAddSpan):
(JSC::ConservativeRoots::add):
* heap/ConservativeRoots.h:
* heap/Heap.cpp:
(JSC::Heap::addJettisonCodeBlock):
(JSC::Heap::markRoots):
* heap/Heap.h:
* heap/JettisonedCodeBlocks.cpp: Added.
(JSC::JettisonedCodeBlocks::JettisonedCodeBlocks):
(JSC::JettisonedCodeBlocks::~JettisonedCodeBlocks):
(JSC::JettisonedCodeBlocks::addCodeBlock):
(JSC::JettisonedCodeBlocks::clearMarks):
(JSC::JettisonedCodeBlocks::deleteUnmarkedCodeBlocks):
(JSC::JettisonedCodeBlocks::traceCodeBlocks):
* heap/JettisonedCodeBlocks.h: Added.
(JSC::JettisonedCodeBlocks::mark):
* interpreter/RegisterFile.cpp:
(JSC::RegisterFile::gatherConservativeRoots):
* interpreter/RegisterFile.h:
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.cpp:
(JSC::jettisonCodeBlock):
(JSC::EvalExecutable::jettisonOptimizedCode):
(JSC::ProgramExecutable::jettisonOptimizedCode):
(JSC::FunctionExecutable::jettisonOptimizedCodeForCall):
(JSC::FunctionExecutable::jettisonOptimizedCodeForConstruct):
* runtime/Executable.h:
(JSC::FunctionExecutable::jettisonOptimizedCodeFor):
* wtf/BitVector.h: Added.
(WTF::BitVector::BitVector):
(WTF::BitVector::~BitVector):
(WTF::BitVector::operator=):
(WTF::BitVector::size):
(WTF::BitVector::ensureSize):
(WTF::BitVector::resize):
(WTF::BitVector::clearAll):
(WTF::BitVector::get):
(WTF::BitVector::set):
(WTF::BitVector::clear):
(WTF::BitVector::bitsInPointer):
(WTF::BitVector::maxInlineBits):
(WTF::BitVector::byteCount):
(WTF::BitVector::makeInlineBits):
(WTF::BitVector::OutOfLineBits::numBits):
(WTF::BitVector::OutOfLineBits::numWords):
(WTF::BitVector::OutOfLineBits::bits):
(WTF::BitVector::OutOfLineBits::create):
(WTF::BitVector::OutOfLineBits::destroy):
(WTF::BitVector::OutOfLineBits::OutOfLineBits):
(WTF::BitVector::isInline):
(WTF::BitVector::outOfLineBits):
(WTF::BitVector::resizeOutOfLine):
(WTF::BitVector::bits):
2011-09-21 Gavin Barraclough <barraclough@apple.com>
Should support value profiling on CPU(X86)
......@@ -140,6 +140,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/Handle.h \
Source/JavaScriptCore/heap/HandleHeap.cpp \
Source/JavaScriptCore/heap/HandleHeap.h \
Source/JavaScriptCore/heap/JettisonedCodeBlocks.cpp \
Source/JavaScriptCore/heap/JettisonedCodeBlocks.h \
Source/JavaScriptCore/heap/SlotVisitor.h \
Source/JavaScriptCore/heap/HandleStack.cpp \
Source/JavaScriptCore/heap/HandleStack.h \
......@@ -464,6 +466,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/wtf/Assertions.h \
Source/JavaScriptCore/wtf/Atomics.h \
Source/JavaScriptCore/wtf/AVLTree.h \
Source/JavaScriptCore/wtf/BitVector.h \
Source/JavaScriptCore/wtf/Bitmap.h \
Source/JavaScriptCore/wtf/BlockStack.h \
Source/JavaScriptCore/wtf/BloomFilter.h \
......
......@@ -77,6 +77,7 @@ SOURCES += \
heap/HandleHeap.cpp \
heap/HandleStack.cpp \
heap/Heap.cpp \
heap/JettisonedCodeBlocks.cpp \
heap/MachineStackMarker.cpp \
heap/MarkStack.cpp \
heap/MarkedBlock.cpp \
......
......@@ -1973,6 +1973,14 @@
RelativePath="..\..\heap\HandleStack.h"
>
</File>
<File
RelativePath="..\..\heap\JettisonedCodeBlocks.cpp"
>
</File>
<File
RelativePath="..\..\heap\JettisonedCodeBlocks.h"
>
</File>
<File
RelativePath="..\..\heap\Local.h"
>
......
......@@ -636,6 +636,10 @@
RelativePath="..\..\wtf\AVLTree.h"
>
</File>
<File
RelativePath="..\..\wtf\BitVector.h"
>
</File>
<File
RelativePath="..\..\wtf\Bitmap.h"
>
......
......@@ -74,6 +74,9 @@
0FD82E86141F3FF100179C94 /* PredictedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* PredictedType.cpp */; };
0FD82E9014207A5F00179C94 /* ValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E8E14207A5100179C94 /* ValueProfile.cpp */; };
0FD82EF51423075B00179C94 /* DFGIntrinsic.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82EF31423073900179C94 /* DFGIntrinsic.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FD82F2B1426CA6D00179C94 /* JettisonedCodeBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82F291426CA5A00179C94 /* JettisonedCodeBlocks.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FD82F2C1426CA7400179C94 /* JettisonedCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82F281426CA5A00179C94 /* JettisonedCodeBlocks.cpp */; };
0FD82F4B142806A100179C94 /* BitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82F491428069200179C94 /* BitVector.h */; settings = {ATTRIBUTES = (Private, ); }; };
1400067712A6F7830064D123 /* OSAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400067612A6F7830064D123 /* OSAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
1400069312A6F9E10064D123 /* OSAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */; };
140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; };
......@@ -813,6 +816,9 @@
0FD82E84141F3FDA00179C94 /* PredictedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PredictedType.cpp; sourceTree = "<group>"; };
0FD82E8E14207A5100179C94 /* ValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ValueProfile.cpp; sourceTree = "<group>"; };
0FD82EF31423073900179C94 /* DFGIntrinsic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGIntrinsic.h; path = dfg/DFGIntrinsic.h; sourceTree = "<group>"; };
0FD82F281426CA5A00179C94 /* JettisonedCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JettisonedCodeBlocks.cpp; sourceTree = "<group>"; };
0FD82F291426CA5A00179C94 /* JettisonedCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JettisonedCodeBlocks.h; sourceTree = "<group>"; };
0FD82F491428069200179C94 /* BitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitVector.h; sourceTree = "<group>"; };
1400067612A6F7830064D123 /* OSAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSAllocator.h; sourceTree = "<group>"; };
1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAllocatorPosix.cpp; sourceTree = "<group>"; };
140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBasePrivate.h; sourceTree = "<group>"; };
......@@ -1621,6 +1627,8 @@
142E312A134FF0A600AFADB5 /* heap */ = {
isa = PBXGroup;
children = (
0FD82F281426CA5A00179C94 /* JettisonedCodeBlocks.cpp */,
0FD82F291426CA5A00179C94 /* JettisonedCodeBlocks.h */,
A70456AF1427FB150037DA68 /* AllocationSpace.h */,
A70456AE1427FB030037DA68 /* AllocationSpace.cpp */,
0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */,
......@@ -1797,6 +1805,7 @@
65162EF108E6A21C007556CD /* wtf */ = {
isa = PBXGroup;
children = (
0FD82F491428069200179C94 /* BitVector.h */,
C22C524813FAF6EF00B7DC0D /* dtoa */,
06D358A00DAAD9C4003B174E /* mac */,
8656573E115BE35200291F40 /* text */,
......@@ -2423,6 +2432,8 @@
BC257DE80E1F51C50016B6C9 /* Arguments.h in Headers */,
86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
0FD82F4B142806A100179C94 /* BitVector.h in Headers */,
0FD82F2B1426CA6D00179C94 /* JettisonedCodeBlocks.h in Headers */,
0FD82EF51423075B00179C94 /* DFGIntrinsic.h in Headers */,
0FD82E85141F3FE300179C94 /* BoundsCheckedPointer.h in Headers */,
0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */,
......@@ -3113,6 +3124,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0FD82F2C1426CA7400179C94 /* JettisonedCodeBlocks.cpp in Sources */,
0FD82E9014207A5F00179C94 /* ValueProfile.cpp in Sources */,
0FD82E86141F3FF100179C94 /* PredictedType.cpp in Sources */,
0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */,
......
......@@ -1428,7 +1428,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo
, m_sourceOffset(sourceOffset)
, m_symbolTable(symTab)
, m_alternative(alternative)
, m_speculativeSuccessCounter(0)
, m_speculativeFailCounter(0)
, m_optimizationDelayCounter(0)
, m_reoptimizationRetryCounter(0)
{
ASSERT(m_source);
......@@ -1935,6 +1938,27 @@ bool FunctionCodeBlock::canCompileWithDFG()
return DFG::canCompileFunctionForConstruct(this);
return DFG::canCompileFunctionForCall(this);
}
void ProgramCodeBlock::jettison(JSGlobalData& globalData)
{
ASSERT(getJITType() != JITCode::BaselineJIT);
ASSERT(this == replacement());
static_cast<ProgramExecutable*>(ownerExecutable())->jettisonOptimizedCode(globalData);
}
void EvalCodeBlock::jettison(JSGlobalData& globalData)
{
ASSERT(getJITType() != JITCode::BaselineJIT);
ASSERT(this == replacement());
static_cast<EvalExecutable*>(ownerExecutable())->jettisonOptimizedCode(globalData);
}
void FunctionCodeBlock::jettison(JSGlobalData& globalData)
{
ASSERT(getJITType() != JITCode::BaselineJIT);
ASSERT(this == replacement());
static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(globalData, m_isConstructor ? CodeForConstruct : CodeForCall);
}
#endif
#if ENABLE(VALUE_PROFILER)
......@@ -1974,8 +1998,8 @@ bool CodeBlock::shouldOptimizeNow()
printf("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfNonArgumentValueProfiles, (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
#endif
if ((double)numberOfLiveNonArgumentValueProfiles / numberOfNonArgumentValueProfiles >= 0.75
&& (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles() >= 0.5)
if ((!numberOfNonArgumentValueProfiles || (double)numberOfLiveNonArgumentValueProfiles / numberOfNonArgumentValueProfiles >= 0.75)
&& (!numberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles() >= 0.5))
return true;
m_optimizationDelayCounter++;
......@@ -2017,6 +2041,11 @@ void CodeBlock::dumpValueProfiles()
RareCaseProfile* profile = rareCaseProfile(i);
fprintf(stderr, " bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
}
fprintf(stderr, "SpecialFastCaseProfile for %p:\n", this);
for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) {
RareCaseProfile* profile = specialFastCaseProfile(i);
fprintf(stderr, " bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
}
}
#endif
......
......@@ -31,6 +31,7 @@
#define CodeBlock_h
#include "CompactJITCodeMap.h"
#include "DFGOSREntry.h"
#include "EvalCodeCache.h"
#include "Instruction.h"
#include "JITCode.h"
......@@ -333,6 +334,21 @@ namespace JSC {
{
return m_jitCodeMap.get();
}
DFG::OSREntryData* appendDFGOSREntryData(unsigned bytecodeIndex, unsigned machineCodeOffset)
{
DFG::OSREntryData entry;
entry.m_bytecodeIndex = bytecodeIndex;
entry.m_machineCodeOffset = machineCodeOffset;
m_dfgOSREntry.append(entry);
return &m_dfgOSREntry.last();
}
unsigned numberOfDFGOSREntries() const { return m_dfgOSREntry.size(); }
DFG::OSREntryData* dfgOSREntryData(unsigned i) { return &m_dfgOSREntry[i]; }
DFG::OSREntryData* dfgOSREntryDataForBytecodeIndex(unsigned bytecodeIndex)
{
return binarySearch<DFG::OSREntryData, unsigned, DFG::getOSREntryDataBytecodeIndex>(m_dfgOSREntry.begin(), m_dfgOSREntry.size(), bytecodeIndex);
}
#endif
#if ENABLE(INTERPRETER)
......@@ -360,9 +376,11 @@ namespace JSC {
m_jitCodeWithArityCheck = codeWithArityCheck;
}
JITCode& getJITCode() { return m_jitCode; }
MacroAssemblerCodePtr getJITCodeWithArityCheck() { return m_jitCodeWithArityCheck; }
JITCode::JITType getJITType() { return m_jitCode.jitType(); }
ExecutableMemoryHandle* executableMemory() { return getJITCode().getExecutableMemory(); }
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0;
virtual void jettison(JSGlobalData&) = 0;
virtual CodeBlock* replacement() = 0;
virtual bool canCompileWithDFG() = 0;
bool hasOptimizedReplacement()
......@@ -685,11 +703,37 @@ namespace JSC {
// trigger files. All CodeBlocks start out with optimizeAfterWarmUp(),
// as this is called from the CodeBlock constructor.
// When we observe a lot of speculation failures, we trigger a
// reoptimization. But each time, we increase the optimization trigger
// to avoid thrashing.
unsigned reoptimizationRetryCounter() const
{
ASSERT(m_reoptimizationRetryCounter <= 18);
return m_reoptimizationRetryCounter;
}
void countReoptimization()
{
m_reoptimizationRetryCounter++;
if (m_reoptimizationRetryCounter > 18)
m_reoptimizationRetryCounter = 18;
}
// These functions are provided to support calling
// optimizeAfterWarmUp() from JIT-generated code.
// optimizeXYZ() methods from JIT-generated code.
static int32_t counterValueForOptimizeNextInvocation()
{
return 0;
}
int32_t counterValueForOptimizeAfterWarmUp()
{
return -1000;
return -1000 << reoptimizationRetryCounter();
}
int32_t counterValueForOptimizeAfterLongWarmUp()
{
return -5000 << reoptimizationRetryCounter();
}
int32_t* addressOfExecuteCounter()
......@@ -697,12 +741,18 @@ namespace JSC {
return &m_executeCounter;
}
static ptrdiff_t offsetOfExecuteCounter() { return OBJECT_OFFSETOF(CodeBlock, m_executeCounter); }
int32_t executeCounter() const { return m_executeCounter; }
unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; }
// Call this to force the next optimization trigger to fire. This is
// rarely wise, since optimization triggers are typically more
// expensive than executing baseline code.
void optimizeNextInvocation()
{
m_executeCounter = 0;
m_executeCounter = counterValueForOptimizeNextInvocation();
}
// Call this to prevent optimization from happening again. Note that
......@@ -726,6 +776,13 @@ namespace JSC {
m_executeCounter = counterValueForOptimizeAfterWarmUp();
}
// Call this to force an optimization trigger to fire only after
// a lot of warm-up.
void optimizeAfterLongWarmUp()
{
m_executeCounter = counterValueForOptimizeAfterLongWarmUp();
}
// Call this to cause an optimization trigger to fire soon, but
// not necessarily the next one. This makes sense if optimization
// succeeds. Successfuly optimization means that all calls are
......@@ -746,18 +803,72 @@ namespace JSC {
// in the baseline code.
void optimizeSoon()
{
m_executeCounter = -100;
m_executeCounter = -100 << reoptimizationRetryCounter();
}
// The speculative JIT tracks its success rate, so that we can
// decide when to reoptimize. It's interesting to note that these
// counters may overflow without any protection. The success
// counter will overflow before the fail one does, becuase the
// fail one is used as a trigger to reoptimize. So the worst case
// is that the success counter overflows and we reoptimize without
// needing to. But this is harmless. If a method really did
// execute 2^32 times then compiling it again probably won't hurt
// anyone.
void countSpeculationSuccess()
{
m_speculativeSuccessCounter++;
}
void countSpeculationFailure()
{
m_speculativeFailCounter++;
}
uint32_t speculativeSuccessCounter() const { return m_speculativeSuccessCounter; }
uint32_t speculativeFailCounter() const { return m_speculativeFailCounter; }
uint32_t* addressOfSpeculativeSuccessCounter() { return &m_speculativeSuccessCounter; }
uint32_t* addressOfSpeculativeFailCounter() { return &m_speculativeFailCounter; }
static ptrdiff_t offsetOfSpeculativeSuccessCounter() { return OBJECT_OFFSETOF(CodeBlock, m_speculativeSuccessCounter); }
static ptrdiff_t offsetOfSpeculativeFailCounter() { return OBJECT_OFFSETOF(CodeBlock, m_speculativeFailCounter); }
// The amount by which the JIT will increment m_executeCounter.
static unsigned executeCounterIncrementForLoop() { return 1; }
static unsigned executeCounterIncrementForReturn() { return 15; }
// The success/failure ratio we want.
unsigned desiredSuccessFailRatio() { return 6; }
// The number of failures that triggers the use of the ratio.
unsigned largeFailCountThreshold() { return 20 << alternative()->reoptimizationRetryCounter(); }
unsigned largeFailCountThresholdForLoop() { return 1 << alternative()->reoptimizationRetryCounter(); }
bool shouldReoptimizeNow()
{
return desiredSuccessFailRatio() * speculativeFailCounter() >= speculativeSuccessCounter() && speculativeFailCounter() >= largeFailCountThreshold();
}
bool shouldReoptimizeFromLoopNow()
{
return desiredSuccessFailRatio() * speculativeFailCounter() >= speculativeSuccessCounter() && speculativeFailCounter() >= largeFailCountThresholdForLoop();
}
#if ENABLE(VALUE_PROFILER)
bool shouldOptimizeNow();
#else
bool shouldOptimizeNow() { return false; }
#endif
void reoptimize(JSGlobalData& globalData)
{
ASSERT(replacement() != this);
replacement()->jettison(globalData);
countReoptimization();
optimizeAfterWarmUp();
}
#if ENABLE(VERBOSE_VALUE_PROFILE)
void dumpValueProfiles();
......@@ -827,6 +938,7 @@ namespace JSC {
#endif
#if ENABLE(DFG_JIT)
OwnPtr<CompactJITCodeMap> m_jitCodeMap;
Vector<DFG::OSREntryData> m_dfgOSREntry;
#endif
#if ENABLE(VALUE_PROFILER)
SegmentedVector<ValueProfile, 8> m_valueProfiles;
......@@ -851,7 +963,10 @@ namespace JSC {
OwnPtr<PredictionTracker> m_predictions;
int32_t m_executeCounter;
uint32_t m_speculativeSuccessCounter;
uint32_t m_speculativeFailCounter;
uint8_t m_optimizationDelayCounter;
uint8_t m_reoptimizationRetryCounter;
struct RareData {
WTF_MAKE_FAST_ALLOCATED;
......@@ -909,6 +1024,7 @@ namespace JSC {
#if ENABLE(JIT)
protected:
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
virtual void jettison(JSGlobalData&);
virtual CodeBlock* replacement();
virtual bool canCompileWithDFG();
#endif
......@@ -935,6 +1051,7 @@ namespace JSC {
#if ENABLE(JIT)
protected:
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
virtual void jettison(JSGlobalData&);
virtual CodeBlock* replacement();
virtual bool canCompileWithDFG();
#endif
......@@ -962,6 +1079,7 @@ namespace JSC {
#if ENABLE(JIT)
protected:
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
virtual void jettison(JSGlobalData&);
virtual CodeBlock* replacement();
virtual bool canCompileWithDFG();
#endif
......
......@@ -492,7 +492,7 @@ private:
ASSERT(profile);
PredictedType prediction = profile->computeUpdatedPrediction();
#if ENABLE(DFG_DEBUG_VERBOSE)
printf("Dynamic [%u, %u] prediction: %s\n", nodeIndex, bytecodeIndex, predictionToString(prediction));
printf("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, predictionToString(prediction));
#endif
return prediction;
}
......
......@@ -408,6 +408,9 @@ void JITCompiler::exitSpeculativeWithOSR(const OSRExit& exit, SpeculationRecover
// entry, since both forms of OSR are expensive. OSR entry is
// particularly expensive.
//
// (d) Frequent OSR failures, even those that do not result in the code
// running in a hot loop, result in recompilation getting triggered.
//
// To ensure (c), we'd like to set the execute counter to
// counterValueForOptimizeAfterWarmUp(). This seems like it would endanger
// (a) and (b), since then every OSR exit would delay the opportunity for
......@@ -415,11 +418,40 @@ void JITCompiler::exitSpeculativeWithOSR(const OSRExit& exit, SpeculationRecover
// frequently and the function has few loops, then the counter will never
// become non-negative and OSR entry will never be triggered. OSR entry
// will only happen if a loop gets hot in the old JIT, which does a pretty
// good job of ensuring (a) and (b). This heuristic may need to be
// rethought in the future, particularly if we support reoptimizing code
// with new value profiles gathered from code that did OSR exit.
// good job of ensuring (a) and (b). But that doesn't take care of (d),
// since each speculation failure would reset the execute counter.
// So we check here if the number of speculation failures is significantly
// larger than the number of successes (we want 90% success rate), and if
// there have been a large enough number of failures. If so, we set the
// counter to 0; otherwise we set the counter to
// counterValueForOptimizeAfterWarmUp().
move(TrustedImmPtr(codeBlock()), GPRInfo::regT0);
load32(Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()), GPRInfo::regT2);
load32(Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()), GPRInfo::regT1);
add32(Imm32(1), GPRInfo::regT2);
add32(Imm32(-1), GPRInfo::regT1);
store32(GPRInfo::regT2, Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()));
store32(GPRInfo::regT1, Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()));
move(TrustedImmPtr(codeBlock()->alternative()), GPRInfo::regT0);
Jump fewFails = branch32(BelowOrEqual, GPRInfo::regT2, Imm32(codeBlock()->largeFailCountThreshold()));
mul32(Imm32(codeBlock()->desiredSuccessFailRatio()), GPRInfo::regT2, GPRInfo::regT2);
Jump lowFailRate = branch32(BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1);
store32(Imm32(codeBlock()->alternative()->counterValueForOptimizeAfterWarmUp()), codeBlock()->alternative()->addressOfExecuteCounter());
// Reoptimize as soon as possible.
store32(Imm32(CodeBlock::counterValueForOptimizeNextInvocation()), Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter()));
Jump doneAdjusting = jump();
fewFails.link(this);
lowFailRate.link(this);
store32(Imm32(codeBlock()->alternative()->counterValueForOptimizeAfterLongWarmUp()), Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter()));
doneAdjusting.link(this);
// 12) Load the result of the last bytecode operation into regT0.
......@@ -481,6 +513,8 @@ void JITCompiler::compileEntry()
// both normal return code and when jumping to an exception handler).
preserveReturnAddressAfterCall(GPRInfo::regT2);
emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
addPtr(Imm32(1), AbsoluteAddress(codeBlock()->addressOfSpeculativeSuccessCounter()));
}
void JITCompiler::compileBody()
......@@ -498,10 +532,6 @@ void JITCompiler::compileBody()
bool compiledSpeculative = speculative.compile();
ASSERT_UNUSED(compiledSpeculative, compiledSpeculative);
#if ENABLE(DFG_OSR_ENTRY)
m_codeBlock->setJITCodeMap(m_jitCodeMapEncoder.finish());
#endif
linkOSRExits(speculative);
// Iterate over the m_calls vector, checking for exception checks,
......
......@@ -320,7 +320,46 @@ public:
void noticeOSREntry(BasicBlock& basicBlock)
{
m_jitCodeMapEncoder.append(basicBlock.bytecodeBegin, differenceBetween(m_startOfCode, label()));
#if ENABLE(DFG_OSR_ENTRY)
OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, differenceBetween(m_startOfCode, label()));
unsigned lastLiveArgument = 0;
unsigned lastLiveLocal = 0;
for (unsigned i = 0; i < basicBlock.m_arguments.size(); ++i) {
if (basicBlock.m_arguments[i].value != NoNode)
lastLiveArgument = i;
}
for (unsigned i = 0; i < basicBlock.m_locals.size(); ++i) {
if (basicBlock.m_locals[i].value != NoNode)
lastLiveLocal = i;
}
if (lastLiveArgument) {