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/MacroAssembler.h>
32 #include <bytecode/CodeBlock.h>
33 #include <dfg/DFGGraph.h>
34 #include <dfg/DFGRegisterBank.h>
35 #include <jit/JITCode.h>
37 #include <dfg/DFGFPRInfo.h>
38 #include <dfg/DFGGPRInfo.h>
42 class AbstractSamplingCounter;
48 class JITCodeGenerator;
49 class NodeToRegisterMap;
50 class NonSpeculativeJIT;
52 class SpeculationRecovery;
55 struct SpeculationCheck;
59 typedef void (*V_DFGDebugOperation_EP)(ExecState*, void*);
62 #if ENABLE(DFG_VERBOSE_SPECULATION_FAILURE)
63 struct SpeculationFailureDebugInfo {
71 // A record of a call out from JIT code to a helper function.
72 // Every CallRecord contains a reference to the call instruction & the function
73 // that it needs to be linked to. Calls that might throw an exception also record
74 // the Jump taken on exception (unset if not present), and ExceptionInfo (presently
75 // an unsigned, bytecode index) used to recover handler/source info.
77 // Constructor for a call with no exception handler.
78 CallRecord(MacroAssembler::Call call, FunctionPtr function)
80 , m_function(function)
81 , m_handlesExceptions(false)
85 // Constructor for a call with an exception handler.
86 CallRecord(MacroAssembler::Call call, FunctionPtr function, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin)
88 , m_function(function)
89 , m_exceptionCheck(exceptionCheck)
90 , m_codeOrigin(codeOrigin)
91 , m_handlesExceptions(true)
95 // Constructor for a call that may cause exceptions, but which are handled
96 // through some mechanism other than the in-line exception handler.
97 CallRecord(MacroAssembler::Call call, FunctionPtr function, CodeOrigin codeOrigin)
99 , m_function(function)
100 , m_codeOrigin(codeOrigin)
101 , m_handlesExceptions(true)
105 MacroAssembler::Call m_call;
106 FunctionPtr m_function;
107 MacroAssembler::Jump m_exceptionCheck;
108 CodeOrigin m_codeOrigin;
109 bool m_handlesExceptions;
112 // === JITCompiler ===
114 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
115 // It does so by delegating to the speculative & non-speculative JITs, which
116 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
117 // relationship). The JITCompiler holds references to information required during
118 // compilation, and also records information used in linking (e.g. a list of all
119 // call to be linked).
120 class JITCompiler : public MacroAssembler {
122 JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock)
123 : m_globalData(globalData)
125 , m_codeBlock(codeBlock)
126 , m_exceptionCheckCount(0)
130 void compile(JITCode& entry);
131 void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
133 // Accessors for properties.
134 Graph& graph() { return m_graph; }
135 CodeBlock* codeBlock() { return m_codeBlock; }
136 JSGlobalData* globalData() { return m_globalData; }
137 AssemblerType_T& assembler() { return m_assembler; }
140 void preserveReturnAddressAfterCall(GPRReg reg)
145 void restoreReturnAddressBeforeReturn(GPRReg reg)
150 void restoreReturnAddressBeforeReturn(Address address)
155 void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, GPRReg to)
157 loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
159 void emitPutToCallFrameHeader(GPRReg from, RegisterFile::CallFrameHeaderEntry entry)
161 storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
164 void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
166 storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
170 static Address addressForGlobalVar(GPRReg global, int32_t varNumber)
172 return Address(global, varNumber * sizeof(Register));
175 static Address addressFor(VirtualRegister virtualRegister)
177 return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register));
180 static Address tagFor(VirtualRegister virtualRegister)
182 return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
185 static Address payloadFor(VirtualRegister virtualRegister)
187 return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
190 Jump branchIfNotObject(GPRReg structureReg)
192 return branch8(NotEqual, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
195 // Notify the JIT of a call that does not require linking.
196 void notifyCall(Call call, CodeOrigin codeOrigin)
198 m_calls.append(CallRecord(call, FunctionPtr(), codeOrigin));
201 // Add a call out from JIT code, without an exception check.
202 void appendCall(const FunctionPtr& function)
204 m_calls.append(CallRecord(call(), function));
205 // FIXME: should be able to JIT_ASSERT here that globalData->exception is null on return back to JIT code.
208 // Add a call out from JIT code, with an exception check.
209 Call appendCallWithExceptionCheck(const FunctionPtr& function, CodeOrigin codeOrigin)
211 Call functionCall = call();
212 Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception));
213 m_calls.append(CallRecord(functionCall, function, exceptionCheck, codeOrigin));
217 // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
218 Call appendCallWithFastExceptionCheck(const FunctionPtr& function, CodeOrigin codeOrigin)
220 Call functionCall = call();
221 Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR);
222 m_calls.append(CallRecord(functionCall, function, exceptionCheck, codeOrigin));
227 // Add a debug call. This call has no effect on JIT code execution state.
228 void debugCall(V_DFGDebugOperation_EP function, void* argument)
230 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
231 storePtr(GPRInfo::toRegister(i), m_globalData->debugDataBuffer + i);
232 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
233 move(TrustedImmPtr(m_globalData->debugDataBuffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
234 storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
236 move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
237 move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
238 move(TrustedImmPtr(reinterpret_cast<void*>(function)), GPRInfo::regT0);
239 call(GPRInfo::regT0);
240 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
241 move(TrustedImmPtr(m_globalData->debugDataBuffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
242 loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
244 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
245 loadPtr(m_globalData->debugDataBuffer + i, GPRInfo::toRegister(i));
249 // Helper methods to check nodes for constants.
250 bool isConstant(NodeIndex nodeIndex) { return graph().isConstant(nodeIndex); }
251 bool isJSConstant(NodeIndex nodeIndex) { return graph().isJSConstant(nodeIndex); }
252 bool isInt32Constant(NodeIndex nodeIndex) { return graph().isInt32Constant(codeBlock(), nodeIndex); }
253 bool isDoubleConstant(NodeIndex nodeIndex) { return graph().isDoubleConstant(codeBlock(), nodeIndex); }
254 bool isNumberConstant(NodeIndex nodeIndex) { return graph().isNumberConstant(codeBlock(), nodeIndex); }
255 bool isBooleanConstant(NodeIndex nodeIndex) { return graph().isBooleanConstant(codeBlock(), nodeIndex); }
256 // Helper methods get constant values from nodes.
257 JSValue valueOfJSConstant(NodeIndex nodeIndex) { return graph().valueOfJSConstant(codeBlock(), nodeIndex); }
258 int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return graph().valueOfInt32Constant(codeBlock(), nodeIndex); }
259 double valueOfNumberConstant(NodeIndex nodeIndex) { return graph().valueOfNumberConstant(codeBlock(), nodeIndex); }
260 bool valueOfBooleanConstant(NodeIndex nodeIndex) { return graph().valueOfBooleanConstant(codeBlock(), nodeIndex); }
262 // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
263 #if ENABLE(DFG_JIT_ASSERT)
264 void jitAssertIsInt32(GPRReg);
265 void jitAssertIsJSInt32(GPRReg);
266 void jitAssertIsJSNumber(GPRReg);
267 void jitAssertIsJSDouble(GPRReg);
268 void jitAssertIsCell(GPRReg);
270 void jitAssertIsInt32(GPRReg) {}
271 void jitAssertIsJSInt32(GPRReg) {}
272 void jitAssertIsJSNumber(GPRReg) {}
273 void jitAssertIsJSDouble(GPRReg) {}
274 void jitAssertIsCell(GPRReg) {}
277 // These methods convert between doubles, and doubles boxed and JSValues.
278 GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
280 moveDoubleToPtr(fpr, gpr);
281 subPtr(GPRInfo::tagTypeNumberRegister, gpr);
284 FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
286 jitAssertIsJSDouble(gpr);
287 addPtr(GPRInfo::tagTypeNumberRegister, gpr);
288 movePtrToDouble(gpr, fpr);
292 #if ENABLE(SAMPLING_COUNTERS)
293 // Debug profiling tool.
294 static void emitCount(MacroAssembler&, AbstractSamplingCounter&, uint32_t increment = 1);
295 void emitCount(AbstractSamplingCounter& counter, uint32_t increment = 1)
297 emitCount(*this, counter, increment);
301 #if ENABLE(SAMPLING_FLAGS)
302 void setSamplingFlag(int32_t flag);
303 void clearSamplingFlag(int32_t flag);
306 void addPropertyAccess(JITCompiler::Call functionCall, int16_t deltaCheckImmToCall, int16_t deltaCallToStructCheck, int16_t deltaCallToLoadOrStore, int16_t deltaCallToSlowCase, int16_t deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR)
308 m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckImmToCall, deltaCallToStructCheck, deltaCallToLoadOrStore, deltaCallToSlowCase, deltaCallToDone, baseGPR, valueGPR, scratchGPR));
311 void addMethodGet(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
313 m_methodGets.append(MethodGetRecord(slowCall, structToCompare, protoObj, protoStructToCompare, putFunction));
316 void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, CodeOrigin codeOrigin)
318 m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, isCall, codeOrigin));
321 void noticeOSREntry(BasicBlock& basicBlock)
323 m_jitCodeMapEncoder.append(basicBlock.bytecodeBegin, differenceBetween(m_startOfCode, label()));
327 // Internal implementation to compile.
330 void link(LinkBuffer&);
332 // These methods used in linking the speculative & non-speculative paths together.
333 void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary);
334 void fillInt32ToInteger(NodeIndex, GPRReg);
335 void fillToJS(NodeIndex, GPRReg);
337 #if ENABLE(DFG_OSR_EXIT)
338 void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*, Vector<BytecodeAndMachineOffset>& decodedCodeMap);
339 void linkOSRExits(SpeculativeJIT&);
341 void jumpFromSpeculativeToNonSpeculative(const SpeculationCheck&, const EntryLocation&, SpeculationRecovery*, NodeToRegisterMap& checkNodeToRegisterMap, NodeToRegisterMap& entryNodeToRegisterMap);
342 void linkSpeculationChecks(SpeculativeJIT&, NonSpeculativeJIT&);
345 // The globalData, used to access constants such as the vPtrs.
346 JSGlobalData* m_globalData;
348 // The dataflow graph currently being generated.
351 // The codeBlock currently being generated, used to access information such as constant values, immediates.
352 CodeBlock* m_codeBlock;
354 // Vector of calls out from JIT code, including exception handler information.
355 // Count of the number of CallRecords with exception handlers.
356 Vector<CallRecord> m_calls;
357 unsigned m_exceptionCheckCount;
359 // JIT code map for OSR entrypoints.
361 CompactJITCodeMap::Encoder m_jitCodeMapEncoder;
363 struct PropertyAccessRecord {
364 PropertyAccessRecord(Call functionCall, int16_t deltaCheckImmToCall, int16_t deltaCallToStructCheck, int16_t deltaCallToLoadOrStore, int16_t deltaCallToSlowCase, int16_t deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR)
365 : m_functionCall(functionCall)
366 , m_deltaCheckImmToCall(deltaCheckImmToCall)
367 , m_deltaCallToStructCheck(deltaCallToStructCheck)
368 , m_deltaCallToLoadOrStore(deltaCallToLoadOrStore)
369 , m_deltaCallToSlowCase(deltaCallToSlowCase)
370 , m_deltaCallToDone(deltaCallToDone)
372 , m_valueGPR(valueGPR)
373 , m_scratchGPR(scratchGPR)
377 JITCompiler::Call m_functionCall;
378 int16_t m_deltaCheckImmToCall;
379 int16_t m_deltaCallToStructCheck;
380 int16_t m_deltaCallToLoadOrStore;
381 int16_t m_deltaCallToSlowCase;
382 int16_t m_deltaCallToDone;
388 struct MethodGetRecord {
389 MethodGetRecord(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
390 : m_slowCall(slowCall)
391 , m_structToCompare(structToCompare)
392 , m_protoObj(protoObj)
393 , m_protoStructToCompare(protoStructToCompare)
394 , m_putFunction(putFunction)
399 DataLabelPtr m_structToCompare;
400 DataLabelPtr m_protoObj;
401 DataLabelPtr m_protoStructToCompare;
402 DataLabelPtr m_putFunction;
405 struct JSCallRecord {
406 JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, CodeOrigin codeOrigin)
407 : m_fastCall(fastCall)
408 , m_slowCall(slowCall)
409 , m_targetToCheck(targetToCheck)
411 , m_codeOrigin(codeOrigin)
417 DataLabelPtr m_targetToCheck;
419 CodeOrigin m_codeOrigin;
422 Vector<PropertyAccessRecord, 4> m_propertyAccesses;
423 Vector<MethodGetRecord, 4> m_methodGets;
424 Vector<JSCallRecord, 4> m_jsCalls;
427 } } // namespace JSC::DFG