initial import
[vuplus_webkit] / Source / JavaScriptCore / dfg / DFGJITCompiler.h
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #ifndef DFGJITCompiler_h
27 #define DFGJITCompiler_h
28
29 #if ENABLE(DFG_JIT)
30
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>
36
37 #include <dfg/DFGFPRInfo.h>
38 #include <dfg/DFGGPRInfo.h>
39
40 namespace JSC {
41
42 class AbstractSamplingCounter;
43 class CodeBlock;
44 class JSGlobalData;
45
46 namespace DFG {
47
48 class JITCodeGenerator;
49 class NodeToRegisterMap;
50 class NonSpeculativeJIT;
51 class SpeculativeJIT;
52 class SpeculationRecovery;
53
54 struct EntryLocation;
55 struct SpeculationCheck;
56 struct OSRExit;
57
58 #ifndef NDEBUG
59 typedef void (*V_DFGDebugOperation_EP)(ExecState*, void*);
60 #endif
61
62 #if ENABLE(DFG_VERBOSE_SPECULATION_FAILURE)
63 struct SpeculationFailureDebugInfo {
64     CodeBlock* codeBlock;
65     unsigned debugOffset;
66 };
67 #endif
68
69 // === CallRecord ===
70 //
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.
76 struct CallRecord {
77     // Constructor for a call with no exception handler.
78     CallRecord(MacroAssembler::Call call, FunctionPtr function)
79         : m_call(call)
80         , m_function(function)
81         , m_handlesExceptions(false)
82     {
83     }
84
85     // Constructor for a call with an exception handler.
86     CallRecord(MacroAssembler::Call call, FunctionPtr function, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin)
87         : m_call(call)
88         , m_function(function)
89         , m_exceptionCheck(exceptionCheck)
90         , m_codeOrigin(codeOrigin)
91         , m_handlesExceptions(true)
92     {
93     }
94
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)
98         : m_call(call)
99         , m_function(function)
100         , m_codeOrigin(codeOrigin)
101         , m_handlesExceptions(true)
102     {
103     }
104
105     MacroAssembler::Call m_call;
106     FunctionPtr m_function;
107     MacroAssembler::Jump m_exceptionCheck;
108     CodeOrigin m_codeOrigin;
109     bool m_handlesExceptions;
110 };
111
112 // === JITCompiler ===
113 //
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 {
121 public:
122     JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock)
123         : m_globalData(globalData)
124         , m_graph(dfg)
125         , m_codeBlock(codeBlock)
126         , m_exceptionCheckCount(0)
127     {
128     }
129
130     void compile(JITCode& entry);
131     void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
132
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; }
138
139 #if CPU(X86_64)
140     void preserveReturnAddressAfterCall(GPRReg reg)
141     {
142         pop(reg);
143     }
144
145     void restoreReturnAddressBeforeReturn(GPRReg reg)
146     {
147         push(reg);
148     }
149
150     void restoreReturnAddressBeforeReturn(Address address)
151     {
152         push(address);
153     }
154
155     void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, GPRReg to)
156     {
157         loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
158     }
159     void emitPutToCallFrameHeader(GPRReg from, RegisterFile::CallFrameHeaderEntry entry)
160     {
161         storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
162     }
163
164     void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
165     {
166         storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
167     }
168 #endif
169
170     static Address addressForGlobalVar(GPRReg global, int32_t varNumber)
171     {
172         return Address(global, varNumber * sizeof(Register));
173     }
174
175     static Address addressFor(VirtualRegister virtualRegister)
176     {
177         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register));
178     }
179
180     static Address tagFor(VirtualRegister virtualRegister)
181     {
182         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
183     }
184
185     static Address payloadFor(VirtualRegister virtualRegister)
186     {
187         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
188     }
189
190     Jump branchIfNotObject(GPRReg structureReg)
191     {
192         return branch8(NotEqual, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
193     }
194
195     // Notify the JIT of a call that does not require linking.
196     void notifyCall(Call call, CodeOrigin codeOrigin)
197     {
198         m_calls.append(CallRecord(call, FunctionPtr(), codeOrigin));
199     }
200
201     // Add a call out from JIT code, without an exception check.
202     void appendCall(const FunctionPtr& function)
203     {
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.
206     }
207
208     // Add a call out from JIT code, with an exception check.
209     Call appendCallWithExceptionCheck(const FunctionPtr& function, CodeOrigin codeOrigin)
210     {
211         Call functionCall = call();
212         Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception));
213         m_calls.append(CallRecord(functionCall, function, exceptionCheck, codeOrigin));
214         return functionCall;
215     }
216     
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)
219     {
220         Call functionCall = call();
221         Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR);
222         m_calls.append(CallRecord(functionCall, function, exceptionCheck, codeOrigin));
223         return functionCall;
224     }
225     
226 #ifndef NDEBUG
227     // Add a debug call. This call has no effect on JIT code execution state.
228     void debugCall(V_DFGDebugOperation_EP function, void* argument)
229     {
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);
235         }
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));
243         }
244         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
245             loadPtr(m_globalData->debugDataBuffer + i, GPRInfo::toRegister(i));
246     }
247 #endif
248
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); }
261
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);
269 #else
270     void jitAssertIsInt32(GPRReg) {}
271     void jitAssertIsJSInt32(GPRReg) {}
272     void jitAssertIsJSNumber(GPRReg) {}
273     void jitAssertIsJSDouble(GPRReg) {}
274     void jitAssertIsCell(GPRReg) {}
275 #endif
276
277     // These methods convert between doubles, and doubles boxed and JSValues.
278     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
279     {
280         moveDoubleToPtr(fpr, gpr);
281         subPtr(GPRInfo::tagTypeNumberRegister, gpr);
282         return gpr;
283     }
284     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
285     {
286         jitAssertIsJSDouble(gpr);
287         addPtr(GPRInfo::tagTypeNumberRegister, gpr);
288         movePtrToDouble(gpr, fpr);
289         return fpr;
290     }
291
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)
296     {
297         emitCount(*this, counter, increment);
298     }
299 #endif
300
301 #if ENABLE(SAMPLING_FLAGS)
302     void setSamplingFlag(int32_t flag);
303     void clearSamplingFlag(int32_t flag);
304 #endif
305
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)
307     {
308         m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckImmToCall, deltaCallToStructCheck, deltaCallToLoadOrStore, deltaCallToSlowCase, deltaCallToDone,  baseGPR, valueGPR, scratchGPR));
309     }
310     
311     void addMethodGet(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
312     {
313         m_methodGets.append(MethodGetRecord(slowCall, structToCompare, protoObj, protoStructToCompare, putFunction));
314     }
315     
316     void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, CodeOrigin codeOrigin)
317     {
318         m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, isCall, codeOrigin));
319     }
320     
321     void noticeOSREntry(BasicBlock& basicBlock)
322     {
323         m_jitCodeMapEncoder.append(basicBlock.bytecodeBegin, differenceBetween(m_startOfCode, label()));
324     }
325
326 private:
327     // Internal implementation to compile.
328     void compileEntry();
329     void compileBody();
330     void link(LinkBuffer&);
331
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);
336     
337 #if ENABLE(DFG_OSR_EXIT)
338     void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*, Vector<BytecodeAndMachineOffset>& decodedCodeMap);
339     void linkOSRExits(SpeculativeJIT&);
340 #else
341     void jumpFromSpeculativeToNonSpeculative(const SpeculationCheck&, const EntryLocation&, SpeculationRecovery*, NodeToRegisterMap& checkNodeToRegisterMap, NodeToRegisterMap& entryNodeToRegisterMap);
342     void linkSpeculationChecks(SpeculativeJIT&, NonSpeculativeJIT&);
343 #endif
344
345     // The globalData, used to access constants such as the vPtrs.
346     JSGlobalData* m_globalData;
347
348     // The dataflow graph currently being generated.
349     Graph& m_graph;
350
351     // The codeBlock currently being generated, used to access information such as constant values, immediates.
352     CodeBlock* m_codeBlock;
353
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;
358     
359     // JIT code map for OSR entrypoints.
360     Label m_startOfCode;
361     CompactJITCodeMap::Encoder m_jitCodeMapEncoder;
362
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)
371             , m_baseGPR(baseGPR)
372             , m_valueGPR(valueGPR)
373             , m_scratchGPR(scratchGPR)
374         {
375         }
376
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;
383         int8_t m_baseGPR;
384         int8_t m_valueGPR;
385         int8_t m_scratchGPR;
386     };
387     
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)
395         {
396         }
397         
398         Call m_slowCall;
399         DataLabelPtr m_structToCompare;
400         DataLabelPtr m_protoObj;
401         DataLabelPtr m_protoStructToCompare;
402         DataLabelPtr m_putFunction;
403     };
404     
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)
410             , m_isCall(isCall)
411             , m_codeOrigin(codeOrigin)
412         {
413         }
414         
415         Call m_fastCall;
416         Call m_slowCall;
417         DataLabelPtr m_targetToCheck;
418         bool m_isCall;
419         CodeOrigin m_codeOrigin;
420     };
421
422     Vector<PropertyAccessRecord, 4> m_propertyAccesses;
423     Vector<MethodGetRecord, 4> m_methodGets;
424     Vector<JSCallRecord, 4> m_jsCalls;
425 };
426
427 } } // namespace JSC::DFG
428
429 #endif
430 #endif
431