]>
Commit | Line | Data |
---|---|---|
14957cd0 | 1 | /* |
93a37866 | 2 | * Copyright (C) 2011, 2013 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 | #include "config.h" | |
27 | #include "DFGJITCompiler.h" | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "CodeBlock.h" | |
6fe7ccc8 | 32 | #include "DFGOSRExitCompiler.h" |
14957cd0 A |
33 | #include "DFGOperations.h" |
34 | #include "DFGRegisterBank.h" | |
93a37866 | 35 | #include "DFGSlowPathGenerator.h" |
14957cd0 | 36 | #include "DFGSpeculativeJIT.h" |
6fe7ccc8 | 37 | #include "DFGThunks.h" |
93a37866 A |
38 | #include "JSCJSValueInlines.h" |
39 | #include "VM.h" | |
14957cd0 A |
40 | #include "LinkBuffer.h" |
41 | ||
42 | namespace JSC { namespace DFG { | |
43 | ||
93a37866 A |
44 | JITCompiler::JITCompiler(Graph& dfg) |
45 | : CCallHelpers(&dfg.m_vm, dfg.m_codeBlock) | |
46 | , m_graph(dfg) | |
47 | , m_currentCodeOriginIndex(0) | |
48 | { | |
49 | if (shouldShowDisassembly() || m_graph.m_vm.m_perBytecodeProfiler) | |
50 | m_disassembler = adoptPtr(new Disassembler(dfg)); | |
51 | } | |
52 | ||
6fe7ccc8 | 53 | void JITCompiler::linkOSRExits() |
14957cd0 | 54 | { |
93a37866 A |
55 | ASSERT(codeBlock()->numberOfOSRExits() == m_exitCompilationInfo.size()); |
56 | if (m_graph.m_compilation) { | |
57 | for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) { | |
58 | OSRExit& exit = codeBlock()->osrExit(i); | |
59 | Vector<Label> labels; | |
60 | if (exit.m_watchpointIndex == std::numeric_limits<unsigned>::max()) { | |
61 | OSRExitCompilationInfo& info = m_exitCompilationInfo[i]; | |
62 | for (unsigned j = 0; j < info.m_failureJumps.jumps().size(); ++j) | |
63 | labels.append(info.m_failureJumps.jumps()[j].label()); | |
64 | } else | |
65 | labels.append(codeBlock()->watchpoint(exit.m_watchpointIndex).sourceLabel()); | |
66 | m_exitSiteLabels.append(labels); | |
67 | } | |
68 | } | |
69 | ||
6fe7ccc8 A |
70 | for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) { |
71 | OSRExit& exit = codeBlock()->osrExit(i); | |
93a37866 A |
72 | JumpList& failureJumps = m_exitCompilationInfo[i].m_failureJumps; |
73 | ASSERT(failureJumps.empty() == (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max())); | |
74 | if (exit.m_watchpointIndex == std::numeric_limits<unsigned>::max()) | |
75 | failureJumps.link(this); | |
76 | else | |
77 | codeBlock()->watchpoint(exit.m_watchpointIndex).setDestination(label()); | |
6fe7ccc8 | 78 | jitAssertHasValidCallFrame(); |
93a37866 A |
79 | store32(TrustedImm32(i), &vm()->osrExitIndex); |
80 | exit.setPatchableCodeOffset(patchableJump()); | |
14957cd0 A |
81 | } |
82 | } | |
83 | ||
6fe7ccc8 | 84 | void JITCompiler::compileEntry() |
14957cd0 | 85 | { |
6fe7ccc8 A |
86 | // This code currently matches the old JIT. In the function header we need to |
87 | // pop the return address (since we do not allow any recursion on the machine | |
93a37866 | 88 | // stack), and perform a fast stack check. |
6fe7ccc8 | 89 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292 |
93a37866 | 90 | // We'll need to convert the remaining cti_ style calls (specifically the stack |
6fe7ccc8 A |
91 | // check) which will be dependent on stack layout. (We'd need to account for this in |
92 | // both normal return code and when jumping to an exception handler). | |
93 | preserveReturnAddressAfterCall(GPRInfo::regT2); | |
93a37866 A |
94 | emitPutToCallFrameHeader(GPRInfo::regT2, JSStack::ReturnPC); |
95 | emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock); | |
14957cd0 A |
96 | } |
97 | ||
6fe7ccc8 | 98 | void JITCompiler::compileBody(SpeculativeJIT& speculative) |
14957cd0 | 99 | { |
6fe7ccc8 A |
100 | // We generate the speculative code path, followed by OSR exit code to return |
101 | // to the old JIT code if speculations fail. | |
14957cd0 | 102 | |
6fe7ccc8 A |
103 | #if DFG_ENABLE(JIT_BREAK_ON_EVERY_FUNCTION) |
104 | // Handy debug tool! | |
105 | breakpoint(); | |
106 | #endif | |
107 | ||
6fe7ccc8 A |
108 | bool compiledSpeculative = speculative.compile(); |
109 | ASSERT_UNUSED(compiledSpeculative, compiledSpeculative); | |
93a37866 | 110 | } |
14957cd0 | 111 | |
93a37866 A |
112 | void JITCompiler::compileExceptionHandlers() |
113 | { | |
6fe7ccc8 A |
114 | // Iterate over the m_calls vector, checking for jumps to link. |
115 | bool didLinkExceptionCheck = false; | |
116 | for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { | |
117 | Jump& exceptionCheck = m_exceptionChecks[i].m_exceptionCheck; | |
118 | if (exceptionCheck.isSet()) { | |
119 | exceptionCheck.link(this); | |
120 | didLinkExceptionCheck = true; | |
121 | } | |
122 | } | |
14957cd0 | 123 | |
6fe7ccc8 A |
124 | // If any exception checks were linked, generate code to lookup a handler. |
125 | if (didLinkExceptionCheck) { | |
126 | // lookupExceptionHandler is passed two arguments, exec (the CallFrame*), and | |
127 | // the index into the CodeBlock's callReturnIndexVector corresponding to the | |
128 | // call that threw the exception (this was set in nonPreservedNonReturnGPR, when | |
129 | // the exception check was planted). | |
130 | move(GPRInfo::nonPreservedNonReturnGPR, GPRInfo::argumentGPR1); | |
131 | move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); | |
132 | #if CPU(X86) | |
133 | // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! | |
134 | poke(GPRInfo::argumentGPR0); | |
135 | poke(GPRInfo::argumentGPR1, 1); | |
136 | #endif | |
137 | m_calls.append(CallLinkRecord(call(), lookupExceptionHandler)); | |
138 | // lookupExceptionHandler leaves the handler CallFrame* in the returnValueGPR, | |
139 | // and the address of the handler in returnValueGPR2. | |
140 | jump(GPRInfo::returnValueGPR2); | |
14957cd0 | 141 | } |
6fe7ccc8 | 142 | } |
14957cd0 | 143 | |
6fe7ccc8 A |
144 | void JITCompiler::link(LinkBuffer& linkBuffer) |
145 | { | |
146 | // Link the code, populate data in CodeBlock data structures. | |
147 | #if DFG_ENABLE(DEBUG_VERBOSE) | |
93a37866 | 148 | dataLogF("JIT code for %p start at [%p, %p). Size = %zu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize()); |
6fe7ccc8 | 149 | #endif |
14957cd0 | 150 | |
6fe7ccc8 A |
151 | // Link all calls out from the JIT code to their respective functions. |
152 | for (unsigned i = 0; i < m_calls.size(); ++i) | |
153 | linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function); | |
14957cd0 | 154 | |
93a37866 A |
155 | m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionChecks.size()); |
156 | for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { | |
157 | unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); | |
158 | CodeOrigin codeOrigin = m_exceptionChecks[i].m_codeOrigin; | |
159 | while (codeOrigin.inlineCallFrame) | |
160 | codeOrigin = codeOrigin.inlineCallFrame->caller; | |
161 | unsigned exceptionInfo = codeOrigin.bytecodeIndex; | |
162 | m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo)); | |
14957cd0 A |
163 | } |
164 | ||
93a37866 | 165 | Vector<CodeOriginAtCallReturnOffset, 0, UnsafeVectorOverflow>& codeOrigins = m_codeBlock->codeOrigins(); |
6fe7ccc8 A |
166 | codeOrigins.resize(m_exceptionChecks.size()); |
167 | ||
168 | for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { | |
169 | CallExceptionRecord& record = m_exceptionChecks[i]; | |
170 | unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); | |
171 | codeOrigins[i].codeOrigin = record.m_codeOrigin; | |
172 | codeOrigins[i].callReturnOffset = returnAddressOffset; | |
6fe7ccc8 A |
173 | } |
174 | ||
175 | m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size()); | |
176 | for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) { | |
177 | StructureStubInfo& info = m_codeBlock->structureStubInfo(i); | |
93a37866 | 178 | CodeLocationCall callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_slowPathGenerator->call()); |
6fe7ccc8 A |
179 | info.codeOrigin = m_propertyAccesses[i].m_codeOrigin; |
180 | info.callReturnLocation = callReturnLocation; | |
93a37866 A |
181 | info.patch.dfg.deltaCheckImmToCall = differenceBetweenCodePtr(linkBuffer.locationOf(m_propertyAccesses[i].m_structureImm), callReturnLocation); |
182 | info.patch.dfg.deltaCallToStructCheck = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_structureCheck)); | |
6fe7ccc8 | 183 | #if USE(JSVALUE64) |
93a37866 | 184 | info.patch.dfg.deltaCallToLoadOrStore = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_loadOrStore)); |
6fe7ccc8 | 185 | #else |
93a37866 A |
186 | info.patch.dfg.deltaCallToTagLoadOrStore = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_tagLoadOrStore)); |
187 | info.patch.dfg.deltaCallToPayloadLoadOrStore = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_payloadLoadOrStore)); | |
6fe7ccc8 | 188 | #endif |
93a37866 A |
189 | info.patch.dfg.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_slowPathGenerator->label())); |
190 | info.patch.dfg.deltaCallToDone = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_done)); | |
191 | info.patch.dfg.deltaCallToStorageLoad = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_propertyStorageLoad)); | |
6fe7ccc8 A |
192 | info.patch.dfg.baseGPR = m_propertyAccesses[i].m_baseGPR; |
193 | #if USE(JSVALUE64) | |
194 | info.patch.dfg.valueGPR = m_propertyAccesses[i].m_valueGPR; | |
195 | #else | |
196 | info.patch.dfg.valueTagGPR = m_propertyAccesses[i].m_valueTagGPR; | |
197 | info.patch.dfg.valueGPR = m_propertyAccesses[i].m_valueGPR; | |
198 | #endif | |
93a37866 | 199 | m_propertyAccesses[i].m_usedRegisters.copyInfo(info.patch.dfg.usedRegisters); |
6fe7ccc8 A |
200 | info.patch.dfg.registersFlushed = m_propertyAccesses[i].m_registerMode == PropertyAccessRecord::RegistersFlushed; |
201 | } | |
202 | ||
203 | m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size()); | |
204 | for (unsigned i = 0; i < m_jsCalls.size(); ++i) { | |
205 | CallLinkInfo& info = m_codeBlock->callLinkInfo(i); | |
206 | info.callType = m_jsCalls[i].m_callType; | |
207 | info.isDFG = true; | |
93a37866 A |
208 | info.codeOrigin = m_jsCalls[i].m_codeOrigin; |
209 | linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_vm->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress())); | |
210 | info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall); | |
6fe7ccc8 A |
211 | info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck); |
212 | info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall); | |
93a37866 | 213 | info.calleeGPR = static_cast<unsigned>(m_jsCalls[i].m_callee); |
6fe7ccc8 A |
214 | } |
215 | ||
93a37866 | 216 | MacroAssemblerCodeRef osrExitThunk = vm()->getCTIStub(osrExitGenerationThunkGenerator); |
6fe7ccc8 A |
217 | CodeLocationLabel target = CodeLocationLabel(osrExitThunk.code()); |
218 | for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) { | |
219 | OSRExit& exit = codeBlock()->osrExit(i); | |
93a37866 A |
220 | linkBuffer.link(exit.getPatchableCodeOffsetAsJump(), target); |
221 | exit.correctJump(linkBuffer); | |
222 | if (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max()) | |
223 | codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer); | |
6fe7ccc8 A |
224 | } |
225 | ||
93a37866 A |
226 | if (m_graph.m_compilation) { |
227 | ASSERT(m_exitSiteLabels.size() == codeBlock()->numberOfOSRExits()); | |
228 | for (unsigned i = 0; i < m_exitSiteLabels.size(); ++i) { | |
229 | Vector<Label>& labels = m_exitSiteLabels[i]; | |
230 | Vector<const void*> addresses; | |
231 | for (unsigned j = 0; j < labels.size(); ++j) | |
232 | addresses.append(linkBuffer.locationOf(labels[j]).executableAddress()); | |
233 | m_graph.m_compilation->addOSRExitSite(addresses); | |
234 | } | |
235 | } else | |
236 | ASSERT(!m_exitSiteLabels.size()); | |
237 | ||
238 | codeBlock()->saveCompilation(m_graph.m_compilation); | |
14957cd0 A |
239 | } |
240 | ||
6fe7ccc8 | 241 | bool JITCompiler::compile(JITCode& entry) |
14957cd0 | 242 | { |
93a37866 A |
243 | SamplingRegion samplingRegion("DFG Backend"); |
244 | ||
245 | setStartOfCode(); | |
6fe7ccc8 A |
246 | compileEntry(); |
247 | SpeculativeJIT speculative(*this); | |
248 | compileBody(speculative); | |
93a37866 | 249 | setEndOfMainPath(); |
6fe7ccc8 | 250 | |
93a37866 A |
251 | // Generate slow path code. |
252 | speculative.runSlowPathGenerators(); | |
253 | ||
254 | compileExceptionHandlers(); | |
255 | linkOSRExits(); | |
256 | ||
6fe7ccc8 A |
257 | // Create OSR entry trampolines if necessary. |
258 | speculative.createOSREntries(); | |
93a37866 | 259 | setEndOfCode(); |
14957cd0 | 260 | |
93a37866 | 261 | LinkBuffer linkBuffer(*m_vm, this, m_codeBlock, JITCompilationCanFail); |
6fe7ccc8 A |
262 | if (linkBuffer.didFailToAllocate()) |
263 | return false; | |
264 | link(linkBuffer); | |
265 | speculative.linkOSREntries(linkBuffer); | |
93a37866 A |
266 | codeBlock()->shrinkToFit(CodeBlock::LateShrink); |
267 | ||
268 | if (shouldShowDisassembly()) | |
269 | m_disassembler->dump(linkBuffer); | |
270 | if (m_graph.m_compilation) | |
271 | m_disassembler->reportToProfiler(m_graph.m_compilation.get(), linkBuffer); | |
6fe7ccc8 | 272 | |
93a37866 A |
273 | entry = JITCode( |
274 | linkBuffer.finalizeCodeWithoutDisassembly(), | |
275 | JITCode::DFGJIT); | |
6fe7ccc8 | 276 | return true; |
14957cd0 A |
277 | } |
278 | ||
6fe7ccc8 | 279 | bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck) |
14957cd0 | 280 | { |
93a37866 A |
281 | SamplingRegion samplingRegion("DFG Backend"); |
282 | ||
283 | setStartOfCode(); | |
6fe7ccc8 | 284 | compileEntry(); |
14957cd0 | 285 | |
6fe7ccc8 | 286 | // === Function header code generation === |
14957cd0 | 287 | // This is the main entry point, without performing an arity check. |
14957cd0 A |
288 | // If we needed to perform an arity check we will already have moved the return address, |
289 | // so enter after this. | |
290 | Label fromArityCheck(this); | |
93a37866 | 291 | // Plant a check that sufficient space is available in the JSStack. |
14957cd0 | 292 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291 |
6fe7ccc8 | 293 | addPtr(TrustedImm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1); |
93a37866 A |
294 | Jump stackCheck = branchPtr(Below, AbsoluteAddress(m_vm->interpreter->stack().addressOfEnd()), GPRInfo::regT1); |
295 | // Return here after stack check. | |
296 | Label fromStackCheck = label(); | |
14957cd0 A |
297 | |
298 | ||
6fe7ccc8 | 299 | // === Function body code generation === |
14957cd0 | 300 | SpeculativeJIT speculative(*this); |
6fe7ccc8 | 301 | compileBody(speculative); |
93a37866 | 302 | setEndOfMainPath(); |
14957cd0 | 303 | |
6fe7ccc8 A |
304 | // === Function footer code generation === |
305 | // | |
93a37866 | 306 | // Generate code to perform the slow stack check (if the fast one in |
6fe7ccc8 | 307 | // the function header fails), and generate the entry point with arity check. |
14957cd0 | 308 | // |
93a37866 | 309 | // Generate the stack check; if the fast check in the function head fails, |
14957cd0 A |
310 | // we need to call out to a helper function to check whether more space is available. |
311 | // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions). | |
93a37866 | 312 | stackCheck.link(this); |
14957cd0 A |
313 | move(stackPointerRegister, GPRInfo::argumentGPR0); |
314 | poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); | |
6fe7ccc8 | 315 | |
93a37866 A |
316 | CallBeginToken token; |
317 | beginCall(CodeOrigin(0), token); | |
318 | Call callStackCheck = call(); | |
319 | notifyCall(callStackCheck, CodeOrigin(0), token); | |
320 | jump(fromStackCheck); | |
6fe7ccc8 | 321 | |
14957cd0 A |
322 | // The fast entry point into a function does not check the correct number of arguments |
323 | // have been passed to the call (we only use the fast entry point where we can statically | |
324 | // determine the correct number of arguments have been passed, or have already checked). | |
325 | // In cases where an arity check is necessary, we enter here. | |
326 | // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions). | |
327 | Label arityCheck = label(); | |
6fe7ccc8 A |
328 | compileEntry(); |
329 | ||
93a37866 | 330 | load32(AssemblyHelpers::payloadFor((VirtualRegister)JSStack::ArgumentCount), GPRInfo::regT1); |
6fe7ccc8 | 331 | branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this); |
14957cd0 A |
332 | move(stackPointerRegister, GPRInfo::argumentGPR0); |
333 | poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); | |
93a37866 | 334 | beginCall(CodeOrigin(0), token); |
14957cd0 | 335 | Call callArityCheck = call(); |
6fe7ccc8 | 336 | notifyCall(callArityCheck, CodeOrigin(0), token); |
14957cd0 A |
337 | move(GPRInfo::regT0, GPRInfo::callFrameRegister); |
338 | jump(fromArityCheck); | |
6fe7ccc8 | 339 | |
93a37866 A |
340 | // Generate slow path code. |
341 | speculative.runSlowPathGenerators(); | |
342 | ||
343 | compileExceptionHandlers(); | |
344 | linkOSRExits(); | |
345 | ||
6fe7ccc8 A |
346 | // Create OSR entry trampolines if necessary. |
347 | speculative.createOSREntries(); | |
93a37866 | 348 | setEndOfCode(); |
6fe7ccc8 A |
349 | |
350 | // === Link === | |
93a37866 | 351 | LinkBuffer linkBuffer(*m_vm, this, m_codeBlock, JITCompilationCanFail); |
6fe7ccc8 A |
352 | if (linkBuffer.didFailToAllocate()) |
353 | return false; | |
354 | link(linkBuffer); | |
355 | speculative.linkOSREntries(linkBuffer); | |
93a37866 | 356 | codeBlock()->shrinkToFit(CodeBlock::LateShrink); |
6fe7ccc8 | 357 | |
93a37866 A |
358 | // FIXME: switch the stack check & arity check over to DFGOpertaion style calls, not JIT stubs. |
359 | linkBuffer.link(callStackCheck, cti_stack_check); | |
14957cd0 | 360 | linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck); |
93a37866 A |
361 | |
362 | if (shouldShowDisassembly()) | |
363 | m_disassembler->dump(linkBuffer); | |
364 | if (m_graph.m_compilation) | |
365 | m_disassembler->reportToProfiler(m_graph.m_compilation.get(), linkBuffer); | |
14957cd0 A |
366 | |
367 | entryWithArityCheck = linkBuffer.locationOf(arityCheck); | |
93a37866 A |
368 | entry = JITCode( |
369 | linkBuffer.finalizeCodeWithoutDisassembly(), | |
370 | JITCode::DFGJIT); | |
6fe7ccc8 | 371 | return true; |
14957cd0 | 372 | } |
14957cd0 A |
373 | |
374 | } } // namespace JSC::DFG | |
375 | ||
6fe7ccc8 | 376 | #endif // ENABLE(DFG_JIT) |