]>
git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGOSRExitCompiler.cpp
2 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "DFGOSRExitCompiler.h"
31 #include "CallFrame.h"
32 #include "DFGCommon.h"
33 #include "LinkBuffer.h"
34 #include "Operations.h"
35 #include "RepatchBuffer.h"
36 #include <wtf/StringPrintStream.h>
38 namespace JSC
{ namespace DFG
{
42 void compileOSRExit(ExecState
* exec
)
44 SamplingRegion
samplingRegion("DFG OSR Exit Compilation");
46 CodeBlock
* codeBlock
= exec
->codeBlock();
49 ASSERT(codeBlock
->getJITType() == JITCode::DFGJIT
);
53 uint32_t exitIndex
= vm
->osrExitIndex
;
54 OSRExit
& exit
= codeBlock
->osrExit(exitIndex
);
56 // Make sure all code on our inline stack is JIT compiled. This is necessary since
57 // we may opt to inline a code block even before it had ever been compiled by the
58 // JIT, but our OSR exit infrastructure currently only works if the target of the
59 // OSR exit is JIT code. This could be changed since there is nothing particularly
60 // hard about doing an OSR exit into the interpreter, but for now this seems to make
61 // sense in that if we're OSR exiting from inlined code of a DFG code block, then
62 // probably it's a good sign that the thing we're exiting into is hot. Even more
63 // interestingly, since the code was inlined, it may never otherwise get JIT
64 // compiled since the act of inlining it may ensure that it otherwise never runs.
65 for (CodeOrigin codeOrigin
= exit
.m_codeOrigin
; codeOrigin
.inlineCallFrame
; codeOrigin
= codeOrigin
.inlineCallFrame
->caller
) {
66 static_cast<FunctionExecutable
*>(codeOrigin
.inlineCallFrame
->executable
.get())
67 ->baselineCodeBlockFor(codeOrigin
.inlineCallFrame
->isCall
? CodeForCall
: CodeForConstruct
)
71 // Compute the value recoveries.
72 Operands
<ValueRecovery
> operands
;
73 codeBlock
->variableEventStream().reconstruct(codeBlock
, exit
.m_codeOrigin
, codeBlock
->minifiedDFG(), exit
.m_streamIndex
, operands
);
75 // There may be an override, for forward speculations.
76 if (!!exit
.m_valueRecoveryOverride
) {
78 exit
.m_valueRecoveryOverride
->operand
, exit
.m_valueRecoveryOverride
->recovery
);
81 SpeculationRecovery
* recovery
= 0;
82 if (exit
.m_recoveryIndex
)
83 recovery
= &codeBlock
->speculationRecovery(exit
.m_recoveryIndex
- 1);
85 #if DFG_ENABLE(DEBUG_VERBOSE)
87 "Generating OSR exit #", exitIndex
, " (seq#", exit
.m_streamIndex
,
88 ", bc#", exit
.m_codeOrigin
.bytecodeIndex
, ", ",
89 exit
.m_kind
, ") for ", *codeBlock
, ".\n");
93 CCallHelpers
jit(vm
, codeBlock
);
94 OSRExitCompiler
exitCompiler(jit
);
96 jit
.jitAssertHasValidCallFrame();
98 if (vm
->m_perBytecodeProfiler
&& codeBlock
->compilation()) {
99 Profiler::Database
& database
= *vm
->m_perBytecodeProfiler
;
100 Profiler::Compilation
* compilation
= codeBlock
->compilation();
102 Profiler::OSRExit
* profilerExit
= compilation
->addOSRExit(
103 exitIndex
, Profiler::OriginStack(database
, codeBlock
, exit
.m_codeOrigin
),
105 exit
.m_watchpointIndex
!= std::numeric_limits
<unsigned>::max());
106 jit
.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit
->counterAddress()));
109 exitCompiler
.compileExit(exit
, operands
, recovery
);
111 LinkBuffer
patchBuffer(*vm
, &jit
, codeBlock
);
112 exit
.m_code
= FINALIZE_CODE_IF(
113 shouldShowDisassembly(),
115 ("DFG OSR exit #%u (bc#%u, %s) from %s",
116 exitIndex
, exit
.m_codeOrigin
.bytecodeIndex
,
117 exitKindToString(exit
.m_kind
), toCString(*codeBlock
).data()));
121 RepatchBuffer
repatchBuffer(codeBlock
);
122 repatchBuffer
.relink(exit
.codeLocationForRepatch(codeBlock
), CodeLocationLabel(exit
.m_code
.code()));
125 vm
->osrExitJumpDestination
= exit
.m_code
.code().executableAddress();
130 void OSRExitCompiler::handleExitCounts(const OSRExit
& exit
)
132 m_jit
.add32(AssemblyHelpers::TrustedImm32(1), AssemblyHelpers::AbsoluteAddress(&exit
.m_count
));
134 m_jit
.move(AssemblyHelpers::TrustedImmPtr(m_jit
.codeBlock()), GPRInfo::regT0
);
136 AssemblyHelpers::Jump tooFewFails
;
138 m_jit
.load32(AssemblyHelpers::Address(GPRInfo::regT0
, CodeBlock::offsetOfOSRExitCounter()), GPRInfo::regT2
);
139 m_jit
.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2
);
140 m_jit
.store32(GPRInfo::regT2
, AssemblyHelpers::Address(GPRInfo::regT0
, CodeBlock::offsetOfOSRExitCounter()));
141 m_jit
.move(AssemblyHelpers::TrustedImmPtr(m_jit
.baselineCodeBlock()), GPRInfo::regT0
);
142 tooFewFails
= m_jit
.branch32(AssemblyHelpers::BelowOrEqual
, GPRInfo::regT2
, AssemblyHelpers::TrustedImm32(m_jit
.codeBlock()->exitCountThresholdForReoptimization()));
144 // Reoptimize as soon as possible.
145 #if !NUMBER_OF_ARGUMENT_REGISTERS
146 m_jit
.poke(GPRInfo::regT0
);
148 m_jit
.move(GPRInfo::regT0
, GPRInfo::argumentGPR0
);
149 ASSERT(GPRInfo::argumentGPR0
!= GPRInfo::regT1
);
151 m_jit
.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast
<void*>(triggerReoptimizationNow
)), GPRInfo::regT1
);
152 m_jit
.call(GPRInfo::regT1
);
153 AssemblyHelpers::Jump doneAdjusting
= m_jit
.jump();
155 tooFewFails
.link(&m_jit
);
157 // Adjust the execution counter such that the target is to only optimize after a while.
158 int32_t activeThreshold
=
159 m_jit
.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp();
160 int32_t targetValue
= ExecutionCounter::applyMemoryUsageHeuristicsAndConvertToInt(
161 activeThreshold
, m_jit
.baselineCodeBlock());
162 int32_t clippedValue
=
163 ExecutionCounter::clippedThreshold(m_jit
.codeBlock()->globalObject(), targetValue
);
164 m_jit
.store32(AssemblyHelpers::TrustedImm32(-clippedValue
), AssemblyHelpers::Address(GPRInfo::regT0
, CodeBlock::offsetOfJITExecuteCounter()));
165 m_jit
.store32(AssemblyHelpers::TrustedImm32(activeThreshold
), AssemblyHelpers::Address(GPRInfo::regT0
, CodeBlock::offsetOfJITExecutionActiveThreshold()));
166 m_jit
.store32(AssemblyHelpers::TrustedImm32(ExecutionCounter::formattedTotalCount(clippedValue
)), AssemblyHelpers::Address(GPRInfo::regT0
, CodeBlock::offsetOfJITExecutionTotalCount()));
168 doneAdjusting
.link(&m_jit
);
171 } } // namespace JSC::DFG
173 #endif // ENABLE(DFG_JIT)