]>
Commit | Line | Data |
---|---|---|
14957cd0 | 1 | /* |
81345200 | 2 | * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. |
14957cd0 A |
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 | ||
81345200 | 31 | #include "CCallHelpers.h" |
93a37866 | 32 | #include "CodeBlock.h" |
93a37866 | 33 | #include "DFGDisassembler.h" |
93a37866 | 34 | #include "DFGGraph.h" |
81345200 A |
35 | #include "DFGInlineCacheWrapper.h" |
36 | #include "DFGJITCode.h" | |
93a37866 A |
37 | #include "DFGOSRExitCompilationInfo.h" |
38 | #include "DFGRegisterBank.h" | |
81345200 A |
39 | #include "FPRInfo.h" |
40 | #include "GPRInfo.h" | |
93a37866 | 41 | #include "JITCode.h" |
81345200 | 42 | #include "JITInlineCacheGenerator.h" |
93a37866 A |
43 | #include "LinkBuffer.h" |
44 | #include "MacroAssembler.h" | |
81345200 | 45 | #include "TempRegisterSet.h" |
14957cd0 | 46 | |
14957cd0 A |
47 | namespace JSC { |
48 | ||
49 | class AbstractSamplingCounter; | |
50 | class CodeBlock; | |
93a37866 | 51 | class VM; |
14957cd0 A |
52 | |
53 | namespace DFG { | |
54 | ||
55 | class JITCodeGenerator; | |
6fe7ccc8 | 56 | class NodeToRegisterMap; |
93a37866 A |
57 | class OSRExitJumpPlaceholder; |
58 | class SlowPathGenerator; | |
14957cd0 A |
59 | class SpeculativeJIT; |
60 | class SpeculationRecovery; | |
61 | ||
62 | struct EntryLocation; | |
6fe7ccc8 | 63 | struct OSRExit; |
14957cd0 | 64 | |
6fe7ccc8 | 65 | // === CallLinkRecord === |
14957cd0 | 66 | // |
6fe7ccc8 A |
67 | // A record of a call out from JIT code that needs linking to a helper function. |
68 | // Every CallLinkRecord contains a reference to the call instruction & the function | |
69 | // that it needs to be linked to. | |
70 | struct CallLinkRecord { | |
71 | CallLinkRecord(MacroAssembler::Call call, FunctionPtr function) | |
14957cd0 A |
72 | : m_call(call) |
73 | , m_function(function) | |
74 | { | |
75 | } | |
76 | ||
6fe7ccc8 A |
77 | MacroAssembler::Call m_call; |
78 | FunctionPtr m_function; | |
79 | }; | |
80 | ||
81345200 A |
81 | struct InRecord { |
82 | InRecord( | |
83 | MacroAssembler::PatchableJump jump, MacroAssembler::Label done, | |
84 | SlowPathGenerator* slowPathGenerator, StructureStubInfo* stubInfo) | |
85 | : m_jump(jump) | |
93a37866 | 86 | , m_done(done) |
81345200 A |
87 | , m_slowPathGenerator(slowPathGenerator) |
88 | , m_stubInfo(stubInfo) | |
6fe7ccc8 A |
89 | { |
90 | } | |
81345200 A |
91 | |
92 | MacroAssembler::PatchableJump m_jump; | |
93a37866 | 93 | MacroAssembler::Label m_done; |
81345200 A |
94 | SlowPathGenerator* m_slowPathGenerator; |
95 | StructureStubInfo* m_stubInfo; | |
14957cd0 A |
96 | }; |
97 | ||
98 | // === JITCompiler === | |
99 | // | |
100 | // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph. | |
101 | // It does so by delegating to the speculative & non-speculative JITs, which | |
102 | // generate to a MacroAssembler (which the JITCompiler owns through an inheritance | |
103 | // relationship). The JITCompiler holds references to information required during | |
104 | // compilation, and also records information used in linking (e.g. a list of all | |
105 | // call to be linked). | |
6fe7ccc8 | 106 | class JITCompiler : public CCallHelpers { |
14957cd0 | 107 | public: |
93a37866 | 108 | JITCompiler(Graph& dfg); |
81345200 | 109 | ~JITCompiler(); |
93a37866 | 110 | |
81345200 A |
111 | void compile(); |
112 | void compileFunction(); | |
113 | ||
114 | void link(); | |
115 | void linkFunction(); | |
14957cd0 A |
116 | |
117 | // Accessors for properties. | |
118 | Graph& graph() { return m_graph; } | |
6fe7ccc8 | 119 | |
93a37866 A |
120 | // Methods to set labels for the disassembler. |
121 | void setStartOfCode() | |
122 | { | |
123 | if (LIKELY(!m_disassembler)) | |
124 | return; | |
125 | m_disassembler->setStartOfCode(labelIgnoringWatchpoints()); | |
126 | } | |
127 | ||
81345200 | 128 | void setForBlockIndex(BlockIndex blockIndex) |
93a37866 A |
129 | { |
130 | if (LIKELY(!m_disassembler)) | |
131 | return; | |
81345200 | 132 | m_disassembler->setForBlockIndex(blockIndex, labelIgnoringWatchpoints()); |
93a37866 A |
133 | } |
134 | ||
135 | void setForNode(Node* node) | |
136 | { | |
137 | if (LIKELY(!m_disassembler)) | |
138 | return; | |
139 | m_disassembler->setForNode(node, labelIgnoringWatchpoints()); | |
140 | } | |
141 | ||
142 | void setEndOfMainPath() | |
143 | { | |
144 | if (LIKELY(!m_disassembler)) | |
145 | return; | |
146 | m_disassembler->setEndOfMainPath(labelIgnoringWatchpoints()); | |
147 | } | |
148 | ||
149 | void setEndOfCode() | |
150 | { | |
151 | if (LIKELY(!m_disassembler)) | |
152 | return; | |
153 | m_disassembler->setEndOfCode(labelIgnoringWatchpoints()); | |
154 | } | |
155 | ||
81345200 | 156 | void emitStoreCodeOrigin(CodeOrigin codeOrigin) |
14957cd0 | 157 | { |
81345200 A |
158 | unsigned index = m_jitCode->common.addCodeOrigin(codeOrigin); |
159 | unsigned locationBits = CallFrame::Location::encodeAsCodeOriginIndex(index); | |
160 | store32(TrustedImm32(locationBits), tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount))); | |
14957cd0 A |
161 | } |
162 | ||
6fe7ccc8 A |
163 | // Add a call out from JIT code, without an exception check. |
164 | Call appendCall(const FunctionPtr& function) | |
14957cd0 | 165 | { |
6fe7ccc8 A |
166 | Call functionCall = call(); |
167 | m_calls.append(CallLinkRecord(functionCall, function)); | |
168 | return functionCall; | |
14957cd0 | 169 | } |
93a37866 | 170 | |
81345200 | 171 | void exceptionCheck(Jump jumpToHandler) |
93a37866 | 172 | { |
81345200 A |
173 | m_exceptionChecks.append(jumpToHandler); |
174 | } | |
175 | ||
176 | void exceptionCheck() | |
177 | { | |
178 | m_exceptionChecks.append(emitExceptionCheck()); | |
93a37866 | 179 | } |
14957cd0 | 180 | |
81345200 | 181 | void exceptionCheckWithCallFrameRollback() |
14957cd0 | 182 | { |
81345200 | 183 | m_exceptionChecksWithCallFrameRollback.append(emitExceptionCheck()); |
14957cd0 | 184 | } |
81345200 | 185 | |
6fe7ccc8 | 186 | // Add a call out from JIT code, with a fast exception check that tests if the return value is zero. |
81345200 | 187 | void fastExceptionCheck() |
14957cd0 | 188 | { |
81345200 A |
189 | callExceptionFuzz(); |
190 | m_exceptionChecks.append(branchTestPtr(Zero, GPRInfo::returnValueGPR)); | |
14957cd0 | 191 | } |
6fe7ccc8 | 192 | |
81345200 | 193 | OSRExitCompilationInfo& appendExitInfo(MacroAssembler::JumpList jumpsToFail = MacroAssembler::JumpList()) |
93a37866 A |
194 | { |
195 | OSRExitCompilationInfo info; | |
196 | info.m_failureJumps = jumpsToFail; | |
197 | m_exitCompilationInfo.append(info); | |
81345200 | 198 | return m_exitCompilationInfo.last(); |
93a37866 | 199 | } |
6fe7ccc8 A |
200 | |
201 | #if USE(JSVALUE32_64) | |
81345200 A |
202 | void* addressOfDoubleConstant(Node*); |
203 | #endif | |
204 | ||
205 | void addGetById(const JITGetByIdGenerator& gen, SlowPathGenerator* slowPath) | |
14957cd0 | 206 | { |
81345200 A |
207 | m_getByIds.append(InlineCacheWrapper<JITGetByIdGenerator>(gen, slowPath)); |
208 | } | |
209 | ||
210 | void addPutById(const JITPutByIdGenerator& gen, SlowPathGenerator* slowPath) | |
211 | { | |
212 | m_putByIds.append(InlineCacheWrapper<JITPutByIdGenerator>(gen, slowPath)); | |
14957cd0 | 213 | } |
14957cd0 | 214 | |
81345200 | 215 | void addIn(const InRecord& record) |
14957cd0 | 216 | { |
81345200 A |
217 | m_ins.append(record); |
218 | } | |
219 | ||
220 | unsigned currentJSCallIndex() const | |
221 | { | |
222 | return m_jsCalls.size(); | |
14957cd0 A |
223 | } |
224 | ||
81345200 | 225 | void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo* info) |
14957cd0 | 226 | { |
81345200 | 227 | m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, info)); |
14957cd0 | 228 | } |
6fe7ccc8 A |
229 | |
230 | void addWeakReference(JSCell* target) | |
14957cd0 | 231 | { |
81345200 | 232 | m_graph.m_plan.weakReferences.addLazily(target); |
14957cd0 | 233 | } |
6fe7ccc8 | 234 | |
93a37866 A |
235 | void addWeakReferences(const StructureSet& structureSet) |
236 | { | |
237 | for (unsigned i = structureSet.size(); i--;) | |
238 | addWeakReference(structureSet[i]); | |
239 | } | |
240 | ||
6fe7ccc8 A |
241 | template<typename T> |
242 | Jump branchWeakPtr(RelationalCondition cond, T left, JSCell* weakPtr) | |
14957cd0 | 243 | { |
6fe7ccc8 A |
244 | Jump result = branchPtr(cond, left, TrustedImmPtr(weakPtr)); |
245 | addWeakReference(weakPtr); | |
246 | return result; | |
14957cd0 | 247 | } |
81345200 A |
248 | |
249 | template<typename T> | |
250 | Jump branchWeakStructure(RelationalCondition cond, T left, Structure* weakStructure) | |
251 | { | |
252 | #if USE(JSVALUE64) | |
253 | Jump result = branch32(cond, left, TrustedImm32(weakStructure->id())); | |
254 | addWeakReference(weakStructure); | |
255 | return result; | |
256 | #else | |
257 | return branchWeakPtr(cond, left, weakStructure); | |
258 | #endif | |
259 | } | |
260 | ||
261 | template<typename T> | |
262 | Jump branchStructurePtr(RelationalCondition cond, T left, Structure* structure) | |
263 | { | |
264 | #if USE(JSVALUE64) | |
265 | return branch32(cond, left, TrustedImm32(structure->id())); | |
266 | #else | |
267 | return branchPtr(cond, left, TrustedImmPtr(structure)); | |
268 | #endif | |
269 | } | |
270 | ||
6fe7ccc8 | 271 | void noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer) |
14957cd0 | 272 | { |
93a37866 A |
273 | // OSR entry is not allowed into blocks deemed unreachable by control flow analysis. |
274 | if (!basicBlock.cfaHasVisited) | |
275 | return; | |
276 | ||
81345200 | 277 | OSREntryData* entry = m_jitCode->appendOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead)); |
6fe7ccc8 A |
278 | |
279 | entry->m_expectedValues = basicBlock.valuesAtHead; | |
280 | ||
281 | // Fix the expected values: in our protocol, a dead variable will have an expected | |
282 | // value of (None, []). But the old JIT may stash some values there. So we really | |
283 | // need (Top, TOP). | |
284 | for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) { | |
93a37866 A |
285 | Node* node = basicBlock.variablesAtHead.argument(argument); |
286 | if (!node || !node->shouldGenerate()) | |
81345200 | 287 | entry->m_expectedValues.argument(argument).makeHeapTop(); |
6fe7ccc8 A |
288 | } |
289 | for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) { | |
93a37866 A |
290 | Node* node = basicBlock.variablesAtHead.local(local); |
291 | if (!node || !node->shouldGenerate()) | |
81345200 A |
292 | entry->m_expectedValues.local(local).makeHeapTop(); |
293 | else { | |
294 | VariableAccessData* variable = node->variableAccessData(); | |
295 | entry->m_machineStackUsed.set(variable->machineLocal().toLocal()); | |
296 | ||
297 | switch (variable->flushFormat()) { | |
298 | case FlushedDouble: | |
299 | entry->m_localsForcedDouble.set(local); | |
300 | break; | |
301 | case FlushedInt52: | |
302 | entry->m_localsForcedMachineInt.set(local); | |
303 | break; | |
304 | default: | |
305 | break; | |
306 | } | |
307 | ||
308 | if (variable->local() != variable->machineLocal()) { | |
309 | entry->m_reshufflings.append( | |
310 | OSREntryReshuffling( | |
311 | variable->local().offset(), variable->machineLocal().offset())); | |
312 | } | |
313 | } | |
6fe7ccc8 | 314 | } |
81345200 A |
315 | |
316 | entry->m_reshufflings.shrinkToFit(); | |
6fe7ccc8 | 317 | } |
81345200 A |
318 | |
319 | PassRefPtr<JITCode> jitCode() { return m_jitCode; } | |
320 | ||
321 | Vector<Label>& blockHeads() { return m_blockHeads; } | |
14957cd0 A |
322 | |
323 | private: | |
93a37866 A |
324 | friend class OSRExitJumpPlaceholder; |
325 | ||
6fe7ccc8 A |
326 | // Internal implementation to compile. |
327 | void compileEntry(); | |
81345200 | 328 | void compileBody(); |
6fe7ccc8 | 329 | void link(LinkBuffer&); |
81345200 | 330 | |
6fe7ccc8 | 331 | void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*); |
93a37866 | 332 | void compileExceptionHandlers(); |
6fe7ccc8 | 333 | void linkOSRExits(); |
81345200 | 334 | void disassemble(LinkBuffer&); |
6fe7ccc8 | 335 | |
14957cd0 A |
336 | // The dataflow graph currently being generated. |
337 | Graph& m_graph; | |
338 | ||
93a37866 A |
339 | OwnPtr<Disassembler> m_disassembler; |
340 | ||
81345200 A |
341 | RefPtr<JITCode> m_jitCode; |
342 | ||
14957cd0 | 343 | // Vector of calls out from JIT code, including exception handler information. |
6fe7ccc8 A |
344 | // Count of the number of CallRecords with exception handlers. |
345 | Vector<CallLinkRecord> m_calls; | |
81345200 A |
346 | JumpList m_exceptionChecks; |
347 | JumpList m_exceptionChecksWithCallFrameRollback; | |
6fe7ccc8 | 348 | |
81345200 A |
349 | Vector<Label> m_blockHeads; |
350 | ||
6fe7ccc8 | 351 | struct JSCallRecord { |
81345200 | 352 | JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo* info) |
6fe7ccc8 A |
353 | : m_fastCall(fastCall) |
354 | , m_slowCall(slowCall) | |
355 | , m_targetToCheck(targetToCheck) | |
81345200 | 356 | , m_info(info) |
6fe7ccc8 A |
357 | { |
358 | } | |
359 | ||
360 | Call m_fastCall; | |
361 | Call m_slowCall; | |
362 | DataLabelPtr m_targetToCheck; | |
81345200 | 363 | CallLinkInfo* m_info; |
6fe7ccc8 A |
364 | }; |
365 | ||
81345200 A |
366 | Vector<InlineCacheWrapper<JITGetByIdGenerator>, 4> m_getByIds; |
367 | Vector<InlineCacheWrapper<JITPutByIdGenerator>, 4> m_putByIds; | |
368 | Vector<InRecord, 4> m_ins; | |
6fe7ccc8 | 369 | Vector<JSCallRecord, 4> m_jsCalls; |
81345200 A |
370 | SegmentedVector<OSRExitCompilationInfo, 4> m_exitCompilationInfo; |
371 | Vector<Vector<Label>> m_exitSiteLabels; | |
372 | ||
373 | Call m_callArityFixup; | |
374 | Label m_arityCheck; | |
375 | OwnPtr<SpeculativeJIT> m_speculative; | |
14957cd0 A |
376 | }; |
377 | ||
378 | } } // namespace JSC::DFG | |
379 | ||
380 | #endif | |
381 | #endif | |
382 |