Towards 8 Bit Strings: Templatize JSC::Parser class by Lexer type
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGJITCompiler.cpp
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 #include "config.h"
27 #include "DFGJITCompiler.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "CodeBlock.h"
32 #include "DFGJITCodeGenerator.h"
33 #include "DFGOperations.h"
34 #include "DFGRegisterBank.h"
35 #include "DFGSpeculativeJIT.h"
36 #include "JSGlobalData.h"
37 #include "LinkBuffer.h"
38
39 namespace JSC { namespace DFG {
40
41 void JITCompiler::linkOSRExits(SpeculativeJIT& speculative)
42 {
43     OSRExitVector::Iterator exitsIter = speculative.osrExits().begin();
44     OSRExitVector::Iterator exitsEnd = speculative.osrExits().end();
45     
46     while (exitsIter != exitsEnd) {
47         const OSRExit& exit = *exitsIter;
48         exitSpeculativeWithOSR(exit, speculative.speculationRecovery(exit.m_recoveryIndex));
49         ++exitsIter;
50     }
51 }
52
53 void JITCompiler::compileEntry()
54 {
55     m_startOfCode = label();
56     
57     // This code currently matches the old JIT. In the function header we need to
58     // pop the return address (since we do not allow any recursion on the machine
59     // stack), and perform a fast register file check.
60     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292
61     // We'll need to convert the remaining cti_ style calls (specifically the register file
62     // check) which will be dependent on stack layout. (We'd need to account for this in
63     // both normal return code and when jumping to an exception handler).
64     preserveReturnAddressAfterCall(GPRInfo::regT2);
65     emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
66 }
67
68 void JITCompiler::compileBody()
69 {
70     // We generate the speculative code path, followed by OSR exit code to return
71     // to the old JIT code if speculations fail.
72
73 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_FUNCTION)
74     // Handy debug tool!
75     breakpoint();
76 #endif
77     
78     addPtr(Imm32(1), AbsoluteAddress(codeBlock()->addressOfSpeculativeSuccessCounter()));
79
80     Label speculativePathBegin = label();
81     SpeculativeJIT speculative(*this);
82     bool compiledSpeculative = speculative.compile();
83     ASSERT_UNUSED(compiledSpeculative, compiledSpeculative);
84
85     linkOSRExits(speculative);
86
87     // Iterate over the m_calls vector, checking for jumps to link.
88     bool didLinkExceptionCheck = false;
89     for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) {
90         Jump& exceptionCheck = m_exceptionChecks[i].m_exceptionCheck;
91         if (exceptionCheck.isSet()) {
92             exceptionCheck.link(this);
93             didLinkExceptionCheck = true;
94         }
95     }
96
97     // If any exception checks were linked, generate code to lookup a handler.
98     if (didLinkExceptionCheck) {
99         // lookupExceptionHandler is passed two arguments, exec (the CallFrame*), and
100         // an identifier for the operation that threw the exception, which we can use
101         // to look up handler information. The identifier we use is the return address
102         // of the call out from JIT code that threw the exception; this is still
103         // available on the stack, just below the stack pointer!
104         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
105         peek(GPRInfo::argumentGPR1, -1);
106         m_calls.append(CallLinkRecord(call(), lookupExceptionHandler));
107         // lookupExceptionHandler leaves the handler CallFrame* in the returnValueGPR,
108         // and the address of the handler in returnValueGPR2.
109         jump(GPRInfo::returnValueGPR2);
110     }
111 }
112
113 void JITCompiler::link(LinkBuffer& linkBuffer)
114 {
115     // Link the code, populate data in CodeBlock data structures.
116 #if DFG_ENABLE(DEBUG_VERBOSE)
117     fprintf(stderr, "JIT code for %p start at [%p, %p). Size = %lu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize());
118 #endif
119
120     // Link all calls out from the JIT code to their respective functions.
121     for (unsigned i = 0; i < m_calls.size(); ++i)
122         linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function);
123
124     if (m_codeBlock->needsCallReturnIndices()) {
125         m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionChecks.size());
126         for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) {
127             unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call);
128             CodeOrigin codeOrigin = m_exceptionChecks[i].m_codeOrigin;
129             while (codeOrigin.inlineCallFrame)
130                 codeOrigin = codeOrigin.inlineCallFrame->caller;
131             unsigned exceptionInfo = codeOrigin.bytecodeIndex;
132             m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo));
133         }
134     }
135     
136     unsigned numCallsFromInlineCode = 0;
137     for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) {
138         if (m_exceptionChecks[i].m_codeOrigin.inlineCallFrame)
139             numCallsFromInlineCode++;
140     }
141
142     if (numCallsFromInlineCode) {
143         Vector<CodeOriginAtCallReturnOffset>& codeOrigins = m_codeBlock->codeOrigins();
144         codeOrigins.resize(numCallsFromInlineCode);
145         
146         for (unsigned i = 0, j = 0; i < m_exceptionChecks.size(); ++i) {
147             CallExceptionRecord& record = m_exceptionChecks[i];
148             if (record.m_codeOrigin.inlineCallFrame) {
149                 unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call);
150                 codeOrigins[j].codeOrigin = record.m_codeOrigin;
151                 codeOrigins[j].callReturnOffset = returnAddressOffset;
152                 j++;
153             }
154         }
155     }
156     
157     m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size());
158     for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) {
159         StructureStubInfo& info = m_codeBlock->structureStubInfo(i);
160         CodeLocationCall callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_functionCall);
161         info.callReturnLocation = callReturnLocation;
162         info.u.unset.deltaCheckImmToCall = differenceBetweenCodePtr(linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCheckImmToCall), callReturnLocation);
163         info.deltaCallToStructCheck = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToStructCheck));
164 #if USE(JSVALUE64)
165         info.u.unset.deltaCallToLoadOrStore = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToLoadOrStore));
166 #else
167         info.u.unset.deltaCallToTagLoadOrStore = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToTagLoadOrStore));
168         info.u.unset.deltaCallToPayloadLoadOrStore = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToPayloadLoadOrStore));
169 #endif
170         info.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToSlowCase));
171         info.deltaCallToDone = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_deltaCallToDone));
172         info.baseGPR = m_propertyAccesses[i].m_baseGPR;
173 #if USE(JSVALUE64)
174         info.valueGPR = m_propertyAccesses[i].m_valueGPR;
175 #else
176         info.valueTagGPR = m_propertyAccesses[i].m_valueTagGPR;
177         info.valueGPR = m_propertyAccesses[i].m_valueGPR;
178 #endif
179         info.scratchGPR = m_propertyAccesses[i].m_scratchGPR;
180     }
181     
182     m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size());
183     for (unsigned i = 0; i < m_jsCalls.size(); ++i) {
184         CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
185         info.isCall = m_jsCalls[i].m_isCall;
186         info.isDFG = true;
187         info.callReturnLocation = CodeLocationLabel(linkBuffer.locationOf(m_jsCalls[i].m_slowCall));
188         info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck);
189         info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall);
190     }
191     
192     m_codeBlock->addMethodCallLinkInfos(m_methodGets.size());
193     for (unsigned i = 0; i < m_methodGets.size(); ++i) {
194         MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i);
195         info.cachedStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_structToCompare));
196         info.cachedPrototypeStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoStructToCompare));
197         info.cachedFunction.setLocation(linkBuffer.locationOf(m_methodGets[i].m_putFunction));
198         info.cachedPrototype.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoObj));
199         info.callReturnLocation = linkBuffer.locationOf(m_methodGets[i].m_slowCall);
200     }
201 }
202
203 void JITCompiler::compile(JITCode& entry)
204 {
205     // Preserve the return address to the callframe.
206     compileEntry();
207     // Generate the body of the program.
208     compileBody();
209     // Link
210     LinkBuffer linkBuffer(*m_globalData, this);
211     link(linkBuffer);
212     entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT);
213 }
214
215 void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
216 {
217     compileEntry();
218
219     // === Function header code generation ===
220     // This is the main entry point, without performing an arity check.
221     // If we needed to perform an arity check we will already have moved the return address,
222     // so enter after this.
223     Label fromArityCheck(this);
224     // Setup a pointer to the codeblock in the CallFrameHeader.
225     emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
226     // Plant a check that sufficient space is available in the RegisterFile.
227     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
228     addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
229     Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
230     // Return here after register file check.
231     Label fromRegisterFileCheck = label();
232
233
234     // === Function body code generation ===
235     compileBody();
236
237     // === Function footer code generation ===
238     //
239     // Generate code to perform the slow register file check (if the fast one in
240     // the function header fails), and generate the entry point with arity check.
241     //
242     // Generate the register file check; if the fast check in the function head fails,
243     // we need to call out to a helper function to check whether more space is available.
244     // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
245     registerFileCheck.link(this);
246     move(stackPointerRegister, GPRInfo::argumentGPR0);
247     poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
248     Call callRegisterFileCheck = call();
249     jump(fromRegisterFileCheck);
250     
251     // The fast entry point into a function does not check the correct number of arguments
252     // have been passed to the call (we only use the fast entry point where we can statically
253     // determine the correct number of arguments have been passed, or have already checked).
254     // In cases where an arity check is necessary, we enter here.
255     // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
256     Label arityCheck = label();
257     preserveReturnAddressAfterCall(GPRInfo::regT2);
258     emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
259     branch32(Equal, GPRInfo::regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(fromArityCheck, this);
260     move(stackPointerRegister, GPRInfo::argumentGPR0);
261     poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
262     Call callArityCheck = call();
263     move(GPRInfo::regT0, GPRInfo::callFrameRegister);
264     jump(fromArityCheck);
265
266
267     // === Link ===
268     LinkBuffer linkBuffer(*m_globalData, this);
269     link(linkBuffer);
270     
271     // FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs.
272     linkBuffer.link(callRegisterFileCheck, cti_register_file_check);
273     linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
274
275     entryWithArityCheck = linkBuffer.locationOf(arityCheck);
276     entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT);
277 }
278
279 #if USE(JSVALUE64)
280
281 void JITCompiler::exitSpeculativeWithOSR(const OSRExit& exit, SpeculationRecovery* recovery)
282 {
283     // 1) Pro-forma stuff.
284     exit.m_check.link(this);
285
286 #if DFG_ENABLE(DEBUG_VERBOSE)
287     fprintf(stderr, "OSR exit for Node @%d (", (int)exit.m_nodeIndex);
288     for (CodeOrigin codeOrigin = exit.m_codeOrigin; ; codeOrigin = codeOrigin.inlineCallFrame->caller) {
289         fprintf(stderr, "bc#%u", codeOrigin.bytecodeIndex);
290         if (!codeOrigin.inlineCallFrame)
291             break;
292         fprintf(stderr, " -> %p ", codeOrigin.inlineCallFrame->executable.get());
293     }
294     fprintf(stderr, ") at JIT offset 0x%x  ", debugOffset());
295     exit.dump(stderr);
296 #endif
297 #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
298     SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
299     debugInfo->codeBlock = m_codeBlock;
300     debugInfo->debugOffset = debugOffset();
301     
302     debugCall(debugOperationPrintSpeculationFailure, debugInfo);
303 #endif
304     
305 #if DFG_ENABLE(JIT_BREAK_ON_SPECULATION_FAILURE)
306     breakpoint();
307 #endif
308     
309 #if DFG_ENABLE(SUCCESS_STATS)
310     static SamplingCounter counter("SpeculationFailure");
311     emitCount(counter);
312 #endif
313     
314     // 2) Perform speculation recovery. This only comes into play when an operation
315     //    starts mutating state before verifying the speculation it has already made.
316     
317     GPRReg alreadyBoxed = InvalidGPRReg;
318     
319     if (recovery) {
320         switch (recovery->type()) {
321         case SpeculativeAdd:
322             sub32(recovery->src(), recovery->dest());
323             orPtr(GPRInfo::tagTypeNumberRegister, recovery->dest());
324             alreadyBoxed = recovery->dest();
325             break;
326             
327         case BooleanSpeculationCheck:
328             xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest());
329             break;
330             
331         default:
332             break;
333         }
334     }
335
336     // 3) Refine some value profile, if appropriate.
337     
338     if (!!exit.m_jsValueSource && !!exit.m_valueProfile) {
339         if (exit.m_jsValueSource.isAddress()) {
340             // We can't be sure that we have a spare register. So use the tagTypeNumberRegister,
341             // since we know how to restore it.
342             loadPtr(Address(exit.m_jsValueSource.asAddress()), GPRInfo::tagTypeNumberRegister);
343             storePtr(GPRInfo::tagTypeNumberRegister, exit.m_valueProfile->specFailBucket(0));
344             move(TrustedImmPtr(bitwise_cast<void*>(TagTypeNumber)), GPRInfo::tagTypeNumberRegister);
345         } else
346             storePtr(exit.m_jsValueSource.gpr(), exit.m_valueProfile->specFailBucket(0));
347     }
348
349     // 4) Figure out how many scratch slots we'll need. We need one for every GPR/FPR
350     //    whose destination is now occupied by a DFG virtual register, and we need
351     //    one for every displaced virtual register if there are more than
352     //    GPRInfo::numberOfRegisters of them. Also see if there are any constants,
353     //    any undefined slots, any FPR slots, and any unboxed ints.
354             
355     Vector<bool> poisonedVirtualRegisters(exit.m_variables.size());
356     for (unsigned i = 0; i < poisonedVirtualRegisters.size(); ++i)
357         poisonedVirtualRegisters[i] = false;
358
359     unsigned numberOfPoisonedVirtualRegisters = 0;
360     unsigned numberOfDisplacedVirtualRegisters = 0;
361     
362     // Booleans for fast checks. We expect that most OSR exits do not have to rebox
363     // Int32s, have no FPRs, and have no constants. If there are constants, we
364     // expect most of them to be jsUndefined(); if that's true then we handle that
365     // specially to minimize code size and execution time.
366     bool haveUnboxedInt32s = false;
367     bool haveFPRs = false;
368     bool haveConstants = false;
369     bool haveUndefined = false;
370     
371     for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
372         const ValueRecovery& recovery = exit.valueRecovery(index);
373         switch (recovery.technique()) {
374         case Int32DisplacedInRegisterFile:
375         case DoubleDisplacedInRegisterFile:
376         case DisplacedInRegisterFile:
377             numberOfDisplacedVirtualRegisters++;
378             ASSERT((int)recovery.virtualRegister() >= 0);
379             
380             // See if we might like to store to this virtual register before doing
381             // virtual register shuffling. If so, we say that the virtual register
382             // is poisoned: it cannot be stored to until after displaced virtual
383             // registers are handled. We track poisoned virtual register carefully
384             // to ensure this happens efficiently. Note that we expect this case
385             // to be rare, so the handling of it is optimized for the cases in
386             // which it does not happen.
387             if (recovery.virtualRegister() < (int)exit.m_variables.size()) {
388                 switch (exit.m_variables[recovery.virtualRegister()].technique()) {
389                 case InGPR:
390                 case UnboxedInt32InGPR:
391                 case InFPR:
392                     if (!poisonedVirtualRegisters[recovery.virtualRegister()]) {
393                         poisonedVirtualRegisters[recovery.virtualRegister()] = true;
394                         numberOfPoisonedVirtualRegisters++;
395                     }
396                     break;
397                 default:
398                     break;
399                 }
400             }
401             break;
402             
403         case UnboxedInt32InGPR:
404         case AlreadyInRegisterFileAsUnboxedInt32:
405             haveUnboxedInt32s = true;
406             break;
407             
408         case InFPR:
409             haveFPRs = true;
410             break;
411             
412         case Constant:
413             haveConstants = true;
414             if (recovery.constant().isUndefined())
415                 haveUndefined = true;
416             break;
417             
418         default:
419             break;
420         }
421     }
422     
423 #if DFG_ENABLE(DEBUG_VERBOSE)
424     fprintf(stderr, "  ");
425     if (numberOfPoisonedVirtualRegisters)
426         fprintf(stderr, "Poisoned=%u ", numberOfPoisonedVirtualRegisters);
427     if (numberOfDisplacedVirtualRegisters)
428         fprintf(stderr, "Displaced=%u ", numberOfDisplacedVirtualRegisters);
429     if (haveUnboxedInt32s)
430         fprintf(stderr, "UnboxedInt32 ");
431     if (haveFPRs)
432         fprintf(stderr, "FPR ");
433     if (haveConstants)
434         fprintf(stderr, "Constants ");
435     if (haveUndefined)
436         fprintf(stderr, "Undefined ");
437     fprintf(stderr, " ");
438 #endif
439     
440     EncodedJSValue* scratchBuffer = static_cast<EncodedJSValue*>(globalData()->scratchBufferForSize(sizeof(EncodedJSValue) * (numberOfPoisonedVirtualRegisters + (numberOfDisplacedVirtualRegisters <= GPRInfo::numberOfRegisters ? 0 : numberOfDisplacedVirtualRegisters))));
441
442     // From here on, the code assumes that it is profitable to maximize the distance
443     // between when something is computed and when it is stored.
444     
445     // 5) Perform all reboxing of integers.
446     
447     if (haveUnboxedInt32s) {
448         for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
449             const ValueRecovery& recovery = exit.valueRecovery(index);
450             switch (recovery.technique()) {
451             case UnboxedInt32InGPR:
452                 if (recovery.gpr() != alreadyBoxed)
453                     orPtr(GPRInfo::tagTypeNumberRegister, recovery.gpr());
454                 break;
455                 
456             case AlreadyInRegisterFileAsUnboxedInt32:
457                 store32(Imm32(static_cast<uint32_t>(TagTypeNumber >> 32)), tagFor(static_cast<VirtualRegister>(exit.operandForIndex(index))));
458                 break;
459                 
460             default:
461                 break;
462             }
463         }
464     }
465     
466     // 6) Dump all non-poisoned GPRs. For poisoned GPRs, save them into the scratch storage.
467     //    Note that GPRs do not have a fast change (like haveFPRs) because we expect that
468     //    most OSR failure points will have at least one GPR that needs to be dumped.
469     
470     unsigned scratchIndex = 0;
471     for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
472         const ValueRecovery& recovery = exit.valueRecovery(index);
473         int operand = exit.operandForIndex(index);
474         switch (recovery.technique()) {
475         case InGPR:
476         case UnboxedInt32InGPR:
477             if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)])
478                 storePtr(recovery.gpr(), scratchBuffer + scratchIndex++);
479             else
480                 storePtr(recovery.gpr(), addressFor((VirtualRegister)operand));
481             break;
482         default:
483             break;
484         }
485     }
486     
487     // At this point all GPRs are available for scratch use.
488     
489     if (haveFPRs) {
490         // 7) Box all doubles (relies on there being more GPRs than FPRs)
491         
492         for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
493             const ValueRecovery& recovery = exit.valueRecovery(index);
494             if (recovery.technique() != InFPR)
495                 continue;
496             FPRReg fpr = recovery.fpr();
497             GPRReg gpr = GPRInfo::toRegister(FPRInfo::toIndex(fpr));
498             boxDouble(fpr, gpr);
499         }
500         
501         // 8) Dump all doubles into the register file, or to the scratch storage if
502         //    the destination virtual register is poisoned.
503         
504         for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
505             const ValueRecovery& recovery = exit.valueRecovery(index);
506             if (recovery.technique() != InFPR)
507                 continue;
508             GPRReg gpr = GPRInfo::toRegister(FPRInfo::toIndex(recovery.fpr()));
509             if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)])
510                 storePtr(gpr, scratchBuffer + scratchIndex++);
511             else
512                 storePtr(gpr, addressFor((VirtualRegister)exit.operandForIndex(index)));
513         }
514     }
515     
516     ASSERT(scratchIndex == numberOfPoisonedVirtualRegisters);
517     
518     // 9) Reshuffle displaced virtual registers. Optimize for the case that
519     //    the number of displaced virtual registers is not more than the number
520     //    of available physical registers.
521     
522     if (numberOfDisplacedVirtualRegisters) {
523         if (numberOfDisplacedVirtualRegisters <= GPRInfo::numberOfRegisters) {
524             // So far this appears to be the case that triggers all the time, but
525             // that is far from guaranteed.
526         
527             unsigned displacementIndex = 0;
528             for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
529                 const ValueRecovery& recovery = exit.valueRecovery(index);
530                 switch (recovery.technique()) {
531                 case DisplacedInRegisterFile:
532                     loadPtr(addressFor(recovery.virtualRegister()), GPRInfo::toRegister(displacementIndex++));
533                     break;
534                     
535                 case Int32DisplacedInRegisterFile: {
536                     GPRReg gpr = GPRInfo::toRegister(displacementIndex++);
537                     load32(addressFor(recovery.virtualRegister()), gpr);
538                     orPtr(GPRInfo::tagTypeNumberRegister, gpr);
539                     break;
540                 }
541                     
542                 case DoubleDisplacedInRegisterFile: {
543                     GPRReg gpr = GPRInfo::toRegister(displacementIndex++);
544                     loadPtr(addressFor(recovery.virtualRegister()), gpr);
545                     subPtr(GPRInfo::tagTypeNumberRegister, gpr);
546                     break;
547                 }
548                     
549                 default:
550                     break;
551                 }
552             }
553         
554             displacementIndex = 0;
555             for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
556                 const ValueRecovery& recovery = exit.valueRecovery(index);
557                 switch (recovery.technique()) {
558                 case DisplacedInRegisterFile:
559                 case Int32DisplacedInRegisterFile:
560                 case DoubleDisplacedInRegisterFile:
561                     storePtr(GPRInfo::toRegister(displacementIndex++), addressFor((VirtualRegister)exit.operandForIndex(index)));
562                     break;
563                     
564                 default:
565                     break;
566                 }
567             }
568         } else {
569             // FIXME: This should use the shuffling algorithm that we use
570             // for speculative->non-speculative jumps, if we ever discover that
571             // some hot code with lots of live values that get displaced and
572             // spilled really enjoys frequently failing speculation.
573         
574             // For now this code is engineered to be correct but probably not
575             // super. In particular, it correctly handles cases where for example
576             // the displacements are a permutation of the destination values, like
577             //
578             // 1 -> 2
579             // 2 -> 1
580             //
581             // It accomplishes this by simply lifting all of the virtual registers
582             // from their old (DFG JIT) locations and dropping them in a scratch
583             // location in memory, and then transferring from that scratch location
584             // to their new (old JIT) locations.
585         
586             for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
587                 const ValueRecovery& recovery = exit.valueRecovery(index);
588                 
589                 switch (recovery.technique()) {
590                 case DisplacedInRegisterFile:
591                     loadPtr(addressFor(recovery.virtualRegister()), GPRInfo::regT0);
592                     storePtr(GPRInfo::regT0, scratchBuffer + scratchIndex++);
593                     break;
594                     
595                 case Int32DisplacedInRegisterFile: {
596                     load32(addressFor(recovery.virtualRegister()), GPRInfo::regT0);
597                     orPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
598                     storePtr(GPRInfo::regT0, scratchBuffer + scratchIndex++);
599                     break;
600                 }
601                     
602                 case DoubleDisplacedInRegisterFile: {
603                     loadPtr(addressFor(recovery.virtualRegister()), GPRInfo::regT0);
604                     subPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
605                     storePtr(GPRInfo::regT0, scratchBuffer + scratchIndex++);
606                     break;
607                 }
608                     
609                 default:
610                     break;
611                 }
612             }
613         
614             scratchIndex = numberOfPoisonedVirtualRegisters;
615             for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
616                 const ValueRecovery& recovery = exit.valueRecovery(index);
617                 switch (recovery.technique()) {
618                 case DisplacedInRegisterFile:
619                 case Int32DisplacedInRegisterFile:
620                 case DoubleDisplacedInRegisterFile:
621                     loadPtr(scratchBuffer + scratchIndex++, GPRInfo::regT0);
622                     storePtr(GPRInfo::regT0, addressFor((VirtualRegister)exit.operandForIndex(index)));
623                     break;
624                     
625                 default:
626                     break;
627                 }
628             }
629         
630             ASSERT(scratchIndex == numberOfPoisonedVirtualRegisters + numberOfDisplacedVirtualRegisters);
631         }
632     }
633     
634     // 10) Dump all poisoned virtual registers.
635     
636     scratchIndex = 0;
637     if (numberOfPoisonedVirtualRegisters) {
638         for (int virtualRegister = 0; virtualRegister < (int)exit.m_variables.size(); ++virtualRegister) {
639             if (!poisonedVirtualRegisters[virtualRegister])
640                 continue;
641             
642             const ValueRecovery& recovery = exit.m_variables[virtualRegister];
643             switch (recovery.technique()) {
644             case InGPR:
645             case UnboxedInt32InGPR:
646             case InFPR:
647                 loadPtr(scratchBuffer + scratchIndex++, GPRInfo::regT0);
648                 storePtr(GPRInfo::regT0, addressFor((VirtualRegister)virtualRegister));
649                 break;
650                 
651             default:
652                 break;
653             }
654         }
655     }
656     ASSERT(scratchIndex == numberOfPoisonedVirtualRegisters);
657     
658     // 11) Dump all constants. Optimize for Undefined, since that's a constant we see
659     //     often.
660
661     if (haveConstants) {
662         if (haveUndefined)
663             move(TrustedImmPtr(JSValue::encode(jsUndefined())), GPRInfo::regT0);
664         
665         for (int index = 0; index < exit.numberOfRecoveries(); ++index) {
666             const ValueRecovery& recovery = exit.valueRecovery(index);
667             if (recovery.technique() != Constant)
668                 continue;
669             if (recovery.constant().isUndefined())
670                 storePtr(GPRInfo::regT0, addressFor((VirtualRegister)exit.operandForIndex(index)));
671             else
672                 storePtr(TrustedImmPtr(JSValue::encode(recovery.constant())), addressFor((VirtualRegister)exit.operandForIndex(index)));
673         }
674     }
675     
676     // 12) Adjust the old JIT's execute counter. Since we are exiting OSR, we know
677     //     that all new calls into this code will go to the new JIT, so the execute
678     //     counter only affects call frames that performed OSR exit and call frames
679     //     that were still executing the old JIT at the time of another call frame's
680     //     OSR exit. We want to ensure that the following is true:
681     //
682     //     (a) Code the performs an OSR exit gets a chance to reenter optimized
683     //         code eventually, since optimized code is faster. But we don't
684     //         want to do such reentery too aggressively (see (c) below).
685     //
686     //     (b) If there is code on the call stack that is still running the old
687     //         JIT's code and has never OSR'd, then it should get a chance to
688     //         perform OSR entry despite the fact that we've exited.
689     //
690     //     (c) Code the performs an OSR exit should not immediately retry OSR
691     //         entry, since both forms of OSR are expensive. OSR entry is
692     //         particularly expensive.
693     //
694     //     (d) Frequent OSR failures, even those that do not result in the code
695     //         running in a hot loop, result in recompilation getting triggered.
696     //
697     //     To ensure (c), we'd like to set the execute counter to
698     //     counterValueForOptimizeAfterWarmUp(). This seems like it would endanger
699     //     (a) and (b), since then every OSR exit would delay the opportunity for
700     //     every call frame to perform OSR entry. Essentially, if OSR exit happens
701     //     frequently and the function has few loops, then the counter will never
702     //     become non-negative and OSR entry will never be triggered. OSR entry
703     //     will only happen if a loop gets hot in the old JIT, which does a pretty
704     //     good job of ensuring (a) and (b). But that doesn't take care of (d),
705     //     since each speculation failure would reset the execute counter.
706     //     So we check here if the number of speculation failures is significantly
707     //     larger than the number of successes (we want 90% success rate), and if
708     //     there have been a large enough number of failures. If so, we set the
709     //     counter to 0; otherwise we set the counter to
710     //     counterValueForOptimizeAfterWarmUp().
711     
712     move(TrustedImmPtr(codeBlock()), GPRInfo::regT0);
713     
714     load32(Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()), GPRInfo::regT2);
715     load32(Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()), GPRInfo::regT1);
716     add32(Imm32(1), GPRInfo::regT2);
717     add32(Imm32(-1), GPRInfo::regT1);
718     store32(GPRInfo::regT2, Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeFailCounter()));
719     store32(GPRInfo::regT1, Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter()));
720     
721     move(TrustedImmPtr(codeBlock()->alternative()), GPRInfo::regT0);
722     
723     Jump fewFails = branch32(BelowOrEqual, GPRInfo::regT2, Imm32(codeBlock()->largeFailCountThreshold()));
724     mul32(Imm32(Heuristics::desiredSpeculativeSuccessFailRatio), GPRInfo::regT2, GPRInfo::regT2);
725     
726     Jump lowFailRate = branch32(BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1);
727     
728     // Reoptimize as soon as possible.
729     store32(Imm32(Heuristics::executionCounterValueForOptimizeNextInvocation), Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter()));
730     Jump doneAdjusting = jump();
731     
732     fewFails.link(this);
733     lowFailRate.link(this);
734     
735     store32(Imm32(codeBlock()->alternative()->counterValueForOptimizeAfterLongWarmUp()), Address(GPRInfo::regT0, CodeBlock::offsetOfExecuteCounter()));
736     
737     doneAdjusting.link(this);
738     
739     // 13) Load the result of the last bytecode operation into regT0.
740     
741     if (exit.m_lastSetOperand != std::numeric_limits<int>::max())
742         loadPtr(addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister);
743     
744     // 14) Fix call frame(s).
745     
746     ASSERT(codeBlock()->alternative()->getJITType() == JITCode::BaselineJIT);
747     storePtr(TrustedImmPtr(codeBlock()->alternative()), addressFor((VirtualRegister)RegisterFile::CodeBlock));
748     
749     for (CodeOrigin codeOrigin = exit.m_codeOrigin; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) {
750         InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
751         CodeBlock* baselineCodeBlock = baselineCodeBlockFor(codeOrigin);
752         CodeBlock* baselineCodeBlockForCaller = baselineCodeBlockFor(inlineCallFrame->caller);
753         Vector<BytecodeAndMachineOffset>& decodedCodeMap = decodedCodeMapFor(baselineCodeBlockForCaller);
754         unsigned returnBytecodeIndex = inlineCallFrame->caller.bytecodeIndex + OPCODE_LENGTH(op_call);
755         BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned, BytecodeAndMachineOffset::getBytecodeIndex>(decodedCodeMap.begin(), decodedCodeMap.size(), returnBytecodeIndex);
756         
757         ASSERT(mapping);
758         ASSERT(mapping->m_bytecodeIndex == returnBytecodeIndex);
759         
760         void* jumpTarget = baselineCodeBlockForCaller->getJITCode().executableAddressAtOffset(mapping->m_machineCodeOffset);
761
762         GPRReg callerFrameGPR;
763         if (inlineCallFrame->caller.inlineCallFrame) {
764             addPtr(Imm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
765             callerFrameGPR = GPRInfo::regT3;
766         } else
767             callerFrameGPR = GPRInfo::callFrameRegister;
768         
769         storePtr(TrustedImmPtr(baselineCodeBlock), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CodeBlock)));
770         storePtr(TrustedImmPtr(inlineCallFrame->callee->scope()), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ScopeChain)));
771         storePtr(callerFrameGPR, addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::CallerFrame)));
772         storePtr(TrustedImmPtr(jumpTarget), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ReturnPC)));
773         storePtr(TrustedImmPtr(JSValue::encode(jsNumber(inlineCallFrame->arguments.size()))), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::ArgumentCount)));
774         storePtr(TrustedImmPtr(inlineCallFrame->callee.get()), addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee)));
775     }
776     
777     if (exit.m_codeOrigin.inlineCallFrame)
778         addPtr(Imm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister);
779     
780     // 15) Jump into the corresponding baseline JIT code.
781     
782     CodeBlock* baselineCodeBlock = baselineCodeBlockFor(exit.m_codeOrigin);
783     Vector<BytecodeAndMachineOffset>& decodedCodeMap = decodedCodeMapFor(baselineCodeBlock);
784     
785     BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned, BytecodeAndMachineOffset::getBytecodeIndex>(decodedCodeMap.begin(), decodedCodeMap.size(), exit.m_codeOrigin.bytecodeIndex);
786     
787     ASSERT(mapping);
788     ASSERT(mapping->m_bytecodeIndex == exit.m_codeOrigin.bytecodeIndex);
789     
790     void* jumpTarget = baselineCodeBlock->getJITCode().executableAddressAtOffset(mapping->m_machineCodeOffset);
791     
792     ASSERT(GPRInfo::regT1 != GPRInfo::cachedResultRegister);
793     
794     move(TrustedImmPtr(jumpTarget), GPRInfo::regT1);
795     jump(GPRInfo::regT1);
796
797 #if DFG_ENABLE(DEBUG_VERBOSE)
798     fprintf(stderr, "-> %p\n", jumpTarget);
799 #endif
800 }
801
802 #endif // USE(JSVALUE64)
803
804 } } // namespace JSC::DFG
805
806 #endif // ENABLE(DFG_JIT)