2 * Copyright (C) 2011, 2013 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 "CodeBlock.h"
32 #include "DFGCCallHelpers.h"
33 #include "DFGDisassembler.h"
34 #include "DFGFPRInfo.h"
35 #include "DFGGPRInfo.h"
37 #include "DFGOSRExitCompilationInfo.h"
38 #include "DFGRegisterBank.h"
39 #include "DFGRegisterSet.h"
41 #include "LinkBuffer.h"
42 #include "MacroAssembler.h"
46 class AbstractSamplingCounter
;
52 class JITCodeGenerator
;
53 class NodeToRegisterMap
;
54 class OSRExitJumpPlaceholder
;
55 class SlowPathGenerator
;
57 class SpeculationRecovery
;
62 // === CallLinkRecord ===
64 // A record of a call out from JIT code that needs linking to a helper function.
65 // Every CallLinkRecord contains a reference to the call instruction & the function
66 // that it needs to be linked to.
67 struct CallLinkRecord
{
68 CallLinkRecord(MacroAssembler::Call call
, FunctionPtr function
)
70 , m_function(function
)
74 MacroAssembler::Call m_call
;
75 FunctionPtr m_function
;
78 class CallBeginToken
{
83 , m_exceptionCheckIndex(std::numeric_limits
<unsigned>::max())
90 ASSERT(m_registered
|| !m_codeOrigin
.isSet());
91 ASSERT(m_codeOrigin
.isSet() == (m_exceptionCheckIndex
!= std::numeric_limits
<unsigned>::max()));
94 void set(CodeOrigin codeOrigin
, unsigned index
)
97 ASSERT(m_registered
|| !m_codeOrigin
.isSet());
98 ASSERT(m_codeOrigin
.isSet() == (m_exceptionCheckIndex
!= std::numeric_limits
<unsigned>::max()));
99 m_codeOrigin
= codeOrigin
;
100 m_registered
= false;
101 m_exceptionCheckIndex
= index
;
103 UNUSED_PARAM(codeOrigin
);
108 void registerWithExceptionCheck(CodeOrigin codeOrigin
, unsigned index
)
111 ASSERT(m_codeOrigin
== codeOrigin
);
114 ASSERT(m_exceptionCheckIndex
== index
);
117 UNUSED_PARAM(codeOrigin
);
123 const CodeOrigin
& codeOrigin() const
131 CodeOrigin m_codeOrigin
;
133 unsigned m_exceptionCheckIndex
;
137 // === CallExceptionRecord ===
139 // A record of a call out from JIT code that might throw an exception.
140 // Calls that might throw an exception also record the Jump taken on exception
141 // (unset if not present) and code origin used to recover handler/source info.
142 struct CallExceptionRecord
{
143 CallExceptionRecord(MacroAssembler::Call call
, CodeOrigin codeOrigin
)
145 , m_codeOrigin(codeOrigin
)
149 CallExceptionRecord(MacroAssembler::Call call
, MacroAssembler::Jump exceptionCheck
, CodeOrigin codeOrigin
)
151 , m_exceptionCheck(exceptionCheck
)
152 , m_codeOrigin(codeOrigin
)
156 MacroAssembler::Call m_call
;
157 MacroAssembler::Jump m_exceptionCheck
;
158 CodeOrigin m_codeOrigin
;
161 struct PropertyAccessRecord
{
162 enum RegisterMode
{ RegistersFlushed
, RegistersInUse
};
165 PropertyAccessRecord(
166 CodeOrigin codeOrigin
,
167 MacroAssembler::DataLabelPtr structureImm
,
168 MacroAssembler::PatchableJump structureCheck
,
169 MacroAssembler::ConvertibleLoadLabel propertyStorageLoad
,
170 MacroAssembler::DataLabelCompact loadOrStore
,
171 SlowPathGenerator
* slowPathGenerator
,
172 MacroAssembler::Label done
,
175 const RegisterSet
& usedRegisters
,
176 RegisterMode registerMode
= RegistersInUse
)
177 #elif USE(JSVALUE32_64)
178 PropertyAccessRecord(
179 CodeOrigin codeOrigin
,
180 MacroAssembler::DataLabelPtr structureImm
,
181 MacroAssembler::PatchableJump structureCheck
,
182 MacroAssembler::ConvertibleLoadLabel propertyStorageLoad
,
183 MacroAssembler::DataLabelCompact tagLoadOrStore
,
184 MacroAssembler::DataLabelCompact payloadLoadOrStore
,
185 SlowPathGenerator
* slowPathGenerator
,
186 MacroAssembler::Label done
,
190 const RegisterSet
& usedRegisters
,
191 RegisterMode registerMode
= RegistersInUse
)
193 : m_codeOrigin(codeOrigin
)
194 , m_structureImm(structureImm
)
195 , m_structureCheck(structureCheck
)
196 , m_propertyStorageLoad(propertyStorageLoad
)
198 , m_loadOrStore(loadOrStore
)
199 #elif USE(JSVALUE32_64)
200 , m_tagLoadOrStore(tagLoadOrStore
)
201 , m_payloadLoadOrStore(payloadLoadOrStore
)
203 , m_slowPathGenerator(slowPathGenerator
)
206 #if USE(JSVALUE32_64)
207 , m_valueTagGPR(valueTagGPR
)
209 , m_valueGPR(valueGPR
)
210 , m_usedRegisters(usedRegisters
)
211 , m_registerMode(registerMode
)
215 CodeOrigin m_codeOrigin
;
216 MacroAssembler::DataLabelPtr m_structureImm
;
217 MacroAssembler::PatchableJump m_structureCheck
;
218 MacroAssembler::ConvertibleLoadLabel m_propertyStorageLoad
;
220 MacroAssembler::DataLabelCompact m_loadOrStore
;
221 #elif USE(JSVALUE32_64)
222 MacroAssembler::DataLabelCompact m_tagLoadOrStore
;
223 MacroAssembler::DataLabelCompact m_payloadLoadOrStore
;
225 SlowPathGenerator
* m_slowPathGenerator
;
226 MacroAssembler::Label m_done
;
228 #if USE(JSVALUE32_64)
229 int8_t m_valueTagGPR
;
232 RegisterSet m_usedRegisters
;
233 RegisterMode m_registerMode
;
236 // === JITCompiler ===
238 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
239 // It does so by delegating to the speculative & non-speculative JITs, which
240 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
241 // relationship). The JITCompiler holds references to information required during
242 // compilation, and also records information used in linking (e.g. a list of all
243 // call to be linked).
244 class JITCompiler
: public CCallHelpers
{
246 JITCompiler(Graph
& dfg
);
248 bool compile(JITCode
& entry
);
249 bool compileFunction(JITCode
& entry
, MacroAssemblerCodePtr
& entryWithArityCheck
);
251 // Accessors for properties.
252 Graph
& graph() { return m_graph
; }
254 // Methods to set labels for the disassembler.
255 void setStartOfCode()
257 if (LIKELY(!m_disassembler
))
259 m_disassembler
->setStartOfCode(labelIgnoringWatchpoints());
262 void setForBlock(BlockIndex blockIndex
)
264 if (LIKELY(!m_disassembler
))
266 m_disassembler
->setForBlock(blockIndex
, labelIgnoringWatchpoints());
269 void setForNode(Node
* node
)
271 if (LIKELY(!m_disassembler
))
273 m_disassembler
->setForNode(node
, labelIgnoringWatchpoints());
276 void setEndOfMainPath()
278 if (LIKELY(!m_disassembler
))
280 m_disassembler
->setEndOfMainPath(labelIgnoringWatchpoints());
285 if (LIKELY(!m_disassembler
))
287 m_disassembler
->setEndOfCode(labelIgnoringWatchpoints());
290 unsigned currentCodeOriginIndex() const
292 return m_currentCodeOriginIndex
;
295 // Get a token for beginning a call, and set the current code origin index in
296 // the call frame. For each beginCall() there must be at least one exception
297 // check, and all of the exception checks must have the same CodeOrigin as the
299 void beginCall(CodeOrigin codeOrigin
, CallBeginToken
& token
)
301 unsigned index
= m_exceptionChecks
.size();
302 store32(TrustedImm32(index
), tagFor(static_cast<VirtualRegister
>(JSStack::ArgumentCount
)));
303 token
.set(codeOrigin
, index
);
306 // Notify the JIT of a call that does not require linking.
307 void notifyCall(Call functionCall
, CodeOrigin codeOrigin
, CallBeginToken
& token
)
309 token
.registerWithExceptionCheck(codeOrigin
, m_exceptionChecks
.size());
310 m_exceptionChecks
.append(CallExceptionRecord(functionCall
, codeOrigin
));
313 // Add a call out from JIT code, without an exception check.
314 Call
appendCall(const FunctionPtr
& function
)
316 Call functionCall
= call();
317 m_calls
.append(CallLinkRecord(functionCall
, function
));
321 void prepareForExceptionCheck()
323 move(TrustedImm32(m_exceptionChecks
.size()), GPRInfo::nonPreservedNonReturnGPR
);
326 // Add a call out from JIT code, with an exception check.
327 void addExceptionCheck(Call functionCall
, CodeOrigin codeOrigin
, CallBeginToken
& token
)
329 prepareForExceptionCheck();
330 token
.registerWithExceptionCheck(codeOrigin
, m_exceptionChecks
.size());
331 m_exceptionChecks
.append(CallExceptionRecord(functionCall
, emitExceptionCheck(), codeOrigin
));
334 // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
335 void addFastExceptionCheck(Call functionCall
, CodeOrigin codeOrigin
, CallBeginToken
& token
)
337 prepareForExceptionCheck();
338 Jump exceptionCheck
= branchTestPtr(Zero
, GPRInfo::returnValueGPR
);
339 token
.registerWithExceptionCheck(codeOrigin
, m_exceptionChecks
.size());
340 m_exceptionChecks
.append(CallExceptionRecord(functionCall
, exceptionCheck
, codeOrigin
));
343 void appendExitInfo(MacroAssembler::JumpList jumpsToFail
= MacroAssembler::JumpList())
345 OSRExitCompilationInfo info
;
346 info
.m_failureJumps
= jumpsToFail
;
347 m_exitCompilationInfo
.append(info
);
350 #if USE(JSVALUE32_64)
351 void* addressOfDoubleConstant(Node
* node
)
353 ASSERT(m_graph
.isNumberConstant(node
));
354 unsigned constantIndex
= node
->constantNumber();
355 return &(codeBlock()->constantRegister(FirstConstantRegisterIndex
+ constantIndex
));
359 void addPropertyAccess(const PropertyAccessRecord
& record
)
361 m_propertyAccesses
.append(record
);
364 void addJSCall(Call fastCall
, Call slowCall
, DataLabelPtr targetToCheck
, CallLinkInfo::CallType callType
, GPRReg callee
, CodeOrigin codeOrigin
)
366 m_jsCalls
.append(JSCallRecord(fastCall
, slowCall
, targetToCheck
, callType
, callee
, codeOrigin
));
369 void addWeakReference(JSCell
* target
)
371 m_codeBlock
->appendWeakReference(target
);
374 void addWeakReferences(const StructureSet
& structureSet
)
376 for (unsigned i
= structureSet
.size(); i
--;)
377 addWeakReference(structureSet
[i
]);
380 void addWeakReferenceTransition(JSCell
* codeOrigin
, JSCell
* from
, JSCell
* to
)
382 m_codeBlock
->appendWeakReferenceTransition(codeOrigin
, from
, to
);
386 Jump
branchWeakPtr(RelationalCondition cond
, T left
, JSCell
* weakPtr
)
388 Jump result
= branchPtr(cond
, left
, TrustedImmPtr(weakPtr
));
389 addWeakReference(weakPtr
);
393 void noticeOSREntry(BasicBlock
& basicBlock
, JITCompiler::Label blockHead
, LinkBuffer
& linkBuffer
)
395 #if DFG_ENABLE(OSR_ENTRY)
396 // OSR entry is not allowed into blocks deemed unreachable by control flow analysis.
397 if (!basicBlock
.cfaHasVisited
)
400 OSREntryData
* entry
= codeBlock()->appendDFGOSREntryData(basicBlock
.bytecodeBegin
, linkBuffer
.offsetOf(blockHead
));
402 entry
->m_expectedValues
= basicBlock
.valuesAtHead
;
404 // Fix the expected values: in our protocol, a dead variable will have an expected
405 // value of (None, []). But the old JIT may stash some values there. So we really
407 for (size_t argument
= 0; argument
< basicBlock
.variablesAtHead
.numberOfArguments(); ++argument
) {
408 Node
* node
= basicBlock
.variablesAtHead
.argument(argument
);
409 if (!node
|| !node
->shouldGenerate())
410 entry
->m_expectedValues
.argument(argument
).makeTop();
412 for (size_t local
= 0; local
< basicBlock
.variablesAtHead
.numberOfLocals(); ++local
) {
413 Node
* node
= basicBlock
.variablesAtHead
.local(local
);
414 if (!node
|| !node
->shouldGenerate())
415 entry
->m_expectedValues
.local(local
).makeTop();
416 else if (node
->variableAccessData()->shouldUseDoubleFormat())
417 entry
->m_localsForcedDouble
.set(local
);
420 UNUSED_PARAM(basicBlock
);
421 UNUSED_PARAM(blockHead
);
422 UNUSED_PARAM(linkBuffer
);
427 friend class OSRExitJumpPlaceholder
;
429 // Internal implementation to compile.
431 void compileBody(SpeculativeJIT
&);
432 void link(LinkBuffer
&);
434 void exitSpeculativeWithOSR(const OSRExit
&, SpeculationRecovery
*);
435 void compileExceptionHandlers();
438 // The dataflow graph currently being generated.
441 OwnPtr
<Disassembler
> m_disassembler
;
443 // Vector of calls out from JIT code, including exception handler information.
444 // Count of the number of CallRecords with exception handlers.
445 Vector
<CallLinkRecord
> m_calls
;
446 Vector
<CallExceptionRecord
> m_exceptionChecks
;
448 struct JSCallRecord
{
449 JSCallRecord(Call fastCall
, Call slowCall
, DataLabelPtr targetToCheck
, CallLinkInfo::CallType callType
, GPRReg callee
, CodeOrigin codeOrigin
)
450 : m_fastCall(fastCall
)
451 , m_slowCall(slowCall
)
452 , m_targetToCheck(targetToCheck
)
453 , m_callType(callType
)
455 , m_codeOrigin(codeOrigin
)
461 DataLabelPtr m_targetToCheck
;
462 CallLinkInfo::CallType m_callType
;
464 CodeOrigin m_codeOrigin
;
467 Vector
<PropertyAccessRecord
, 4> m_propertyAccesses
;
468 Vector
<JSCallRecord
, 4> m_jsCalls
;
469 Vector
<OSRExitCompilationInfo
> m_exitCompilationInfo
;
470 Vector
<Vector
<Label
> > m_exitSiteLabels
;
471 unsigned m_currentCodeOriginIndex
;
474 } } // namespace JSC::DFG