Commit 4ea262e2 authored by fpizlo@apple.com's avatar fpizlo@apple.com

CodeBlock compilation and installation should be simplified and rationalized

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

Reviewed by Oliver Hunt.
        
Previously Executable owned the code for generating JIT code; you always had
to go through Executable. But often you also had to go through CodeBlock,
because ScriptExecutable couldn't have virtual methods, but CodeBlock could.
So you'd ask CodeBlock to do something, which would dispatch through a
virtual method that would select the appropriate Executable subtype's method.
This all meant that the same code would often be duplicated, because most of
the work needed to compile something was identical regardless of code type.
But then we tried to fix this, by having templatized helpers in
ExecutionHarness.h and JITDriver.h. The result was that if you wanted to find
out what happened when you asked for something to be compiled, you'd go on a
wild ride that started with CodeBlock, touched upon Executable, and then
ricocheted into either ExecutionHarness or JITDriver (likely both).
        
Another awkwardness was that for concurrent compiles, the DFG::Worklist had
super-special inside knowledge of what JITStubs.cpp's cti_optimize would have
done once the compilation finished.
        
Also, most of the DFG JIT drivers assumed that they couldn't install the
JITCode into the CodeBlock directly - instead they would return it via a
reference, which happened to be a reference to the JITCode pointer in
Executable. This was super weird.
        
Finally, there was no notion of compiling code into a special CodeBlock that
wasn't used for handling calls into an Executable. I'd like this for FTL OSR
entry.
        
This patch solves these problems by reducing all of that complexity into just
three primitives:
        
- Executable::newCodeBlock(). This gives you a new code block, either for call
  or for construct, and either to serve as the baseline code or the optimized
  code. The new code block is then owned by the caller; Executable doesn't
  register it anywhere. The new code block has no JITCode and isn't callable,
  but it has all of the bytecode.
        
- CodeBlock::prepareForExecution(). This takes the CodeBlock's bytecode and
  produces a JITCode, and then installs the JITCode into the CodeBlock. This
  method takes a JITType, and always compiles with that JIT. If you ask for
  JITCode::InterpreterThunk then you'll get JITCode that just points to the
  LLInt entrypoints. Once this returns, it is possible to call into the
  CodeBlock if you do so manually - but the Executable still won't know about
  it so JS calls to that Executable will still be routed to whatever CodeBlock
  is associated with the Executable.
        
- Executable::installCode(). This takes a CodeBlock and makes it the code-for-
  entry for that Executable. This involves unlinking the Executable's last
  CodeBlock, if there was one. This also tells the GC about any effect on
  memory usage and does a bunch of weird data structure rewiring, since
  Executable caches some of CodeBlock's fields for the benefit of virtual call
  fast paths.
        
This functionality is then wrapped around three convenience methods:
        
- Executable::prepareForExecution(). If there is no code block for that
  Executable, then one is created (newCodeBlock()), compiled
  (CodeBlock::prepareForExecution()) and installed (installCode()).
        
- CodeBlock::newReplacement(). Asks the Executable for a new CodeBlock that
  can serve as an optimized replacement of the current one.
        
- CodeBlock::install(). Asks the Executable to install this code block.
        
This patch allows me to kill *a lot* of code and to remove a lot of
specializations for functions vs. not-functions, and a lot of places where we
pass around JITCode references and such. ExecutionHarness and JITDriver are
both gone. Overall this patch has more red than green.
        
It also allows me to work on FTL OSR entry and tier-up:
        
- FTL tier-up: this will involve DFGOperations.cpp asking the DFG::Worklist
  to do some compilation, but it will require the DFG::Worklist to do
  something different than what JITStubs.cpp would want, once the compilation
  finishes. This patch introduces a callback mechanism for that purpose.
        
- FTL OSR entry: this will involve creating a special auto-jettisoned
  CodeBlock that is used only for FTL OSR entry. The new set of primitives
  allows for this: Executable can vend you a fresh new CodeBlock, and you can
  ask that CodeBlock to compile itself with any JIT of your choosing. Or you
  can take that CodeBlock and compile it yourself. Previously the act of
  producing a CodeBlock-for-optimization and the act of compiling code for it
  were tightly coupled; now you can separate them and you can create such
  auto-jettisoned CodeBlocks that are used for a one-shot OSR entry.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::prepareForExecution):
