]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - dfg/DFGJITCompiler.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / dfg / DFGJITCompiler.h
... / ...
CommitLineData
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/LinkBuffer.h>
32#include <assembler/MacroAssembler.h>
33#include <bytecode/CodeBlock.h>
34#include <dfg/DFGCCallHelpers.h>
35#include <dfg/DFGFPRInfo.h>
36#include <dfg/DFGGPRInfo.h>
37#include <dfg/DFGGraph.h>
38#include <dfg/DFGRegisterBank.h>
39#include <jit/JITCode.h>
40
41namespace JSC {
42
43class AbstractSamplingCounter;
44class CodeBlock;
45class JSGlobalData;
46
47namespace DFG {
48
49class JITCodeGenerator;
50class NodeToRegisterMap;
51class SpeculativeJIT;
52class SpeculationRecovery;
53
54struct EntryLocation;
55struct OSRExit;
56
57// === CallLinkRecord ===
58//
59// A record of a call out from JIT code that needs linking to a helper function.
60// Every CallLinkRecord contains a reference to the call instruction & the function
61// that it needs to be linked to.
62struct CallLinkRecord {
63 CallLinkRecord(MacroAssembler::Call call, FunctionPtr function)
64 : m_call(call)
65 , m_function(function)
66 {
67 }
68
69 MacroAssembler::Call m_call;
70 FunctionPtr m_function;
71};
72
73class CallBeginToken {
74public:
75 CallBeginToken()
76#if !ASSERT_DISABLED
77 : m_codeOriginIndex(UINT_MAX)
78#endif
79 {
80 }
81
82 explicit CallBeginToken(unsigned codeOriginIndex)
83#if !ASSERT_DISABLED
84 : m_codeOriginIndex(codeOriginIndex)
85#endif
86 {
87 UNUSED_PARAM(codeOriginIndex);
88 }
89
90 void assertCodeOriginIndex(unsigned codeOriginIndex) const
91 {
92 ASSERT_UNUSED(codeOriginIndex, codeOriginIndex < UINT_MAX);
93 ASSERT_UNUSED(codeOriginIndex, codeOriginIndex == m_codeOriginIndex);
94 }
95
96private:
97#if !ASSERT_DISABLED
98 unsigned m_codeOriginIndex;
99#endif
100};
101
102// === CallExceptionRecord ===
103//
104// A record of a call out from JIT code that might throw an exception.
105// Calls that might throw an exception also record the Jump taken on exception
106// (unset if not present) and code origin used to recover handler/source info.
107struct CallExceptionRecord {
108 CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin, CallBeginToken token)
109 : m_call(call)
110 , m_codeOrigin(codeOrigin)
111 , m_token(token)
112 {
113 }
114
115 CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin, CallBeginToken token)
116 : m_call(call)
117 , m_exceptionCheck(exceptionCheck)
118 , m_codeOrigin(codeOrigin)
119 , m_token(token)
120 {
121 }
122
123 MacroAssembler::Call m_call;
124 MacroAssembler::Jump m_exceptionCheck;
125 CodeOrigin m_codeOrigin;
126 CallBeginToken m_token;
127};
128
129struct PropertyAccessRecord {
130 enum RegisterMode { RegistersFlushed, RegistersInUse };
131
132#if USE(JSVALUE64)
133 PropertyAccessRecord(CodeOrigin codeOrigin, MacroAssembler::DataLabelPtr deltaCheckImmToCall, MacroAssembler::Call functionCall, MacroAssembler::PatchableJump deltaCallToStructCheck, MacroAssembler::DataLabelCompact deltaCallToLoadOrStore, MacroAssembler::Label deltaCallToSlowCase, MacroAssembler::Label deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR, RegisterMode registerMode = RegistersInUse)
134#elif USE(JSVALUE32_64)
135 PropertyAccessRecord(CodeOrigin codeOrigin, MacroAssembler::DataLabelPtr deltaCheckImmToCall, MacroAssembler::Call functionCall, MacroAssembler::PatchableJump deltaCallToStructCheck, MacroAssembler::DataLabelCompact deltaCallToTagLoadOrStore, MacroAssembler::DataLabelCompact deltaCallToPayloadLoadOrStore, MacroAssembler::Label deltaCallToSlowCase, MacroAssembler::Label deltaCallToDone, int8_t baseGPR, int8_t valueTagGPR, int8_t valueGPR, int8_t scratchGPR, RegisterMode registerMode = RegistersInUse)
136#endif
137 : m_codeOrigin(codeOrigin)
138 , m_deltaCheckImmToCall(deltaCheckImmToCall)
139 , m_functionCall(functionCall)
140 , m_deltaCallToStructCheck(deltaCallToStructCheck)
141#if USE(JSVALUE64)
142 , m_deltaCallToLoadOrStore(deltaCallToLoadOrStore)
143#elif USE(JSVALUE32_64)
144 , m_deltaCallToTagLoadOrStore(deltaCallToTagLoadOrStore)
145 , m_deltaCallToPayloadLoadOrStore(deltaCallToPayloadLoadOrStore)
146#endif
147 , m_deltaCallToSlowCase(deltaCallToSlowCase)
148 , m_deltaCallToDone(deltaCallToDone)
149 , m_baseGPR(baseGPR)
150#if USE(JSVALUE32_64)
151 , m_valueTagGPR(valueTagGPR)
152#endif
153 , m_valueGPR(valueGPR)
154 , m_scratchGPR(scratchGPR)
155 , m_registerMode(registerMode)
156 {
157 }
158
159 CodeOrigin m_codeOrigin;
160 MacroAssembler::DataLabelPtr m_deltaCheckImmToCall;
161 MacroAssembler::Call m_functionCall;
162 MacroAssembler::PatchableJump m_deltaCallToStructCheck;
163#if USE(JSVALUE64)
164 MacroAssembler::DataLabelCompact m_deltaCallToLoadOrStore;
165#elif USE(JSVALUE32_64)
166 MacroAssembler::DataLabelCompact m_deltaCallToTagLoadOrStore;
167 MacroAssembler::DataLabelCompact m_deltaCallToPayloadLoadOrStore;
168#endif
169 MacroAssembler::Label m_deltaCallToSlowCase;
170 MacroAssembler::Label m_deltaCallToDone;
171 int8_t m_baseGPR;
172#if USE(JSVALUE32_64)
173 int8_t m_valueTagGPR;
174#endif
175 int8_t m_valueGPR;
176 int8_t m_scratchGPR;
177 RegisterMode m_registerMode;
178};
179
180// === JITCompiler ===
181//
182// DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
183// It does so by delegating to the speculative & non-speculative JITs, which
184// generate to a MacroAssembler (which the JITCompiler owns through an inheritance
185// relationship). The JITCompiler holds references to information required during
186// compilation, and also records information used in linking (e.g. a list of all
187// call to be linked).
188class JITCompiler : public CCallHelpers {
189public:
190 JITCompiler(Graph& dfg)
191 : CCallHelpers(&dfg.m_globalData, dfg.m_codeBlock)
192 , m_graph(dfg)
193 , m_currentCodeOriginIndex(0)
194 {
195 }
196
197 bool compile(JITCode& entry);
198 bool compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
199
200 // Accessors for properties.
201 Graph& graph() { return m_graph; }
202
203 // Get a token for beginning a call, and set the current code origin index in
204 // the call frame.
205 CallBeginToken beginCall()
206 {
207 unsigned codeOriginIndex = m_currentCodeOriginIndex++;
208 store32(TrustedImm32(codeOriginIndex), tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount)));
209 return CallBeginToken(codeOriginIndex);
210 }
211
212 // Notify the JIT of a call that does not require linking.
213 void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token)
214 {
215 m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin, token));
216 }
217
218 // Add a call out from JIT code, without an exception check.
219 Call appendCall(const FunctionPtr& function)
220 {
221 Call functionCall = call();
222 m_calls.append(CallLinkRecord(functionCall, function));
223 return functionCall;
224 }
225
226 // Add a call out from JIT code, with an exception check.
227 void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token)
228 {
229 move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR);
230 m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin, token));
231 }
232
233 // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
234 void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token)
235 {
236 move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR);
237 Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR);
238 m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin, token));
239 }
240
241 // Helper methods to get predictions
242 PredictedType getPrediction(Node& node) { return node.prediction(); }
243 PredictedType getPrediction(NodeIndex nodeIndex) { return getPrediction(graph()[nodeIndex]); }
244 PredictedType getPrediction(Edge nodeUse) { return getPrediction(nodeUse.index()); }
245
246#if USE(JSVALUE32_64)
247 void* addressOfDoubleConstant(NodeIndex nodeIndex)
248 {
249 ASSERT(m_graph.isNumberConstant(nodeIndex));
250 unsigned constantIndex = graph()[nodeIndex].constantNumber();
251 return &(codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex));
252 }
253#endif
254
255 void addPropertyAccess(const PropertyAccessRecord& record)
256 {
257 m_propertyAccesses.append(record);
258 }
259
260 void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, CodeOrigin codeOrigin)
261 {
262 m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, callType, codeOrigin));
263 }
264
265 void addWeakReference(JSCell* target)
266 {
267 m_codeBlock->appendWeakReference(target);
268 }
269
270 void addWeakReferenceTransition(JSCell* codeOrigin, JSCell* from, JSCell* to)
271 {
272 m_codeBlock->appendWeakReferenceTransition(codeOrigin, from, to);
273 }
274
275 template<typename T>
276 Jump branchWeakPtr(RelationalCondition cond, T left, JSCell* weakPtr)
277 {
278 Jump result = branchPtr(cond, left, TrustedImmPtr(weakPtr));
279 addWeakReference(weakPtr);
280 return result;
281 }
282
283 void noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer)
284 {
285#if DFG_ENABLE(OSR_ENTRY)
286 OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead));
287
288 entry->m_expectedValues = basicBlock.valuesAtHead;
289
290 // Fix the expected values: in our protocol, a dead variable will have an expected
291 // value of (None, []). But the old JIT may stash some values there. So we really
292 // need (Top, TOP).
293 for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) {
294 NodeIndex nodeIndex = basicBlock.variablesAtHead.argument(argument);
295 if (nodeIndex == NoNode || !m_graph[nodeIndex].shouldGenerate())
296 entry->m_expectedValues.argument(argument).makeTop();
297 }
298 for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) {
299 NodeIndex nodeIndex = basicBlock.variablesAtHead.local(local);
300 if (nodeIndex == NoNode || !m_graph[nodeIndex].shouldGenerate())
301 entry->m_expectedValues.local(local).makeTop();
302 else if (m_graph[nodeIndex].variableAccessData()->shouldUseDoubleFormat())
303 entry->m_localsForcedDouble.set(local);
304 }
305#else
306 UNUSED_PARAM(basicBlock);
307 UNUSED_PARAM(blockHead);
308 UNUSED_PARAM(linkBuffer);
309#endif
310 }
311
312private:
313 // Internal implementation to compile.
314 void compileEntry();
315 void compileBody(SpeculativeJIT&);
316 void link(LinkBuffer&);
317
318 void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*);
319 void linkOSRExits();
320
321 // The dataflow graph currently being generated.
322 Graph& m_graph;
323
324 // Vector of calls out from JIT code, including exception handler information.
325 // Count of the number of CallRecords with exception handlers.
326 Vector<CallLinkRecord> m_calls;
327 Vector<CallExceptionRecord> m_exceptionChecks;
328
329 struct JSCallRecord {
330 JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, CodeOrigin codeOrigin)
331 : m_fastCall(fastCall)
332 , m_slowCall(slowCall)
333 , m_targetToCheck(targetToCheck)
334 , m_callType(callType)
335 , m_codeOrigin(codeOrigin)
336 {
337 }
338
339 Call m_fastCall;
340 Call m_slowCall;
341 DataLabelPtr m_targetToCheck;
342 CallLinkInfo::CallType m_callType;
343 CodeOrigin m_codeOrigin;
344 };
345
346 Vector<PropertyAccessRecord, 4> m_propertyAccesses;
347 Vector<JSCallRecord, 4> m_jsCalls;
348 unsigned m_currentCodeOriginIndex;
349};
350
351} } // namespace JSC::DFG
352
353#endif
354#endif
355