]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGJITCompiler.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / dfg / DFGJITCompiler.h
1 /*
2 * Copyright (C) 2011, 2013 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 "CodeBlock.h"
32 #include "DFGCCallHelpers.h"
33 #include "DFGDisassembler.h"
34 #include "DFGFPRInfo.h"
35 #include "DFGGPRInfo.h"
36 #include "DFGGraph.h"
37 #include "DFGOSRExitCompilationInfo.h"
38 #include "DFGRegisterBank.h"
39 #include "DFGRegisterSet.h"
40 #include "JITCode.h"
41 #include "LinkBuffer.h"
42 #include "MacroAssembler.h"
43
44 namespace JSC {
45
46 class AbstractSamplingCounter;
47 class CodeBlock;
48 class VM;
49
50 namespace DFG {
51
52 class JITCodeGenerator;
53 class NodeToRegisterMap;
54 class OSRExitJumpPlaceholder;
55 class SlowPathGenerator;
56 class SpeculativeJIT;
57 class SpeculationRecovery;
58
59 struct EntryLocation;
60 struct OSRExit;
61
62 // === CallLinkRecord ===
63 //
64 // A record of a call out from JIT code that needs linking to a helper function.
65 // Every CallLinkRecord contains a reference to the call instruction & the function
66 // that it needs to be linked to.
67 struct CallLinkRecord {
68 CallLinkRecord(MacroAssembler::Call call, FunctionPtr function)
69 : m_call(call)
70 , m_function(function)
71 {
72 }
73
74 MacroAssembler::Call m_call;
75 FunctionPtr m_function;
76 };
77
78 class CallBeginToken {
79 public:
80 CallBeginToken()
81 #if !ASSERT_DISABLED
82 : m_registered(false)
83 , m_exceptionCheckIndex(std::numeric_limits<unsigned>::max())
84 #endif
85 {
86 }
87
88 ~CallBeginToken()
89 {
90 ASSERT(m_registered || !m_codeOrigin.isSet());
91 ASSERT(m_codeOrigin.isSet() == (m_exceptionCheckIndex != std::numeric_limits<unsigned>::max()));
92 }
93
94 void set(CodeOrigin codeOrigin, unsigned index)
95 {
96 #if !ASSERT_DISABLED
97 ASSERT(m_registered || !m_codeOrigin.isSet());
98 ASSERT(m_codeOrigin.isSet() == (m_exceptionCheckIndex != std::numeric_limits<unsigned>::max()));
99 m_codeOrigin = codeOrigin;
100 m_registered = false;
101 m_exceptionCheckIndex = index;
102 #else
103 UNUSED_PARAM(codeOrigin);
104 UNUSED_PARAM(index);
105 #endif
106 }
107
108 void registerWithExceptionCheck(CodeOrigin codeOrigin, unsigned index)
109 {
110 #if !ASSERT_DISABLED
111 ASSERT(m_codeOrigin == codeOrigin);
112 if (m_registered)
113 return;
114 ASSERT(m_exceptionCheckIndex == index);
115 m_registered = true;
116 #else
117 UNUSED_PARAM(codeOrigin);
118 UNUSED_PARAM(index);
119 #endif
120 }
121
122 #if !ASSERT_DISABLED
123 const CodeOrigin& codeOrigin() const
124 {
125 return m_codeOrigin;
126 }
127 #endif
128
129 private:
130 #if !ASSERT_DISABLED
131 CodeOrigin m_codeOrigin;
132 bool m_registered;
133 unsigned m_exceptionCheckIndex;
134 #endif
135 };
136
137 // === CallExceptionRecord ===
138 //
139 // A record of a call out from JIT code that might throw an exception.
140 // Calls that might throw an exception also record the Jump taken on exception
141 // (unset if not present) and code origin used to recover handler/source info.
142 struct CallExceptionRecord {
143 CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin)
144 : m_call(call)
145 , m_codeOrigin(codeOrigin)
146 {
147 }
148
149 CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin)
150 : m_call(call)
151 , m_exceptionCheck(exceptionCheck)
152 , m_codeOrigin(codeOrigin)
153 {
154 }
155
156 MacroAssembler::Call m_call;
157 MacroAssembler::Jump m_exceptionCheck;
158 CodeOrigin m_codeOrigin;
159 };
160
161 struct PropertyAccessRecord {
162 enum RegisterMode { RegistersFlushed, RegistersInUse };
163
164 #if USE(JSVALUE64)
165 PropertyAccessRecord(
166 CodeOrigin codeOrigin,
167 MacroAssembler::DataLabelPtr structureImm,
168 MacroAssembler::PatchableJump structureCheck,
169 MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
170 MacroAssembler::DataLabelCompact loadOrStore,
171 SlowPathGenerator* slowPathGenerator,
172 MacroAssembler::Label done,
173 int8_t baseGPR,
174 int8_t valueGPR,
175 const RegisterSet& usedRegisters,
176 RegisterMode registerMode = RegistersInUse)
177 #elif USE(JSVALUE32_64)
178 PropertyAccessRecord(
179 CodeOrigin codeOrigin,
180 MacroAssembler::DataLabelPtr structureImm,
181 MacroAssembler::PatchableJump structureCheck,
182 MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
183 MacroAssembler::DataLabelCompact tagLoadOrStore,
184 MacroAssembler::DataLabelCompact payloadLoadOrStore,
185 SlowPathGenerator* slowPathGenerator,
186 MacroAssembler::Label done,
187 int8_t baseGPR,
188 int8_t valueTagGPR,
189 int8_t valueGPR,
190 const RegisterSet& usedRegisters,
191 RegisterMode registerMode = RegistersInUse)
192 #endif
193 : m_codeOrigin(codeOrigin)
194 , m_structureImm(structureImm)
195 , m_structureCheck(structureCheck)
196 , m_propertyStorageLoad(propertyStorageLoad)
197 #if USE(JSVALUE64)
198 , m_loadOrStore(loadOrStore)
199 #elif USE(JSVALUE32_64)
200 , m_tagLoadOrStore(tagLoadOrStore)
201 , m_payloadLoadOrStore(payloadLoadOrStore)
202 #endif
203 , m_slowPathGenerator(slowPathGenerator)
204 , m_done(done)
205 , m_baseGPR(baseGPR)
206 #if USE(JSVALUE32_64)
207 , m_valueTagGPR(valueTagGPR)
208 #endif
209 , m_valueGPR(valueGPR)
210 , m_usedRegisters(usedRegisters)
211 , m_registerMode(registerMode)
212 {
213 }
214
215 CodeOrigin m_codeOrigin;
216 MacroAssembler::DataLabelPtr m_structureImm;
217 MacroAssembler::PatchableJump m_structureCheck;
218 MacroAssembler::ConvertibleLoadLabel m_propertyStorageLoad;
219 #if USE(JSVALUE64)
220 MacroAssembler::DataLabelCompact m_loadOrStore;
221 #elif USE(JSVALUE32_64)
222 MacroAssembler::DataLabelCompact m_tagLoadOrStore;
223 MacroAssembler::DataLabelCompact m_payloadLoadOrStore;
224 #endif
225 SlowPathGenerator* m_slowPathGenerator;
226 MacroAssembler::Label m_done;
227 int8_t m_baseGPR;
228 #if USE(JSVALUE32_64)
229 int8_t m_valueTagGPR;
230 #endif
231 int8_t m_valueGPR;
232 RegisterSet m_usedRegisters;
233 RegisterMode m_registerMode;
234 };
235
236 // === JITCompiler ===
237 //
238 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
239 // It does so by delegating to the speculative & non-speculative JITs, which
240 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
241 // relationship). The JITCompiler holds references to information required during
242 // compilation, and also records information used in linking (e.g. a list of all
243 // call to be linked).
244 class JITCompiler : public CCallHelpers {
245 public:
246 JITCompiler(Graph& dfg);
247
248 bool compile(JITCode& entry);
249 bool compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
250
251 // Accessors for properties.
252 Graph& graph() { return m_graph; }
253
254 // Methods to set labels for the disassembler.
255 void setStartOfCode()
256 {
257 if (LIKELY(!m_disassembler))
258 return;
259 m_disassembler->setStartOfCode(labelIgnoringWatchpoints());
260 }
261
262 void setForBlock(BlockIndex blockIndex)
263 {
264 if (LIKELY(!m_disassembler))
265 return;
266 m_disassembler->setForBlock(blockIndex, labelIgnoringWatchpoints());
267 }
268
269 void setForNode(Node* node)
270 {
271 if (LIKELY(!m_disassembler))
272 return;
273 m_disassembler->setForNode(node, labelIgnoringWatchpoints());
274 }
275
276 void setEndOfMainPath()
277 {
278 if (LIKELY(!m_disassembler))
279 return;
280 m_disassembler->setEndOfMainPath(labelIgnoringWatchpoints());
281 }
282
283 void setEndOfCode()
284 {
285 if (LIKELY(!m_disassembler))
286 return;
287 m_disassembler->setEndOfCode(labelIgnoringWatchpoints());
288 }
289
290 unsigned currentCodeOriginIndex() const
291 {
292 return m_currentCodeOriginIndex;
293 }
294
295 // Get a token for beginning a call, and set the current code origin index in
296 // the call frame. For each beginCall() there must be at least one exception
297 // check, and all of the exception checks must have the same CodeOrigin as the
298 // beginCall().
299 void beginCall(CodeOrigin codeOrigin, CallBeginToken& token)
300 {
301 unsigned index = m_exceptionChecks.size();
302 store32(TrustedImm32(index), tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
303 token.set(codeOrigin, index);
304 }
305
306 // Notify the JIT of a call that does not require linking.
307 void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token)
308 {
309 token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size());
310 m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin));
311 }
312
313 // Add a call out from JIT code, without an exception check.
314 Call appendCall(const FunctionPtr& function)
315 {
316 Call functionCall = call();
317 m_calls.append(CallLinkRecord(functionCall, function));
318 return functionCall;
319 }
320
321 void prepareForExceptionCheck()
322 {
323 move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR);
324 }
325
326 // Add a call out from JIT code, with an exception check.
327 void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token)
328 {
329 prepareForExceptionCheck();
330 token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size());
331 m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin));
332 }
333
334 // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
335 void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token)
336 {
337 prepareForExceptionCheck();
338 Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR);
339 token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size());
340 m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin));
341 }
342
343 void appendExitInfo(MacroAssembler::JumpList jumpsToFail = MacroAssembler::JumpList())
344 {
345 OSRExitCompilationInfo info;
346 info.m_failureJumps = jumpsToFail;
347 m_exitCompilationInfo.append(info);
348 }
349
350 #if USE(JSVALUE32_64)
351 void* addressOfDoubleConstant(Node* node)
352 {
353 ASSERT(m_graph.isNumberConstant(node));
354 unsigned constantIndex = node->constantNumber();
355 return &(codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex));
356 }
357 #endif
358
359 void addPropertyAccess(const PropertyAccessRecord& record)
360 {
361 m_propertyAccesses.append(record);
362 }
363
364 void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
365 {
366 m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, callType, callee, codeOrigin));
367 }
368
369 void addWeakReference(JSCell* target)
370 {
371 m_codeBlock->appendWeakReference(target);
372 }
373
374 void addWeakReferences(const StructureSet& structureSet)
375 {
376 for (unsigned i = structureSet.size(); i--;)
377 addWeakReference(structureSet[i]);
378 }
379
380 void addWeakReferenceTransition(JSCell* codeOrigin, JSCell* from, JSCell* to)
381 {
382 m_codeBlock->appendWeakReferenceTransition(codeOrigin, from, to);
383 }
384
385 template<typename T>
386 Jump branchWeakPtr(RelationalCondition cond, T left, JSCell* weakPtr)
387 {
388 Jump result = branchPtr(cond, left, TrustedImmPtr(weakPtr));
389 addWeakReference(weakPtr);
390 return result;
391 }
392
393 void noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer)
394 {
395 #if DFG_ENABLE(OSR_ENTRY)
396 // OSR entry is not allowed into blocks deemed unreachable by control flow analysis.
397 if (!basicBlock.cfaHasVisited)
398 return;
399
400 OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead));
401
402 entry->m_expectedValues = basicBlock.valuesAtHead;
403
404 // Fix the expected values: in our protocol, a dead variable will have an expected
405 // value of (None, []). But the old JIT may stash some values there. So we really
406 // need (Top, TOP).
407 for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) {
408 Node* node = basicBlock.variablesAtHead.argument(argument);
409 if (!node || !node->shouldGenerate())
410 entry->m_expectedValues.argument(argument).makeTop();
411 }
412 for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) {
413 Node* node = basicBlock.variablesAtHead.local(local);
414 if (!node || !node->shouldGenerate())
415 entry->m_expectedValues.local(local).makeTop();
416 else if (node->variableAccessData()->shouldUseDoubleFormat())
417 entry->m_localsForcedDouble.set(local);
418 }
419 #else
420 UNUSED_PARAM(basicBlock);
421 UNUSED_PARAM(blockHead);
422 UNUSED_PARAM(linkBuffer);
423 #endif
424 }
425
426 private:
427 friend class OSRExitJumpPlaceholder;
428
429 // Internal implementation to compile.
430 void compileEntry();
431 void compileBody(SpeculativeJIT&);
432 void link(LinkBuffer&);
433
434 void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*);
435 void compileExceptionHandlers();
436 void linkOSRExits();
437
438 // The dataflow graph currently being generated.
439 Graph& m_graph;
440
441 OwnPtr<Disassembler> m_disassembler;
442
443 // Vector of calls out from JIT code, including exception handler information.
444 // Count of the number of CallRecords with exception handlers.
445 Vector<CallLinkRecord> m_calls;
446 Vector<CallExceptionRecord> m_exceptionChecks;
447
448 struct JSCallRecord {
449 JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
450 : m_fastCall(fastCall)
451 , m_slowCall(slowCall)
452 , m_targetToCheck(targetToCheck)
453 , m_callType(callType)
454 , m_callee(callee)
455 , m_codeOrigin(codeOrigin)
456 {
457 }
458
459 Call m_fastCall;
460 Call m_slowCall;
461 DataLabelPtr m_targetToCheck;
462 CallLinkInfo::CallType m_callType;
463 GPRReg m_callee;
464 CodeOrigin m_codeOrigin;
465 };
466
467 Vector<PropertyAccessRecord, 4> m_propertyAccesses;
468 Vector<JSCallRecord, 4> m_jsCalls;
469 Vector<OSRExitCompilationInfo> m_exitCompilationInfo;
470 Vector<Vector<Label> > m_exitSiteLabels;
471 unsigned m_currentCodeOriginIndex;
472 };
473
474 } } // namespace JSC::DFG
475
476 #endif
477 #endif
478