(JSC::CodeBlock::install):
(JSC::CodeBlock::newReplacement):
(JSC::FunctionCodeBlock::jettisonImpl):
(JSC::CodeBlock::setOptimizationThresholdBasedOnCompilationResult):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::hasBaselineJITProfiling):
* bytecode/DeferredCompilationCallback.cpp: Added.
(JSC::DeferredCompilationCallback::DeferredCompilationCallback):
(JSC::DeferredCompilationCallback::~DeferredCompilationCallback):
* bytecode/DeferredCompilationCallback.h: Added.
* dfg/DFGDriver.cpp:
(JSC::DFG::tryCompile):
* dfg/DFGDriver.h:
(JSC::DFG::tryCompile):
* dfg/DFGFailedFinalizer.cpp:
(JSC::DFG::FailedFinalizer::finalize):
(JSC::DFG::FailedFinalizer::finalizeFunction):
* dfg/DFGFailedFinalizer.h:
* dfg/DFGFinalizer.h:
* dfg/DFGJITFinalizer.cpp:
(JSC::DFG::JITFinalizer::finalize):
(JSC::DFG::JITFinalizer::finalizeFunction):
* dfg/DFGJITFinalizer.h:
* dfg/DFGOSRExitPreparation.cpp:
(JSC::DFG::prepareCodeOriginForOSRExit):
* dfg/DFGOperations.cpp:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::Plan):
(JSC::DFG::Plan::compileInThreadImpl):
(JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
(JSC::DFG::Plan::finalizeAndNotifyCallback):
* dfg/DFGPlan.h:
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::completeAllReadyPlansForVM):
* ftl/FTLJITFinalizer.cpp:
(JSC::FTL::JITFinalizer::finalize):
(JSC::FTL::JITFinalizer::finalizeFunction):
* ftl/FTLJITFinalizer.h:
* heap/Heap.h:
(JSC::Heap::isDeferred):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
* jit/JITDriver.h: Removed.
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC::jitCompileFor):
(JSC::lazyLinkFor):
* jit/JITToDFGDeferredCompilationCallback.cpp: Added.
(JSC::JITToDFGDeferredCompilationCallback::JITToDFGDeferredCompilationCallback):
(JSC::JITToDFGDeferredCompilationCallback::~JITToDFGDeferredCompilationCallback):
(JSC::JITToDFGDeferredCompilationCallback::create):
(JSC::JITToDFGDeferredCompilationCallback::compilationDidComplete):
* jit/JITToDFGDeferredCompilationCallback.h: Added.
* llint/LLIntEntrypoints.cpp:
(JSC::LLInt::setFunctionEntrypoint):
(JSC::LLInt::setEvalEntrypoint):
(JSC::LLInt::setProgramEntrypoint):
* llint/LLIntEntrypoints.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::jitCompileAndSetHeuristics):
(JSC::LLInt::setUpCall):
* runtime/ArrayPrototype.cpp:
(JSC::isNumericCompareFunction):
* runtime/CommonSlowPaths.cpp:
* runtime/CompilationResult.cpp:
(WTF::printInternal):
* runtime/CompilationResult.h:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode):
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ScriptExecutable::newReplacementCodeBlockFor):
(JSC::ScriptExecutable::prepareForExecutionImpl):
* runtime/Executable.h:
(JSC::ScriptExecutable::prepareForExecution):
(JSC::FunctionExecutable::jettisonOptimizedCodeFor):
* runtime/ExecutionHarness.h: Removed.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154804 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent cb1d0344
......@@ -53,6 +53,7 @@ set(JavaScriptCore_SOURCES
bytecode/CodeOrigin.cpp
bytecode/CodeType.cpp
bytecode/DFGExitProfile.cpp
bytecode/DeferredCompilationCallback.cpp
bytecode/ExecutionCounter.cpp
bytecode/ExitKind.cpp
bytecode/GetByIdStatus.cpp
......@@ -243,6 +244,7 @@ set(JavaScriptCore_SOURCES
jit/JITStubRoutine.cpp
jit/JITStubs.cpp
jit/JITThunks.cpp
jit/JITToDFGDeferredCompilationCallback.cpp
jit/JumpReplacementWatchpoint.cpp
jit/ThunkGenerators.cpp
......
2013-08-28 Filip Pizlo <fpizlo@apple.com>
CodeBlock compilation and installation should be simplified and rationalized
https://bugs.webkit.org/show_bug.cgi?id=120326
Reviewed by Oliver Hunt.
Previously Executable owned the code for generating JIT code; you always had
to go through Executable. But often you also had to go through CodeBlock,
because ScriptExecutable couldn't have virtual methods, but CodeBlock could.
So you'd ask CodeBlock to do something, which would dispatch through a
virtual method that would select the appropriate Executable subtype's method.
This all meant that the same code would often be duplicated, because most of
the work needed to compile something was identical regardless of code type.
But then we tried to fix this, by having templatized helpers in
ExecutionHarness.h and JITDriver.h. The result was that if you wanted to find
out what happened when you asked for something to be compiled, you'd go on a
wild ride that started with CodeBlock, touched upon Executable, and then
ricocheted into either ExecutionHarness or JITDriver (likely both).
Another awkwardness was that for concurrent compiles, the DFG::Worklist had
super-special inside knowledge of what JITStubs.cpp's cti_optimize would have
done once the compilation finished.
Also, most of the DFG JIT drivers assumed that they couldn't install the
JITCode into the CodeBlock directly - instead they would return it via a
reference, which happened to be a reference to the JITCode pointer in
Executable. This was super weird.
Finally, there was no notion of compiling code into a special CodeBlock that
wasn't used for handling calls into an Executable. I'd like this for FTL OSR
entry.
This patch solves these problems by reducing all of that complexity into just
three primitives:
- Executable::newCodeBlock(). This gives you a new code block, either for call
or for construct, and either to serve as the baseline code or the optimized
code. The new code block is then owned by the caller; Executable doesn't
register it anywhere. The new code block has no JITCode and isn't callable,
but it has all of the bytecode.
- CodeBlock::prepareForExecution(). This takes the CodeBlock's bytecode and
produces a JITCode, and then installs the JITCode into the CodeBlock. This
method takes a JITType, and always compiles with that JIT. If you ask for
JITCode::InterpreterThunk then you'll get JITCode that just points to the
LLInt entrypoints. Once this returns, it is possible to call into the
CodeBlock if you do so manually - but the Executable still won't know about
it so JS calls to that Executable will still be routed to whatever CodeBlock
is associated with the Executable.
- Executable::installCode(). This takes a CodeBlock and makes it the code-for-
entry for that Executable. This involves unlinking the Executable's last
CodeBlock, if there was one. This also tells the GC about any effect on
memory usage and does a bunch of weird data structure rewiring, since
Executable caches some of CodeBlock's fields for the benefit of virtual call
fast paths.
This functionality is then wrapped around three convenience methods:
- Executable::prepareForExecution(). If there is no code block for that
Executable, then one is created (newCodeBlock()), compiled
(CodeBlock::prepareForExecution()) and installed (installCode()).
- CodeBlock::newReplacement(). Asks the Executable for a new CodeBlock that
can serve as an optimized replacement of the current one.
- CodeBlock::install(). Asks the Executable to install this code block.
This patch allows me to kill *a lot* of code and to remove a lot of
specializations for functions vs. not-functions, and a lot of places where we
pass around JITCode references and such. ExecutionHarness and JITDriver are
both gone. Overall this patch has more red than green.
It also allows me to work on FTL OSR entry and tier-up:
- FTL tier-up: this will involve DFGOperations.cpp asking the DFG::Worklist
to do some compilation, but it will require the DFG::Worklist to do
something different than what JITStubs.cpp would want, once the compilation
finishes. This patch introduces a callback mechanism for that purpose.
- FTL OSR entry: this will involve creating a special auto-jettisoned
CodeBlock that is used only for FTL OSR entry. The new set of primitives
allows for this: Executable can vend you a fresh new CodeBlock, and you can
ask that CodeBlock to compile itself with any JIT of your choosing. Or you
can take that CodeBlock and compile it yourself. Previously the act of
producing a CodeBlock-for-optimization and the act of compiling code for it
were tightly coupled; now you can separate them and you can create such
auto-jettisoned CodeBlocks that are used for a one-shot OSR entry.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::prepareForExecution):
(JSC::CodeBlock::install):
(JSC::CodeBlock::newReplacement):
(JSC::FunctionCodeBlock::jettisonImpl):
(JSC::CodeBlock::setOptimizationThresholdBasedOnCompilationResult):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::hasBaselineJITProfiling):
* bytecode/DeferredCompilationCallback.cpp: Added.
(JSC::DeferredCompilationCallback::DeferredCompilationCallback):
(JSC::DeferredCompilationCallback::~DeferredCompilationCallback):
* bytecode/DeferredCompilationCallback.h: Added.
* dfg/DFGDriver.cpp:
(JSC::DFG::tryCompile):
* dfg/DFGDriver.h:
(JSC::DFG::tryCompile):
* dfg/DFGFailedFinalizer.cpp:
(JSC::DFG::FailedFinalizer::finalize):
(JSC::DFG::FailedFinalizer::finalizeFunction):
* dfg/DFGFailedFinalizer.h:
* dfg/DFGFinalizer.h:
* dfg/DFGJITFinalizer.cpp:
(JSC::DFG::JITFinalizer::finalize):
(JSC::DFG::JITFinalizer::finalizeFunction):
* dfg/DFGJITFinalizer.h:
* dfg/DFGOSRExitPreparation.cpp:
(JSC::DFG::prepareCodeOriginForOSRExit):
* dfg/DFGOperations.cpp:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::Plan):
(JSC::DFG::Plan::compileInThreadImpl):
(JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
(JSC::DFG::Plan::finalizeAndNotifyCallback):
* dfg/DFGPlan.h:
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::completeAllReadyPlansForVM):
* ftl/FTLJITFinalizer.cpp:
(JSC::FTL::JITFinalizer::finalize):
(JSC::FTL::JITFinalizer::finalizeFunction):
* ftl/FTLJITFinalizer.h:
* heap/Heap.h:
(JSC::Heap::isDeferred):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
* jit/JITDriver.h: Removed.
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC::jitCompileFor):
(JSC::lazyLinkFor):
* jit/JITToDFGDeferredCompilationCallback.cpp: Added.
(JSC::JITToDFGDeferredCompilationCallback::JITToDFGDeferredCompilationCallback):
(JSC::JITToDFGDeferredCompilationCallback::~JITToDFGDeferredCompilationCallback):
(JSC::JITToDFGDeferredCompilationCallback::create):
(JSC::JITToDFGDeferredCompilationCallback::compilationDidComplete):
* jit/JITToDFGDeferredCompilationCallback.h: Added.
* llint/LLIntEntrypoints.cpp:
(JSC::LLInt::setFunctionEntrypoint):
(JSC::LLInt::setEvalEntrypoint):
(JSC::LLInt::setProgramEntrypoint):
* llint/LLIntEntrypoints.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::jitCompileAndSetHeuristics):
(JSC::LLInt::setUpCall):
* runtime/ArrayPrototype.cpp:
(JSC::isNumericCompareFunction):
* runtime/CommonSlowPaths.cpp:
* runtime/CompilationResult.cpp:
(WTF::printInternal):
* runtime/CompilationResult.h:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode):
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ScriptExecutable::newReplacementCodeBlockFor):
(JSC::ScriptExecutable::prepareForExecutionImpl):
* runtime/Executable.h:
(JSC::ScriptExecutable::prepareForExecution):
(JSC::FunctionExecutable::jettisonOptimizedCodeFor):
* runtime/ExecutionHarness.h: Removed.
2013-08-28 Chris Curtis <chris_curtis@apple.com>
https://bugs.webkit.org/show_bug.cgi?id=119548
......
......@@ -113,9 +113,11 @@ javascriptcore_sources += \
Source/JavaScriptCore/bytecode/CodeBlockWithJITType.h \
Source/JavaScriptCore/bytecode/CodeOrigin.cpp \
Source/JavaScriptCore/bytecode/CodeOrigin.h \
Source/JavaScriptCore/bytecode/DataFormat.h \
Source/JavaScriptCore/bytecode/DFGExitProfile.cpp \
Source/JavaScriptCore/bytecode/DFGExitProfile.h \
Source/JavaScriptCore/bytecode/DataFormat.h \
Source/JavaScriptCore/bytecode/DeferredCompilationCallback.cpp \
Source/JavaScriptCore/bytecode/DeferredCompilationCallback.h \
Source/JavaScriptCore/bytecode/EvalCodeCache.h \
Source/JavaScriptCore/bytecode/ExecutionCounter.cpp \
Source/JavaScriptCore/bytecode/ExecutionCounter.h \
......@@ -604,7 +606,6 @@ javascriptcore_sources += \
Source/JavaScriptCore/jit/JITCompilationEffort.h \
Source/JavaScriptCore/jit/JITDisassembler.cpp \
Source/JavaScriptCore/jit/JITDisassembler.h \
Source/JavaScriptCore/jit/JITDriver.h \
Source/JavaScriptCore/jit/JIT.cpp \
Source/JavaScriptCore/jit/JIT.h \
Source/JavaScriptCore/jit/JITExceptions.cpp \
......@@ -628,6 +629,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/jit/JITStubsX86Common.h \
Source/JavaScriptCore/jit/JITThunks.cpp \
Source/JavaScriptCore/jit/JITThunks.h \
Source/JavaScriptCore/jit/JITToDFGDeferredCompilationCallback.cpp \
Source/JavaScriptCore/jit/JITToDFGDeferredCompilationCallback.h \
Source/JavaScriptCore/jit/JITWriteBarrier.h \
Source/JavaScriptCore/jit/JSInterfaceJIT.h \
Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp \
......@@ -783,7 +786,6 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/ExceptionHelpers.h \
Source/JavaScriptCore/runtime/Executable.cpp \
Source/JavaScriptCore/runtime/Executable.h \
Source/JavaScriptCore/runtime/ExecutionHarness.h \
Source/JavaScriptCore/runtime/Float32Array.h \
Source/JavaScriptCore/runtime/Float64Array.h \
Source/JavaScriptCore/runtime/FunctionConstructor.cpp \
......
......@@ -302,6 +302,7 @@
<ClCompile Include="..\bytecode\CodeBlockHash.cpp" />
<ClCompile Include="..\bytecode\CodeOrigin.cpp" />
<ClCompile Include="..\bytecode\CodeType.cpp" />
<ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp" />
<ClCompile Include="..\bytecode\ExecutionCounter.cpp" />
<ClCompile Include="..\bytecode\ExitKind.cpp" />
<ClCompile Include="..\bytecode\GetByIdStatus.cpp" />
......@@ -377,6 +378,7 @@
<ClCompile Include="..\jit\JITStubRoutine.cpp" />
<ClCompile Include="..\jit\JITStubs.cpp" />
<ClCompile Include="..\jit\JITThunks.cpp" />
<ClCompile Include="..\jit\JITToDFGDeferredCompilationCallback.cpp" />
<ClCompile Include="..\jit\JumpReplacementWatchpoint.cpp" />
<ClCompile Include="..\jit\ThunkGenerators.cpp" />
<ClCompile Include="..\llint\LLIntCLoop.cpp" />
......@@ -623,6 +625,7 @@
<ClInclude Include="..\bytecode\CodeType.h" />
<ClInclude Include="..\bytecode\Comment.h" />
<ClInclude Include="..\bytecode\DataFormat.h" />
<ClInclude Include="..\bytecode\DeferredCompilationCallback.h" />
<ClInclude Include="..\bytecode\EvalCodeCache.h" />
<ClInclude Include="..\bytecode\ExecutionCounter.h" />
<ClInclude Include="..\bytecode\ExitKind.h" />
......@@ -740,7 +743,6 @@
<ClInclude Include="..\jit\JITCode.h" />
<ClInclude Include="..\jit\JITCompilationEffort.h" />
<ClInclude Include="..\jit\JITDisassembler.h" />
<ClInclude Include="..\jit\JITDriver.h" />
<ClInclude Include="..\jit\JITExceptions.h" />
<ClInclude Include="..\jit\JITInlines.h" />
<ClInclude Include="..\jit\JITStubCall.h" />
......@@ -750,6 +752,7 @@
<ClInclude Include="..\jit\JITStubsX86Common.h" />
<ClInclude Include="..\jit\JITStubsX86_64.h" />
<ClInclude Include="..\jit\JITThunks.h" />
<ClInclude Include="..\jit\JITToDFGDeferredCompilationCallback.h" />
<ClInclude Include="..\jit\JITWriteBarrier.h" />
<ClInclude Include="..\jit\JSInterfaceJIT.h" />
<ClInclude Include="..\jit\JumpReplacementWatchpoint.h" />
......@@ -837,7 +840,6 @@
<ClInclude Include="..\runtime\ErrorPrototype.h" />
<ClInclude Include="..\runtime\ExceptionHelpers.h" />
<ClInclude Include="..\runtime\Executable.h" />
<ClInclude Include="..\runtime\ExecutionHarness.h" />
<ClInclude Include="..\runtime\Float32Array.h" />
<ClInclude Include="..\runtime\Float64Array.h" />
<ClInclude Include="..\runtime\FunctionConstructor.h" />
......
......@@ -61,6 +61,7 @@ SOURCES += \
bytecode/CodeOrigin.cpp \
bytecode/CodeType.cpp \
bytecode/DFGExitProfile.cpp \
bytecode/DeferredCompilationCallback.cpp \
bytecode/ExecutionCounter.cpp \
bytecode/ExitKind.cpp \
bytecode/GetByIdStatus.cpp \
......@@ -221,6 +222,7 @@ SOURCES += \
jit/JITStubRoutine.cpp \
jit/JITStubs.cpp \
jit/JITThunks.cpp \
jit/JITToDFGDeferredCompilationCallback.cpp \
jit/JumpReplacementWatchpoint.cpp \
jit/ThunkGenerators.cpp \
llint/LLIntCLoop.cpp \
......
......@@ -34,6 +34,7 @@
#include "CallLinkStatus.h"
#include "DFGCapabilities.h"
#include "DFGCommon.h"
#include "DFGDriver.h"
#include "DFGNode.h"
#include "DFGRepatch.h"
#include "DFGWorklist.h"
......@@ -45,6 +46,7 @@
#include "JSCJSValue.h"
#include "JSFunction.h"
#include "JSNameScope.h"
#include "LLIntEntrypoints.h"
#include "LowLevelInterpreter.h"
#include "Operations.h"
#include "PolymorphicPutByIdList.h"
......@@ -2536,20 +2538,22 @@ void CodeBlock::linkIncomingCall(ExecState* callerFrame, CallLinkInfo* incoming)
noticeIncomingCall(callerFrame);
m_incomingCalls.push(incoming);
}
#endif // ENABLE(JIT)
void CodeBlock::unlinkIncomingCalls()
{
#if ENABLE(LLINT)
while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end())
m_incomingLLIntCalls.begin()->unlink();
#endif
#endif // ENABLE(LLINT)
#if ENABLE(JIT)
if (m_incomingCalls.isEmpty())
return;
RepatchBuffer repatchBuffer(this);
while (m_incomingCalls.begin() != m_incomingCalls.end())
m_incomingCalls.begin()->unlink(*m_vm, repatchBuffer);
}
#endif // ENABLE(JIT)
}
#if ENABLE(LLINT)
void CodeBlock::linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo* incoming)
......@@ -2689,78 +2693,108 @@ void CodeBlock::copyPostParseDataFromAlternative()
copyPostParseDataFrom(m_alternative.get());
}
#if ENABLE(JIT)
void CodeBlock::reoptimize()
{
ASSERT(replacement() != this);
ASSERT(replacement()->alternative() == this);
if (DFG::shouldShowDisassembly())
dataLog(*replacement(), " will be jettisoned due to reoptimization of ", *this, ".\n");
replacement()->jettison();
countReoptimization();
}
CodeBlock* ProgramCodeBlock::replacement()
CompilationResult CodeBlock::prepareForExecutionImpl(
ExecState* exec, JITCode::JITType jitType, JITCompilationEffort effort,
unsigned bytecodeIndex, PassRefPtr<DeferredCompilationCallback> callback)
{
return &static_cast<ProgramExecutable*>(ownerExecutable())->generatedBytecode();
VM& vm = exec->vm();
if (jitType == JITCode::InterpreterThunk) {
switch (codeType()) {
case GlobalCode:
LLInt::setProgramEntrypoint(vm, static_cast<ProgramCodeBlock*>(this));
break;
case EvalCode:
LLInt::setEvalEntrypoint(vm, static_cast<EvalCodeBlock*>(this));
break;
case FunctionCode:
LLInt::setFunctionEntrypoint(vm, static_cast<FunctionCodeBlock*>(this));
break;
}
return CompilationSuccessful;
}
#if ENABLE(JIT)
if (JITCode::isOptimizingJIT(jitType)) {
ASSERT(effort == JITCompilationCanFail);
bool hadCallback = !!callback;
CompilationResult result = DFG::tryCompile(exec, this, bytecodeIndex, callback);
ASSERT_UNUSED(hadCallback, result != CompilationDeferred || hadCallback);
return result;
}
MacroAssemblerCodePtr jitCodeWithArityCheck;
RefPtr<JITCode> jitCode = JIT::compile(&vm, this, effort, &jitCodeWithArityCheck);
if (!jitCode)
return CompilationFailed;
setJITCode(jitCode, jitCodeWithArityCheck);
return CompilationSuccessful;
#else
UNUSED_PARAM(effort);
UNUSED_PARAM(bytecodeIndex);
UNUSED_PARAM(callback);
return CompilationFailed;
#endif // ENABLE(JIT)
}
CodeBlock* EvalCodeBlock::replacement()
CompilationResult CodeBlock::prepareForExecution(
ExecState* exec, JITCode::JITType jitType,
JITCompilationEffort effort, unsigned bytecodeIndex)
{
return &static_cast<EvalExecutable*>(ownerExecutable())->generatedBytecode();
CompilationResult result =
prepareForExecutionImpl(exec, jitType, effort, bytecodeIndex, 0);
ASSERT(result != CompilationDeferred);
return result;
}
CodeBlock* FunctionCodeBlock::replacement()
CompilationResult CodeBlock::prepareForExecutionAsynchronously(
ExecState* exec, JITCode::JITType jitType,
PassRefPtr<DeferredCompilationCallback> passedCallback,
JITCompilationEffort effort, unsigned bytecodeIndex)
{
return &static_cast<FunctionExecutable*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor ? CodeForConstruct : CodeForCall);
RefPtr<DeferredCompilationCallback> callback = passedCallback;
CompilationResult result =
prepareForExecutionImpl(exec, jitType, effort, bytecodeIndex, callback);
if (result != CompilationDeferred)
callback->compilationDidComplete(this, result);
return result;
}
#if ENABLE(DFG_JIT)
JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, JSScope* scope, CompilationResult& result, unsigned bytecodeIndex)
void CodeBlock::install()
{
if (JITCode::isHigherTier(replacement()->jitType(), jitType())) {
result = CompilationNotNeeded;
return 0;
}
JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scope, result, bytecodeIndex);
return error;
ownerExecutable()->installCode(this);
}
CompilationResult ProgramCodeBlock::replaceWithDeferredOptimizedCode(PassRefPtr<DFG::Plan> plan)
PassRefPtr<CodeBlock> CodeBlock::newReplacement()
{
return static_cast<ProgramExecutable*>(ownerExecutable())->replaceWithDeferredOptimizedCode(plan);
return ownerExecutable()->newReplacementCodeBlockFor(specializationKind());
}
JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, JSScope* scope, CompilationResult& result, unsigned bytecodeIndex)
#if ENABLE(JIT)
void CodeBlock::reoptimize()
{
if (JITCode::isHigherTier(replacement()->jitType(), jitType())) {
result = CompilationNotNeeded;
return 0;
}
JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scope, result, bytecodeIndex);
return error;
ASSERT(replacement() != this);
ASSERT(replacement()->alternative() == this);
if (DFG::shouldShowDisassembly())
dataLog(*replacement(), " will be jettisoned due to reoptimization of ", *this, ".\n");
replacement()->jettison();
countReoptimization();
}
CompilationResult EvalCodeBlock::replaceWithDeferredOptimizedCode(PassRefPtr<DFG::Plan> plan)
CodeBlock* ProgramCodeBlock::replacement()
{
return static_cast<EvalExecutable*>(ownerExecutable())->replaceWithDeferredOptimizedCode(plan);
return &static_cast<ProgramExecutable*>(ownerExecutable())->generatedBytecode();
}
JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, JSScope* scope, CompilationResult& result, unsigned bytecodeIndex)
CodeBlock* EvalCodeBlock::replacement()
{
if (JITCode::isHigherTier(replacement()->jitType(), jitType())) {
result = CompilationNotNeeded;
return 0;
}
JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scope, result, bytecodeIndex, m_isConstructor ? CodeForConstruct : CodeForCall);
return error;
return &static_cast<EvalExecutable*>(ownerExecutable())->generatedBytecode();
}
CompilationResult FunctionCodeBlock::replaceWithDeferredOptimizedCode(PassRefPtr<DFG::Plan> plan)
CodeBlock* FunctionCodeBlock::replacement()
{
return static_cast<FunctionExecutable*>(ownerExecutable())->replaceWithDeferredOptimizedCodeFor(plan, m_isConstructor ? CodeForConstruct : CodeForCall);
return &static_cast<FunctionExecutable*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor ? CodeForConstruct : CodeForCall);
}
#endif // ENABLE(DFG_JIT)
DFG::CapabilityLevel ProgramCodeBlock::capabilityLevelInternal()
{
......@@ -2804,27 +2838,6 @@ void FunctionCodeBlock::jettisonImpl()
{
static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*vm(), m_isConstructor ? CodeForConstruct : CodeForCall);
}
CompilationResult ProgramCodeBlock::jitCompileImpl(ExecState* exec)
{
ASSERT(jitType() == JITCode::InterpreterThunk);
ASSERT(this == replacement());
return static_cast<ProgramExecutable*>(ownerExecutable())->jitCompile(exec);
}
CompilationResult EvalCodeBlock::jitCompileImpl(ExecState* exec)
{
ASSERT(jitType() == JITCode::InterpreterThunk);
ASSERT(this == replacement());
return static_cast<EvalExecutable*>(ownerExecutable())->jitCompile(exec);
}
CompilationResult FunctionCodeBlock::jitCompileImpl(ExecState* exec)
{
ASSERT(jitType() == JITCode::InterpreterThunk);
ASSERT(this == replacement());
return static_cast<FunctionExecutable*>(ownerExecutable())->jitCompileFor(exec, m_isConstructor ? CodeForConstruct : CodeForCall);
}
#endif
JSGlobalObject* CodeBlock::globalObjectFor(CodeOrigin codeOrigin)
......
......@@ -48,6 +48,7 @@
#include "DFGOSREntry.h"
#include "DFGOSRExit.h"
#include "DFGVariableEventStream.h"
#include "DeferredCompilationCallback.h"
#include "EvalCodeCache.h"
#include "ExecutionCounter.h"
#include "ExpressionRangeInfo.h"
......@@ -202,6 +203,8 @@ public:
unsigned bytecodeOffset(ExecState*, ReturnAddressPtr);
void unlinkIncomingCalls();
#if ENABLE(JIT)
unsigned bytecodeOffsetForCallAtIndex(unsigned index)
{
......@@ -231,8 +234,6 @@ public:
void linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo*);
#endif // ENABLE(LLINT)
void unlinkIncomingCalls();
#if ENABLE(DFG_JIT) || ENABLE(LLINT)
void setJITCodeMap(PassOwnPtr<CompactJITCodeMap> jitCodeMap)
{
......@@ -264,7 +265,38 @@ public:
int argumentIndexAfterCapture(size_t argument);
#if ENABLE(JIT)
// Prepares this code block for execution. This is synchronous. This compile
// may fail, if you passed JITCompilationCanFail.
CompilationResult prepareForExecution(
ExecState*, JITCode::JITType,
JITCompilationEffort = JITCompilationMustSucceed,
unsigned bytecodeIndex = UINT_MAX);
// Use this method for asynchronous compiles. This will do a compile at some
// point in time between when you called into this method and some point in the
// future. If you're lucky then it might complete before this method returns.
// Once it completes, the callback is called with the result. If the compile
// did happen to complete before the method returns, the result of the compile
// may be returned. If the compile didn't happen to complete yet, or if we
// didn't happen to notice that the compile already completed, we return
// CompilationDeferred.
//
// Note that asynchronous compiles don't actually complete unless you call into
// DFG::Worklist::completeAllReadyPlansForVM(). You usually force a call to
// this on the main thread by listening to the callback's
// compilationDidBecomeReadyAsynchronously() notification. Note that this call
// happens on another thread.
CompilationResult prepareForExecutionAsynchronously(
ExecState*, JITCode::JITType, PassRefPtr<DeferredCompilationCallback>,
JITCompilationEffort = JITCompilationMustSucceed,
unsigned bytecodeIndex = UINT_MAX);
// Exactly equivalent to codeBlock->ownerExecutable()->installCode(codeBlock);
void install();
// Exactly equivalent to codeBlock->ownerExecutable()->newReplacementCodeBlockFor(codeBlock->specializationKind())
PassRefPtr<CodeBlock> newReplacement();
void setJITCode(PassRefPtr<JITCode> code, MacroAssemblerCodePtr codeWithArityCheck)
{
ConcurrentJITLocker locker(m_lock);
......@@ -286,23 +318,14 @@ public:
WTF::loadLoadFence(); // This probably isn't needed. Oh well, paranoia is good.
return result;
}
#if ENABLE(JIT)
bool hasBaselineJITProfiling() const
{
return jitType() == JITCode::BaselineJIT;
}
#if ENABLE(DFG_JIT)
virtual JSObject* compileOptimized(ExecState*, JSScope*, CompilationResult&, unsigned bytecodeIndex) = 0;
virtual CompilationResult replaceWithDeferredOptimizedCode(PassRefPtr<DFG::Plan>) = 0;
#endif // ENABLE(DFG_JIT)
void jettison();
CompilationResult jitCompile(ExecState* exec)
{
if (jitType() != JITCode::InterpreterThunk) {
ASSERT(jitType() == JITCode::BaselineJIT);
return CompilationNotNeeded;
}
return jitCompileImpl(exec);
}
virtual CodeBlock* replacement() = 0;
virtual DFG::CapabilityLevel capabilityLevelInternal() = 0;
......@@ -315,8 +338,6 @@ public:
DFG::CapabilityLevel capabilityLevelState() { return m_capabilityLevelState; }
bool hasOptimizedReplacement();
#else
JITCode::JITType jitType() const { return JITCode::InterpreterThunk; }
#endif
ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); }
......@@ -969,7 +990,6 @@ public:
protected:
#if ENABLE(JIT)
virtual CompilationResult jitCompileImpl(ExecState*) = 0;
virtual void jettisonImpl() = 0;
#endif
virtual void visitWeakReferences(SlotVisitor&);
......@@ -984,6 +1004,10 @@ protected:
private:
friend class DFGCodeBlocks;
CompilationResult prepareForExecutionImpl(
ExecState*, JITCode::JITType, JITCompilationEffort, unsigned bytecodeIndex,
PassRefPtr<DeferredCompilationCallback>);
void noticeIncomingCall(ExecState* callerFrame);
double optimizationThresholdScalingFactor();
......@@ -1085,12 +1109,12 @@ private:
SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos;
SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo> > m_incomingLLIntCalls;
#endif
RefPtr<JITCode> m_jitCode;
MacroAssemblerCodePtr m_jitCodeWithArityCheck;
#if ENABLE(JIT)
Vector<StructureStubInfo> m_structureStubInfos;
Vector<ByValInfo> m_byValInfos;
Vector<CallLinkInfo> m_callLinkInfos;
RefPtr<JITCode> m_jitCode;
MacroAssemblerCodePtr m_jitCodeWithArityCheck;
SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo> > m_incomingCalls;
#endif
#if ENABLE(DFG_JIT) || ENABLE(LLINT)
......@@ -1194,13 +1218,7 @@ public: