0f78ff123bda4c52df0a18e163ba8342b718fb0e
[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/DFGAssemblyHelpers.h>
34 #include <dfg/DFGFPRInfo.h>
35 #include <dfg/DFGGPRInfo.h>
36 #include <dfg/DFGGraph.h>
37 #include <dfg/DFGRegisterBank.h>
38 #include <jit/JITCode.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 SpeculativeJIT;
51 class SpeculationRecovery;
52
53 struct EntryLocation;
54 struct OSRExit;
55
56 #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
57 struct SpeculationFailureDebugInfo {
58     CodeBlock* codeBlock;
59     unsigned debugOffset;
60 };
61 #endif
62
63 // === CallLinkRecord ===
64 //
65 // A record of a call out from JIT code that needs linking to a helper function.
66 // Every CallLinkRecord contains a reference to the call instruction & the function
67 // that it needs to be linked to.
68 struct CallLinkRecord {
69     CallLinkRecord(MacroAssembler::Call call, FunctionPtr function)
70         : m_call(call)
71         , m_function(function)
72     {
73     }
74
75     MacroAssembler::Call m_call;
76     FunctionPtr m_function;
77 };
78
79 // === CallExceptionRecord ===
80 //
81 // A record of a call out from JIT code that might throw an exception.
82 // Calls that might throw an exception also record the Jump taken on exception
83 // (unset if not present) and code origin used to recover handler/source info.
84 struct CallExceptionRecord {
85     CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin)
86         : m_call(call)
87         , m_codeOrigin(codeOrigin)
88     {
89     }
90
91     CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin)
92         : m_call(call)
93         , m_exceptionCheck(exceptionCheck)
94         , m_codeOrigin(codeOrigin)
95     {
96     }
97
98     MacroAssembler::Call m_call;
99     MacroAssembler::Jump m_exceptionCheck;
100     CodeOrigin m_codeOrigin;
101 };
102
103 // === JITCompiler ===
104 //
105 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
106 // It does so by delegating to the speculative & non-speculative JITs, which
107 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
108 // relationship). The JITCompiler holds references to information required during
109 // compilation, and also records information used in linking (e.g. a list of all
110 // call to be linked).
111 class JITCompiler : public AssemblyHelpers {
112 public:
113     JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock)
114         : AssemblyHelpers(globalData, codeBlock)
115         , m_graph(dfg)
116     {
117     }
118
119     void compile(JITCode& entry);
120     void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
121
122     // Accessors for properties.
123     Graph& graph() { return m_graph; }
124
125     // Notify the JIT of a call that does not require linking.
126     void notifyCall(Call functionCall, CodeOrigin codeOrigin)
127     {
128         m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin));
129     }
130
131     // Add a call out from JIT code, without an exception check.
132     Call appendCall(const FunctionPtr& function)
133     {
134         Call functionCall = call();
135         m_calls.append(CallLinkRecord(functionCall, function));
136         return functionCall;
137     }
138
139     // Add a call out from JIT code, with an exception check.
140     Call addExceptionCheck(Call functionCall, CodeOrigin codeOrigin)
141     {
142 #if USE(JSVALUE64)
143         Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception));
144 #elif USE(JSVALUE32_64)
145         Jump exceptionCheck = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData()->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
146 #endif
147         m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin));
148         return functionCall;
149     }
150     
151     // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
152     Call addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin)
153     {
154         Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR);
155         m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin));
156         return functionCall;
157     }
158     
159     // Helper methods to check nodes for constants.
160     bool isConstant(NodeIndex nodeIndex) { return graph().isConstant(nodeIndex); }
161     bool isJSConstant(NodeIndex nodeIndex) { return graph().isJSConstant(nodeIndex); }
162     bool isInt32Constant(NodeIndex nodeIndex) { return graph().isInt32Constant(codeBlock(), nodeIndex); }
163     bool isDoubleConstant(NodeIndex nodeIndex) { return graph().isDoubleConstant(codeBlock(), nodeIndex); }
164     bool isNumberConstant(NodeIndex nodeIndex) { return graph().isNumberConstant(codeBlock(), nodeIndex); }
165     bool isBooleanConstant(NodeIndex nodeIndex) { return graph().isBooleanConstant(codeBlock(), nodeIndex); }
166     bool isFunctionConstant(NodeIndex nodeIndex) { return graph().isFunctionConstant(codeBlock(), nodeIndex); }
167     // Helper methods get constant values from nodes.
168     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return graph().valueOfJSConstant(codeBlock(), nodeIndex); }
169     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return graph().valueOfInt32Constant(codeBlock(), nodeIndex); }
170     double valueOfNumberConstant(NodeIndex nodeIndex) { return graph().valueOfNumberConstant(codeBlock(), nodeIndex); }
171     bool valueOfBooleanConstant(NodeIndex nodeIndex) { return graph().valueOfBooleanConstant(codeBlock(), nodeIndex); }
172     JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) { return graph().valueOfFunctionConstant(codeBlock(), nodeIndex); }
173     
174     // Helper methods to get predictions
175     PredictedType getPrediction(Node& node) { return node.prediction(); }
176     PredictedType getPrediction(NodeIndex nodeIndex) { return getPrediction(graph()[nodeIndex]); }
177
178 #if USE(JSVALUE32_64)
179     void* addressOfDoubleConstant(NodeIndex nodeIndex)
180     {
181         ASSERT(isNumberConstant(nodeIndex));
182         unsigned constantIndex = graph()[nodeIndex].constantNumber();
183         return &(codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex));
184     }
185
186     void emitLoadTag(NodeIndex, GPRReg tag);
187     void emitLoadPayload(NodeIndex, GPRReg payload);
188
189     void emitLoad(const JSValue&, GPRReg tag, GPRReg payload);
190     void emitLoad(NodeIndex, GPRReg tag, GPRReg payload);
191     void emitLoad2(NodeIndex index1, GPRReg tag1, GPRReg payload1, NodeIndex index2, GPRReg tag2, GPRReg payload2);
192
193     void emitLoadDouble(NodeIndex, FPRReg value);
194     void emitLoadInt32ToDouble(NodeIndex, FPRReg value);
195
196     void emitStore(NodeIndex, GPRReg tag, GPRReg payload);
197     void emitStore(NodeIndex, const JSValue constant);
198     void emitStoreInt32(NodeIndex, GPRReg payload, bool indexIsInt32 = false);
199     void emitStoreInt32(NodeIndex, TrustedImm32 payload, bool indexIsInt32 = false);
200     void emitStoreCell(NodeIndex, GPRReg payload, bool indexIsCell = false);
201     void emitStoreBool(NodeIndex, GPRReg payload, bool indexIsBool = false);
202     void emitStoreDouble(NodeIndex, FPRReg value);
203 #endif
204
205 #if USE(JSVALUE64)
206     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)
207     {
208         m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckImmToCall, deltaCallToStructCheck, deltaCallToLoadOrStore, deltaCallToSlowCase, deltaCallToDone,  baseGPR, valueGPR, scratchGPR));
209     }
210 #elif USE(JSVALUE32_64)
211     void addPropertyAccess(JITCompiler::Call functionCall, int16_t deltaCheckImmToCall, int16_t deltaCallToStructCheck, int16_t deltaCallToTagLoadOrStore, int16_t deltaCallToPayloadLoadOrStore, int16_t deltaCallToSlowCase, int16_t deltaCallToDone, int8_t baseGPR, int8_t valueTagGPR, int8_t valueGPR, int8_t scratchGPR)
212     {
213         m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckImmToCall, deltaCallToStructCheck, deltaCallToTagLoadOrStore, deltaCallToPayloadLoadOrStore, deltaCallToSlowCase, deltaCallToDone,  baseGPR, valueTagGPR, valueGPR, scratchGPR));
214     }
215 #endif
216
217     void addMethodGet(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
218     {
219         m_methodGets.append(MethodGetRecord(slowCall, structToCompare, protoObj, protoStructToCompare, putFunction));
220     }
221     
222     void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, CodeOrigin codeOrigin)
223     {
224         m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, isCall, codeOrigin));
225     }
226     
227     void noticeOSREntry(BasicBlock& basicBlock)
228     {
229 #if DFG_ENABLE(OSR_ENTRY)
230         OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, differenceBetween(m_startOfCode, label()));
231         
232         entry->m_expectedValues = basicBlock.valuesAtHead;
233         
234         // Fix the expected values: in our protocol, a dead variable will have an expected
235         // value of (None, []). But the old JIT may stash some values there. So we really
236         // need (Top, TOP).
237         for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) {
238             if (basicBlock.variablesAtHead.argument(argument) == NoNode)
239                 entry->m_expectedValues.argument(argument).makeTop();
240         }
241         for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) {
242             if (basicBlock.variablesAtHead.local(local) == NoNode)
243                 entry->m_expectedValues.local(local).makeTop();
244         }
245 #else
246         UNUSED_PARAM(basicBlock);
247 #endif
248     }
249
250     ValueProfile* valueProfileFor(NodeIndex nodeIndex)
251     {
252         if (nodeIndex == NoNode)
253             return 0;
254         
255         return m_graph.valueProfileFor(nodeIndex, baselineCodeBlockFor(m_graph[nodeIndex].codeOrigin));
256     }
257     
258 private:
259     // Internal implementation to compile.
260     void compileEntry();
261     void compileBody();
262     void link(LinkBuffer&);
263
264     void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*);
265     void linkOSRExits(SpeculativeJIT&);
266     
267     // The dataflow graph currently being generated.
268     Graph& m_graph;
269
270     // Vector of calls out from JIT code, including exception handler information.
271     // Count of the number of CallRecords with exception handlers.
272     Vector<CallLinkRecord> m_calls;
273     Vector<CallExceptionRecord> m_exceptionChecks;
274     
275     // JIT code map for OSR entrypoints.
276     Label m_startOfCode;
277
278     struct PropertyAccessRecord {
279 #if USE(JSVALUE64)
280         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)
281 #elif USE(JSVALUE32_64)
282         PropertyAccessRecord(Call functionCall, int16_t deltaCheckImmToCall, int16_t deltaCallToStructCheck, int16_t deltaCallToTagLoadOrStore, int16_t deltaCallToPayloadLoadOrStore, int16_t deltaCallToSlowCase, int16_t deltaCallToDone, int8_t baseGPR, int8_t valueTagGPR, int8_t valueGPR, int8_t scratchGPR)
283 #endif
284             : m_functionCall(functionCall)
285             , m_deltaCheckImmToCall(deltaCheckImmToCall)
286             , m_deltaCallToStructCheck(deltaCallToStructCheck)
287 #if USE(JSVALUE64)
288             , m_deltaCallToLoadOrStore(deltaCallToLoadOrStore)
289 #elif USE(JSVALUE32_64)
290             , m_deltaCallToTagLoadOrStore(deltaCallToTagLoadOrStore)
291             , m_deltaCallToPayloadLoadOrStore(deltaCallToPayloadLoadOrStore)
292 #endif
293             , m_deltaCallToSlowCase(deltaCallToSlowCase)
294             , m_deltaCallToDone(deltaCallToDone)
295             , m_baseGPR(baseGPR)
296 #if USE(JSVALUE32_64)
297             , m_valueTagGPR(valueTagGPR)
298 #endif
299             , m_valueGPR(valueGPR)
300             , m_scratchGPR(scratchGPR)
301         {
302         }
303
304         JITCompiler::Call m_functionCall;
305         int16_t m_deltaCheckImmToCall;
306         int16_t m_deltaCallToStructCheck;
307 #if USE(JSVALUE64)
308         int16_t m_deltaCallToLoadOrStore;
309 #elif USE(JSVALUE32_64)
310         int16_t m_deltaCallToTagLoadOrStore;
311         int16_t m_deltaCallToPayloadLoadOrStore;
312 #endif
313         int16_t m_deltaCallToSlowCase;
314         int16_t m_deltaCallToDone;
315         int8_t m_baseGPR;
316 #if USE(JSVALUE32_64)
317         int8_t m_valueTagGPR;
318 #endif
319         int8_t m_valueGPR;
320         int8_t m_scratchGPR;
321     };
322     
323     struct MethodGetRecord {
324         MethodGetRecord(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
325             : m_slowCall(slowCall)
326             , m_structToCompare(structToCompare)
327             , m_protoObj(protoObj)
328             , m_protoStructToCompare(protoStructToCompare)
329             , m_putFunction(putFunction)
330         {
331         }
332         
333         Call m_slowCall;
334         DataLabelPtr m_structToCompare;
335         DataLabelPtr m_protoObj;
336         DataLabelPtr m_protoStructToCompare;
337         DataLabelPtr m_putFunction;
338     };
339     
340     struct JSCallRecord {
341         JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, CodeOrigin codeOrigin)
342             : m_fastCall(fastCall)
343             , m_slowCall(slowCall)
344             , m_targetToCheck(targetToCheck)
345             , m_isCall(isCall)
346             , m_codeOrigin(codeOrigin)
347         {
348         }
349         
350         Call m_fastCall;
351         Call m_slowCall;
352         DataLabelPtr m_targetToCheck;
353         bool m_isCall;
354         CodeOrigin m_codeOrigin;
355     };
356
357     Vector<PropertyAccessRecord, 4> m_propertyAccesses;
358     Vector<MethodGetRecord, 4> m_methodGets;
359     Vector<JSCallRecord, 4> m_jsCalls;
360 };
361
362 } } // namespace JSC::DFG
363
364 #endif
365 #endif
366