5075614505d93894d4dd88d75634deb431865d96
[WebKit-https.git] / 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 NonSpeculativeJIT;
50 class SpeculativeJIT;
51 class SpeculationRecovery;
52
53 struct EntryLocation;
54 struct SpeculationCheck;
55
56 // === CallRecord ===
57 //
58 // A record of a call out from JIT code to a helper function.
59 // Every CallRecord contains a reference to the call instruction & the function
60 // that it needs to be linked to. Calls that might throw an exception also record
61 // the Jump taken on exception (unset if not present), and ExceptionInfo (presently
62 // an unsigned, bytecode index) used to recover handler/source info.
63 struct CallRecord {
64     // Constructor for a call with no exception handler.
65     CallRecord(MacroAssembler::Call call, FunctionPtr function)
66         : m_call(call)
67         , m_function(function)
68     {
69     }
70
71     // Constructor for a call with an exception handler.
72     CallRecord(MacroAssembler::Call call, FunctionPtr function, MacroAssembler::Jump exceptionCheck, ExceptionInfo exceptionInfo)
73         : m_call(call)
74         , m_function(function)
75         , m_exceptionCheck(exceptionCheck)
76         , m_exceptionInfo(exceptionInfo)
77     {
78     }
79
80     MacroAssembler::Call m_call;
81     FunctionPtr m_function;
82     MacroAssembler::Jump m_exceptionCheck;
83     ExceptionInfo m_exceptionInfo;
84 };
85
86 // === JITCompiler ===
87 //
88 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
89 // It does so by delegating to the speculative & non-speculative JITs, which
90 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
91 // relationship). The JITCompiler holds references to information required during
92 // compilation, and also records information used in linking (e.g. a list of all
93 // call to be linked).
94 class JITCompiler : public MacroAssembler {
95 public:
96     JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock)
97         : m_globalData(globalData)
98         , m_graph(dfg)
99         , m_codeBlock(codeBlock)
100     {
101     }
102
103     void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
104
105     // Accessors for properties.
106     Graph& graph() { return m_graph; }
107     CodeBlock* codeBlock() { return m_codeBlock; }
108     JSGlobalData* globalData() { return m_globalData; }
109
110 #if CPU(X86_64)
111     void preserveReturnAddressAfterCall(GPRReg reg)
112     {
113         pop(reg);
114     }
115
116     void restoreReturnAddressBeforeReturn(GPRReg reg)
117     {
118         push(reg);
119     }
120
121     void restoreReturnAddressBeforeReturn(Address address)
122     {
123         push(address);
124     }
125
126     void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, GPRReg to)
127     {
128         loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
129     }
130     void emitPutToCallFrameHeader(GPRReg from, RegisterFile::CallFrameHeaderEntry entry)
131     {
132         storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
133     }
134
135     void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
136     {
137         storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
138     }
139 #endif
140
141     static Address addressForGlobalVar(GPRReg global, int32_t varNumber)
142     {
143         return Address(global, varNumber * sizeof(Register));
144     }
145
146     static Address addressFor(VirtualRegister virtualRegister)
147     {
148         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register));
149     }
150
151     static Address tagFor(VirtualRegister virtualRegister)
152     {
153         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
154     }
155
156     static Address payloadFor(VirtualRegister virtualRegister)
157     {
158         return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
159     }
160
161     // Add a call out from JIT code, without an exception check.
162     void appendCall(const FunctionPtr& function)
163     {
164         m_calls.append(CallRecord(call(), function));
165         // FIXME: should be able to JIT_ASSERT here that globalData->exception is null on return back to JIT code.
166     }
167
168     // Add a call out from JIT code, with an exception check.
169     Call appendCallWithExceptionCheck(const FunctionPtr& function, unsigned exceptionInfo)
170     {
171         Call functionCall = call();
172         Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception));
173         m_calls.append(CallRecord(functionCall, function, exceptionCheck, exceptionInfo));
174         return functionCall;
175     }
176
177     // Helper methods to check nodes for constants.
178     bool isConstant(NodeIndex nodeIndex)
179     {
180         return graph()[nodeIndex].isConstant();
181     }
182     bool isInt32Constant(NodeIndex nodeIndex)
183     {
184         return graph()[nodeIndex].op == Int32Constant;
185     }
186     bool isDoubleConstant(NodeIndex nodeIndex)
187     {
188         return graph()[nodeIndex].op == DoubleConstant;
189     }
190     bool isJSConstant(NodeIndex nodeIndex)
191     {
192         return graph()[nodeIndex].op == JSConstant;
193     }
194
195     // Helper methods get constant values from nodes.
196     int32_t valueOfInt32Constant(NodeIndex nodeIndex)
197     {
198         ASSERT(isInt32Constant(nodeIndex));
199         return graph()[nodeIndex].int32Constant();
200     }
201     double valueOfDoubleConstant(NodeIndex nodeIndex)
202     {
203         ASSERT(isDoubleConstant(nodeIndex));
204         return graph()[nodeIndex].numericConstant();
205     }
206     JSValue valueOfJSConstant(NodeIndex nodeIndex)
207     {
208         ASSERT(isJSConstant(nodeIndex));
209         unsigned constantIndex = graph()[nodeIndex].constantNumber();
210         return codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex).get();
211     }
212
213     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
214 #if DFG_JIT_ASSERT
215     void jitAssertIsInt32(GPRReg);
216     void jitAssertIsJSInt32(GPRReg);
217     void jitAssertIsJSNumber(GPRReg);
218     void jitAssertIsJSDouble(GPRReg);
219 #else
220     void jitAssertIsInt32(GPRReg) {}
221     void jitAssertIsJSInt32(GPRReg) {}
222     void jitAssertIsJSNumber(GPRReg) {}
223     void jitAssertIsJSDouble(GPRReg) {}
224 #endif
225
226 #if ENABLE(SAMPLING_COUNTERS)
227     // Debug profiling tool.
228     void emitCount(AbstractSamplingCounter&, uint32_t increment = 1);
229 #endif
230
231 #if ENABLE(SAMPLING_FLAGS)
232     void setSamplingFlag(int32_t flag);
233     void clearSamplingFlag(int32_t flag);
234 #endif
235
236     void addPropertyAccess(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoad)
237     {
238         m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckToCall, deltaCallToLoad));
239     }
240
241 private:
242     // These methods used in linking the speculative & non-speculative paths together.
243     void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary);
244     void fillInt32ToInteger(NodeIndex, GPRReg);
245     void fillToJS(NodeIndex, GPRReg);
246     void jumpFromSpeculativeToNonSpeculative(const SpeculationCheck&, const EntryLocation&, SpeculationRecovery*);
247     void linkSpeculationChecks(SpeculativeJIT&, NonSpeculativeJIT&);
248
249     // The globalData, used to access constants such as the vPtrs.
250     JSGlobalData* m_globalData;
251
252     // The dataflow graph currently being generated.
253     Graph& m_graph;
254
255     // The codeBlock currently being generated, used to access information such as constant values, immediates.
256     CodeBlock* m_codeBlock;
257
258     // Vector of calls out from JIT code, including exception handler information.
259     Vector<CallRecord> m_calls;
260
261     struct PropertyAccessRecord {
262         PropertyAccessRecord(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoad)
263             : m_functionCall(functionCall)
264             , m_deltaCheckToCall(deltaCheckToCall)
265             , m_deltaCallToLoad(deltaCallToLoad)
266         {
267         }
268
269         JITCompiler::Call m_functionCall;
270         intptr_t m_deltaCheckToCall;
271         intptr_t m_deltaCallToLoad;
272     };
273
274     Vector<PropertyAccessRecord, 4> m_propertyAccesses;
275 };
276
277 } } // namespace JSC::DFG
278
279 #endif
280 #endif
281