2 * Copyright (C) 2011 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.
26 #ifndef DFGJITCompiler_h
27 #define DFGJITCompiler_h
31 #include <assembler/LinkBuffer.h>
32 #include <assembler/MacroAssembler.h>
33 #include <bytecode/CodeBlock.h>
34 #include <dfg/DFGCCallHelpers.h>
35 #include <dfg/DFGFPRInfo.h>
36 #include <dfg/DFGGPRInfo.h>
37 #include <dfg/DFGGraph.h>
38 #include <dfg/DFGRegisterBank.h>
39 #include <jit/JITCode.h>
43 class AbstractSamplingCounter
;
49 class JITCodeGenerator
;
50 class NodeToRegisterMap
;
52 class SpeculationRecovery
;
57 // === CallLinkRecord ===
59 // A record of a call out from JIT code that needs linking to a helper function.
60 // Every CallLinkRecord contains a reference to the call instruction & the function
61 // that it needs to be linked to.
62 struct CallLinkRecord
{
63 CallLinkRecord(MacroAssembler::Call call
, FunctionPtr function
)
65 , m_function(function
)
69 MacroAssembler::Call m_call
;
70 FunctionPtr m_function
;
73 class CallBeginToken
{
77 : m_codeOriginIndex(UINT_MAX
)
82 explicit CallBeginToken(unsigned codeOriginIndex
)
84 : m_codeOriginIndex(codeOriginIndex
)
87 UNUSED_PARAM(codeOriginIndex
);
90 void assertCodeOriginIndex(unsigned codeOriginIndex
) const
92 ASSERT_UNUSED(codeOriginIndex
, codeOriginIndex
< UINT_MAX
);
93 ASSERT_UNUSED(codeOriginIndex
, codeOriginIndex
== m_codeOriginIndex
);
98 unsigned m_codeOriginIndex
;
102 // === CallExceptionRecord ===
104 // A record of a call out from JIT code that might throw an exception.
105 // Calls that might throw an exception also record the Jump taken on exception
106 // (unset if not present) and code origin used to recover handler/source info.
107 struct CallExceptionRecord
{
108 CallExceptionRecord(MacroAssembler::Call call
, CodeOrigin codeOrigin
, CallBeginToken token
)
110 , m_codeOrigin(codeOrigin
)
115 CallExceptionRecord(MacroAssembler::Call call
, MacroAssembler::Jump exceptionCheck
, CodeOrigin codeOrigin
, CallBeginToken token
)
117 , m_exceptionCheck(exceptionCheck
)
118 , m_codeOrigin(codeOrigin
)
123 MacroAssembler::Call m_call
;
124 MacroAssembler::Jump m_exceptionCheck
;
125 CodeOrigin m_codeOrigin
;
126 CallBeginToken m_token
;
129 struct PropertyAccessRecord
{
130 enum RegisterMode
{ RegistersFlushed
, RegistersInUse
};
133 PropertyAccessRecord(CodeOrigin codeOrigin
, MacroAssembler::DataLabelPtr deltaCheckImmToCall
, MacroAssembler::Call functionCall
, MacroAssembler::PatchableJump deltaCallToStructCheck
, MacroAssembler::DataLabelCompact deltaCallToLoadOrStore
, MacroAssembler::Label deltaCallToSlowCase
, MacroAssembler::Label deltaCallToDone
, int8_t baseGPR
, int8_t valueGPR
, int8_t scratchGPR
, RegisterMode registerMode
= RegistersInUse
)
134 #elif USE(JSVALUE32_64)
135 PropertyAccessRecord(CodeOrigin codeOrigin
, MacroAssembler::DataLabelPtr deltaCheckImmToCall
, MacroAssembler::Call functionCall
, MacroAssembler::PatchableJump deltaCallToStructCheck
, MacroAssembler::DataLabelCompact deltaCallToTagLoadOrStore
, MacroAssembler::DataLabelCompact deltaCallToPayloadLoadOrStore
, MacroAssembler::Label deltaCallToSlowCase
, MacroAssembler::Label deltaCallToDone
, int8_t baseGPR
, int8_t valueTagGPR
, int8_t valueGPR
, int8_t scratchGPR
, RegisterMode registerMode
= RegistersInUse
)
137 : m_codeOrigin(codeOrigin
)
138 , m_deltaCheckImmToCall(deltaCheckImmToCall
)
139 , m_functionCall(functionCall
)
140 , m_deltaCallToStructCheck(deltaCallToStructCheck
)
142 , m_deltaCallToLoadOrStore(deltaCallToLoadOrStore
)
143 #elif USE(JSVALUE32_64)
144 , m_deltaCallToTagLoadOrStore(deltaCallToTagLoadOrStore
)
145 , m_deltaCallToPayloadLoadOrStore(deltaCallToPayloadLoadOrStore
)
147 , m_deltaCallToSlowCase(deltaCallToSlowCase
)
148 , m_deltaCallToDone(deltaCallToDone
)
150 #if USE(JSVALUE32_64)
151 , m_valueTagGPR(valueTagGPR
)
153 , m_valueGPR(valueGPR
)
154 , m_scratchGPR(scratchGPR
)
155 , m_registerMode(registerMode
)
159 CodeOrigin m_codeOrigin
;
160 MacroAssembler::DataLabelPtr m_deltaCheckImmToCall
;
161 MacroAssembler::Call m_functionCall
;
162 MacroAssembler::PatchableJump m_deltaCallToStructCheck
;
164 MacroAssembler::DataLabelCompact m_deltaCallToLoadOrStore
;
165 #elif USE(JSVALUE32_64)
166 MacroAssembler::DataLabelCompact m_deltaCallToTagLoadOrStore
;
167 MacroAssembler::DataLabelCompact m_deltaCallToPayloadLoadOrStore
;
169 MacroAssembler::Label m_deltaCallToSlowCase
;
170 MacroAssembler::Label m_deltaCallToDone
;
172 #if USE(JSVALUE32_64)
173 int8_t m_valueTagGPR
;
177 RegisterMode m_registerMode
;
180 // === JITCompiler ===
182 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
183 // It does so by delegating to the speculative & non-speculative JITs, which
184 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
185 // relationship). The JITCompiler holds references to information required during
186 // compilation, and also records information used in linking (e.g. a list of all
187 // call to be linked).
188 class JITCompiler
: public CCallHelpers
{
190 JITCompiler(Graph
& dfg
)
191 : CCallHelpers(&dfg
.m_globalData
, dfg
.m_codeBlock
)
193 , m_currentCodeOriginIndex(0)
197 bool compile(JITCode
& entry
);
198 bool compileFunction(JITCode
& entry
, MacroAssemblerCodePtr
& entryWithArityCheck
);
200 // Accessors for properties.
201 Graph
& graph() { return m_graph
; }
203 // Get a token for beginning a call, and set the current code origin index in
205 CallBeginToken
beginCall()
207 unsigned codeOriginIndex
= m_currentCodeOriginIndex
++;
208 store32(TrustedImm32(codeOriginIndex
), tagFor(static_cast<VirtualRegister
>(RegisterFile::ArgumentCount
)));
209 return CallBeginToken(codeOriginIndex
);
212 // Notify the JIT of a call that does not require linking.
213 void notifyCall(Call functionCall
, CodeOrigin codeOrigin
, CallBeginToken token
)
215 m_exceptionChecks
.append(CallExceptionRecord(functionCall
, codeOrigin
, token
));
218 // Add a call out from JIT code, without an exception check.
219 Call
appendCall(const FunctionPtr
& function
)
221 Call functionCall
= call();
222 m_calls
.append(CallLinkRecord(functionCall
, function
));
226 // Add a call out from JIT code, with an exception check.
227 void addExceptionCheck(Call functionCall
, CodeOrigin codeOrigin
, CallBeginToken token
)
229 move(TrustedImm32(m_exceptionChecks
.size()), GPRInfo::nonPreservedNonReturnGPR
);
230 m_exceptionChecks
.append(CallExceptionRecord(functionCall
, emitExceptionCheck(), codeOrigin
, token
));
233 // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
234 void addFastExceptionCheck(Call functionCall
, CodeOrigin codeOrigin
, CallBeginToken token
)
236 move(TrustedImm32(m_exceptionChecks
.size()), GPRInfo::nonPreservedNonReturnGPR
);
237 Jump exceptionCheck
= branchTestPtr(Zero
, GPRInfo::returnValueGPR
);
238 m_exceptionChecks
.append(CallExceptionRecord(functionCall
, exceptionCheck
, codeOrigin
, token
));
241 // Helper methods to get predictions
242 PredictedType
getPrediction(Node
& node
) { return node
.prediction(); }
243 PredictedType
getPrediction(NodeIndex nodeIndex
) { return getPrediction(graph()[nodeIndex
]); }
244 PredictedType
getPrediction(Edge nodeUse
) { return getPrediction(nodeUse
.index()); }
246 #if USE(JSVALUE32_64)
247 void* addressOfDoubleConstant(NodeIndex nodeIndex
)
249 ASSERT(m_graph
.isNumberConstant(nodeIndex
));
250 unsigned constantIndex
= graph()[nodeIndex
].constantNumber();
251 return &(codeBlock()->constantRegister(FirstConstantRegisterIndex
+ constantIndex
));
255 void addPropertyAccess(const PropertyAccessRecord
& record
)
257 m_propertyAccesses
.append(record
);
260 void addJSCall(Call fastCall
, Call slowCall
, DataLabelPtr targetToCheck
, CallLinkInfo::CallType callType
, CodeOrigin codeOrigin
)
262 m_jsCalls
.append(JSCallRecord(fastCall
, slowCall
, targetToCheck
, callType
, codeOrigin
));
265 void addWeakReference(JSCell
* target
)
267 m_codeBlock
->appendWeakReference(target
);
270 void addWeakReferenceTransition(JSCell
* codeOrigin
, JSCell
* from
, JSCell
* to
)
272 m_codeBlock
->appendWeakReferenceTransition(codeOrigin
, from
, to
);
276 Jump
branchWeakPtr(RelationalCondition cond
, T left
, JSCell
* weakPtr
)
278 Jump result
= branchPtr(cond
, left
, TrustedImmPtr(weakPtr
));
279 addWeakReference(weakPtr
);
283 void noticeOSREntry(BasicBlock
& basicBlock
, JITCompiler::Label blockHead
, LinkBuffer
& linkBuffer
)
285 #if DFG_ENABLE(OSR_ENTRY)
286 OSREntryData
* entry
= codeBlock()->appendDFGOSREntryData(basicBlock
.bytecodeBegin
, linkBuffer
.offsetOf(blockHead
));
288 entry
->m_expectedValues
= basicBlock
.valuesAtHead
;
290 // Fix the expected values: in our protocol, a dead variable will have an expected
291 // value of (None, []). But the old JIT may stash some values there. So we really
293 for (size_t argument
= 0; argument
< basicBlock
.variablesAtHead
.numberOfArguments(); ++argument
) {
294 NodeIndex nodeIndex
= basicBlock
.variablesAtHead
.argument(argument
);
295 if (nodeIndex
== NoNode
|| !m_graph
[nodeIndex
].shouldGenerate())
296 entry
->m_expectedValues
.argument(argument
).makeTop();
298 for (size_t local
= 0; local
< basicBlock
.variablesAtHead
.numberOfLocals(); ++local
) {
299 NodeIndex nodeIndex
= basicBlock
.variablesAtHead
.local(local
);
300 if (nodeIndex
== NoNode
|| !m_graph
[nodeIndex
].shouldGenerate())
301 entry
->m_expectedValues
.local(local
).makeTop();
302 else if (m_graph
[nodeIndex
].variableAccessData()->shouldUseDoubleFormat())
303 entry
->m_localsForcedDouble
.set(local
);
306 UNUSED_PARAM(basicBlock
);
307 UNUSED_PARAM(blockHead
);
308 UNUSED_PARAM(linkBuffer
);
313 // Internal implementation to compile.
315 void compileBody(SpeculativeJIT
&);
316 void link(LinkBuffer
&);
318 void exitSpeculativeWithOSR(const OSRExit
&, SpeculationRecovery
*);
321 // The dataflow graph currently being generated.
324 // Vector of calls out from JIT code, including exception handler information.
325 // Count of the number of CallRecords with exception handlers.
326 Vector
<CallLinkRecord
> m_calls
;
327 Vector
<CallExceptionRecord
> m_exceptionChecks
;
329 struct JSCallRecord
{
330 JSCallRecord(Call fastCall
, Call slowCall
, DataLabelPtr targetToCheck
, CallLinkInfo::CallType callType
, CodeOrigin codeOrigin
)
331 : m_fastCall(fastCall
)
332 , m_slowCall(slowCall
)
333 , m_targetToCheck(targetToCheck
)
334 , m_callType(callType
)
335 , m_codeOrigin(codeOrigin
)
341 DataLabelPtr m_targetToCheck
;
342 CallLinkInfo::CallType m_callType
;
343 CodeOrigin m_codeOrigin
;
346 Vector
<PropertyAccessRecord
, 4> m_propertyAccesses
;
347 Vector
<JSCallRecord
, 4> m_jsCalls
;
348 unsigned m_currentCodeOriginIndex
;
351 } } // namespace JSC::DFG