Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / jit / CallFrameShuffler.cpp
1 /*
2  * Copyright (C) 2015 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 "CallFrameShuffler.h"
28
29 #if ENABLE(JIT)
30
31 #include "CachedRecovery.h"
32 #include "CCallHelpers.h"
33 #include "CodeBlock.h"
34
35 namespace JSC {
36
37 CallFrameShuffler::CallFrameShuffler(CCallHelpers& jit, const CallFrameShuffleData& data)
38     : m_jit(jit)
39     , m_oldFrame(data.numLocals + JSStack::CallerFrameAndPCSize, nullptr)
40     , m_newFrame(data.args.size() + JSStack::CallFrameHeaderSize, nullptr)
41     , m_alignedOldFrameSize(JSStack::CallFrameHeaderSize
42         + roundArgumentCountToAlignFrame(jit.codeBlock()->numParameters()))
43     , m_alignedNewFrameSize(JSStack::CallFrameHeaderSize
44         + roundArgumentCountToAlignFrame(data.args.size()))
45     , m_frameDelta(m_alignedNewFrameSize - m_alignedOldFrameSize)
46     , m_lockedRegisters(RegisterSet::allRegisters())
47 {
48     // We are allowed all the usual registers...
49     for (unsigned i = GPRInfo::numberOfRegisters; i--; )
50         m_lockedRegisters.clear(GPRInfo::toRegister(i));
51     for (unsigned i = FPRInfo::numberOfRegisters; i--; )
52         m_lockedRegisters.clear(FPRInfo::toRegister(i));
53     // ... as well as the runtime registers.
54     m_lockedRegisters.exclude(RegisterSet::vmCalleeSaveRegisters());
55
56     ASSERT(!data.callee.isInJSStack() || data.callee.virtualRegister().isLocal());
57     addNew(VirtualRegister(JSStack::Callee), data.callee);
58
59     for (size_t i = 0; i < data.args.size(); ++i) {
60         ASSERT(!data.args[i].isInJSStack() || data.args[i].virtualRegister().isLocal());
61         addNew(virtualRegisterForArgument(i), data.args[i]);
62     }
63
64 #if USE(JSVALUE64)
65     for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
66         if (!data.registers[reg].isSet())
67             continue;
68
69         if (reg.isGPR())
70             addNew(JSValueRegs(reg.gpr()), data.registers[reg]);
71         else
72             addNew(reg.fpr(), data.registers[reg]);
73     }
74
75     m_tagTypeNumber = data.tagTypeNumber;
76     if (m_tagTypeNumber != InvalidGPRReg)
77         lockGPR(m_tagTypeNumber);
78 #endif
79 }
80
81 void CallFrameShuffler::dump(PrintStream& out) const
82 {
83     static const char* delimiter             = " +-------------------------------+ ";
84     static const char* dangerDelimiter       = " X-------------------------------X ";
85     static const char* dangerBoundsDelimiter = " XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ";
86     static const char* emptySpace            = "                                   ";
87     out.print("          ");
88     out.print("           Old frame               ");
89     out.print("           New frame               ");
90     out.print("\n");
91     int totalSize = m_alignedOldFrameSize + std::max(numLocals(), m_alignedNewFrameSize) + 3;
92     for (int i = 0; i < totalSize; ++i) {
93         VirtualRegister old { m_alignedOldFrameSize - i - 1 };
94         VirtualRegister newReg { old + m_frameDelta };
95
96         if (!isValidOld(old) && old != firstOld() - 1
97             && !isValidNew(newReg) && newReg != firstNew() - 1)
98             continue;
99
100         out.print("        ");
101         if (dangerFrontier() >= firstNew()
102             && (newReg == dangerFrontier() || newReg == firstNew() - 1))
103             out.print(dangerBoundsDelimiter);
104         else if (isValidOld(old))
105             out.print(isValidNew(newReg) && isDangerNew(newReg) ? dangerDelimiter : delimiter);
106         else if (old == firstOld() - 1)
107             out.print(delimiter);
108         else
109             out.print(emptySpace);
110         if (dangerFrontier() >= firstNew()
111             && (newReg == dangerFrontier() || newReg == firstNew() - 1))
112             out.print(dangerBoundsDelimiter);
113         else if (isValidNew(newReg) || newReg == firstNew() - 1)
114             out.print(isDangerNew(newReg) ? dangerDelimiter : delimiter);
115         else
116             out.print(emptySpace);
117         out.print("\n");
118         if (old == firstOld())
119             out.print(" sp --> ");
120         else if (!old.offset())
121             out.print(" fp --> ");
122         else
123             out.print("        ");
124         if (isValidOld(old)) {
125             if (getOld(old)) {
126                 auto str = toCString(old);
127                 if (isValidNew(newReg) && isDangerNew(newReg))
128                     out.printf(" X      %18s       X ", str.data());
129                 else
130                     out.printf(" |      %18s       | ", str.data());
131             } else if (isValidNew(newReg) && isDangerNew(newReg))
132                 out.printf(" X%30s X ", "");
133             else
134                 out.printf(" |%30s | ", "");
135         } else
136             out.print(emptySpace);
137         if (isValidNew(newReg)) {
138             const char d = isDangerNew(newReg) ? 'X' : '|';
139             auto str = toCString(newReg);
140             if (getNew(newReg)) {
141                 if (getNew(newReg)->recovery().isConstant())
142                     out.printf(" %c%8s <-           constant %c ", d, str.data(), d);
143                 else {
144                     auto recoveryStr = toCString(getNew(newReg)->recovery());
145                     out.printf(" %c%8s <- %18s %c ", d, str.data(),
146                         recoveryStr.data(), d);
147                 }
148             } else if (newReg == VirtualRegister { JSStack::ArgumentCount })
149                 out.printf(" %c%8s <- %18zu %c ", d, str.data(), argCount(), d);
150             else
151                 out.printf(" %c%30s %c ", d, "", d);
152         } else
153             out.print(emptySpace);
154         if (newReg == firstNew() - m_newFrameOffset && !isSlowPath())
155             out.print(" <-- new sp before jump (current ", m_newFrameBase, ") ");
156         if (newReg == firstNew())
157             out.print(" <-- new fp after prologue");
158         out.print("\n");
159     }
160     out.print("          ");
161     out.print("        Live registers             ");
162     out.print("        Wanted registers           ");
163     out.print("\n");
164     for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
165         CachedRecovery* oldCachedRecovery { m_registers[reg] };
166         CachedRecovery* newCachedRecovery { m_newRegisters[reg] };
167         if (!oldCachedRecovery && !newCachedRecovery)
168             continue;
169         out.print("          ");
170         if (oldCachedRecovery) {
171             auto str = toCString(reg);
172             out.printf("         %8s                  ", str.data());
173         } else
174             out.print(emptySpace);
175 #if USE(JSVALUE32_64)
176         if (newCachedRecovery) {
177             JSValueRegs wantedJSValueRegs { newCachedRecovery->wantedJSValueRegs() };
178             if (reg.isFPR())
179                 out.print(reg, " <- ", newCachedRecovery->recovery());
180             else {
181                 if (reg.gpr() == wantedJSValueRegs.tagGPR())
182                     out.print(reg.gpr(), " <- tag(", newCachedRecovery->recovery(), ")");
183                 else
184                     out.print(reg.gpr(), " <- payload(", newCachedRecovery->recovery(), ")");
185             }
186         }
187 #else
188         if (newCachedRecovery)
189             out.print("         ", reg, " <- ", newCachedRecovery->recovery());
190 #endif
191         out.print("\n");
192     }
193     out.print("  Locked registers: ");
194     bool firstLocked { true };
195     for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
196         if (m_lockedRegisters.get(reg)) {
197             out.print(firstLocked ? "" : ", ", reg);
198             firstLocked = false;
199         }
200     }
201     out.print("\n");
202
203     if (isSlowPath())
204         out.print("  Using fp-relative addressing for slow path call\n");
205     else
206         out.print("  Using sp-relative addressing for jump (using ", m_newFrameBase, " as new sp)\n");
207     if (m_oldFrameOffset)
208         out.print("   Old frame offset is ", m_oldFrameOffset, "\n");
209     if (m_newFrameOffset)
210         out.print("   New frame offset is ", m_newFrameOffset, "\n");
211 #if USE(JSVALUE64)
212     if (m_tagTypeNumber != InvalidGPRReg)
213         out.print("   TagTypeNumber is currently in ", m_tagTypeNumber, "\n");
214 #endif
215 }
216
217 CachedRecovery* CallFrameShuffler::getCachedRecovery(ValueRecovery recovery)
218 {
219     ASSERT(!recovery.isConstant());
220     if (recovery.isInGPR())
221         return m_registers[recovery.gpr()];
222     if (recovery.isInFPR())
223         return m_registers[recovery.fpr()];
224 #if USE(JSVALUE32_64)
225     if (recovery.technique() == InPair) {
226         ASSERT(m_registers[recovery.tagGPR()] == m_registers[recovery.payloadGPR()]);
227         return m_registers[recovery.payloadGPR()];
228     }
229 #endif
230     ASSERT(recovery.isInJSStack());
231     return getOld(recovery.virtualRegister());
232 }
233
234 CachedRecovery* CallFrameShuffler::setCachedRecovery(ValueRecovery recovery, CachedRecovery* cachedRecovery)
235 {
236     ASSERT(!recovery.isConstant());
237     if (recovery.isInGPR())
238         return m_registers[recovery.gpr()] = cachedRecovery;
239     if (recovery.isInFPR())
240         return m_registers[recovery.fpr()] = cachedRecovery;
241 #if USE(JSVALUE32_64)
242     if (recovery.technique() == InPair) {
243         m_registers[recovery.tagGPR()] = cachedRecovery;
244         return m_registers[recovery.payloadGPR()] = cachedRecovery;
245     }
246 #endif
247     ASSERT(recovery.isInJSStack());
248     setOld(recovery.virtualRegister(), cachedRecovery);
249     return cachedRecovery;
250 }
251
252 void CallFrameShuffler::spill(CachedRecovery& cachedRecovery)
253 {
254     ASSERT(!isSlowPath());
255     ASSERT(cachedRecovery.recovery().isInRegisters());
256
257     VirtualRegister spillSlot { 0 };
258     for (VirtualRegister slot = firstOld(); slot <= lastOld(); slot += 1) {
259         if (slot >= newAsOld(firstNew()))
260             break;
261
262         if (getOld(slot))
263             continue;
264
265         spillSlot = slot;
266         break;
267     }
268     // We must have enough slots to be able to fit the whole callee's
269     // frame for the slow path - unless we are in the FTL. In that
270     // case, we are allowed to extend the frame *once*, since we are
271     // guaranteed to have enough available space for that.
272     if (spillSlot >= newAsOld(firstNew()) || !spillSlot.isLocal()) {
273         RELEASE_ASSERT(!m_didExtendFrame);
274         extendFrameIfNeeded();
275         spill(cachedRecovery);
276         return;
277     }
278
279     if (verbose)
280         dataLog("   * Spilling ", cachedRecovery.recovery(), " into ", spillSlot, "\n");
281     auto format = emitStore(cachedRecovery, addressForOld(spillSlot));
282     ASSERT(format != DataFormatNone);
283     updateRecovery(cachedRecovery, ValueRecovery::displacedInJSStack(spillSlot, format));
284 }
285
286 void CallFrameShuffler::emitDeltaCheck()
287 {
288     if (ASSERT_DISABLED)
289         return;
290
291     GPRReg scratchGPR { getFreeGPR() };
292     if (scratchGPR != InvalidGPRReg) {
293         if (verbose)
294             dataLog("  Using ", scratchGPR, " for the fp-sp delta check\n");
295         m_jit.move(MacroAssembler::stackPointerRegister, scratchGPR);
296         m_jit.subPtr(GPRInfo::callFrameRegister, scratchGPR);
297         MacroAssembler::Jump ok = m_jit.branch32(
298             MacroAssembler::Equal, scratchGPR,
299             MacroAssembler::TrustedImm32(-numLocals() * sizeof(Register)));
300         m_jit.abortWithReason(JITUnexpectedCallFrameSize);
301         ok.link(&m_jit);
302     } else if (verbose)
303         dataLog("  Skipping the fp-sp delta check since there is too much pressure");
304 }
305
306 void CallFrameShuffler::extendFrameIfNeeded()
307 {
308     ASSERT(!m_didExtendFrame);
309
310     VirtualRegister firstRead { firstOld() };
311     for (; firstRead <= virtualRegisterForLocal(0); firstRead += 1) {
312         if (getOld(firstRead))
313             break;
314     }
315     size_t availableSize = static_cast<size_t>(firstRead.offset() - firstOld().offset());
316     size_t wantedSize = m_newFrame.size() + m_newFrameOffset;
317
318     if (availableSize < wantedSize) {
319         size_t delta = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), wantedSize - availableSize);
320         m_oldFrame.grow(m_oldFrame.size() + delta);
321         for (size_t i = 0; i < delta; ++i)
322             m_oldFrame[m_oldFrame.size() - i - 1] = nullptr;
323         m_jit.subPtr(MacroAssembler::TrustedImm32(delta * sizeof(Register)), MacroAssembler::stackPointerRegister);
324
325         if (isSlowPath())
326             m_frameDelta = numLocals() + JSStack::CallerFrameAndPCSize;
327         else
328             m_oldFrameOffset = numLocals();
329
330         if (verbose)
331             dataLogF("  Not enough space - extending the old frame %zu slot\n", delta);
332     }
333
334     m_didExtendFrame = true;
335 }
336
337 void CallFrameShuffler::prepareForSlowPath()
338 {
339     ASSERT(isUndecided());
340     emitDeltaCheck();
341
342     m_frameDelta = numLocals() + JSStack::CallerFrameAndPCSize;
343     m_newFrameBase = MacroAssembler::stackPointerRegister;
344     m_newFrameOffset = -JSStack::CallerFrameAndPCSize;
345
346     if (verbose)
347         dataLog("\n\nPreparing frame for slow path call:\n");
348
349     // When coming from the FTL, we need to extend the frame. In other
350     // cases, we may end up extending the frame if we previously
351     // spilled things (e.g. in polymorphic cache).
352     extendFrameIfNeeded();
353
354     if (verbose)
355         dataLog(*this);
356
357     prepareAny();
358
359     if (verbose)
360         dataLog("Ready for slow path call!\n");
361 }
362
363 void CallFrameShuffler::prepareForTailCall()
364 {
365     ASSERT(isUndecided());
366     emitDeltaCheck();
367
368     // We'll use sp-based indexing so that we can load the
369     // caller's frame pointer into the fpr immediately
370     m_oldFrameBase = MacroAssembler::stackPointerRegister;
371     m_oldFrameOffset = numLocals();
372     m_newFrameBase = acquireGPR();
373 #if CPU(X86)
374     // We load the frame pointer manually, but we need to ask the
375     // algorithm to move the return PC for us (it'd probably
376     // require a write to the danger zone). Since it'd be awkward
377     // to ask for half a value move, we ask that the whole thing
378     // be moved for us.
379     addNew(VirtualRegister { 0 },
380         ValueRecovery::displacedInJSStack(VirtualRegister(0), DataFormatJS));
381
382     // sp will point to head0 and we will move it up half a slot
383     // manually
384     m_newFrameOffset = 0;
385 #elif CPU(ARM) || CPU(SH4) || CPU(MIPS)
386     // We load the the frame pointer and link register
387     // manually. We could ask the algorithm to load them for us,
388     // and it would allow us to use the link register as an extra
389     // temporary - but it'd mean that the frame pointer can also
390     // be used as an extra temporary, so we keep the link register
391     // locked instead.
392
393     // sp will point to head1 since the callee's prologue pushes
394     // the call frame and link register.
395     m_newFrameOffset = -1;
396 #elif CPU(ARM64)
397     // We load the frame pointer and link register manually. We
398     // could ask the algorithm to load the link register for us
399     // (which would allow for its use as an extra temporary), but
400     // since its not in GPRInfo, we can't do it.
401
402     // sp will point to head2 since the callee's prologue pushes the
403     // call frame and link register
404     m_newFrameOffset = -2;
405 #elif CPU(X86_64)
406     // We load the frame pointer manually, but we ask the
407     // algorithm to move the return PC for us (it'd probably
408     // require a write in the danger zone)
409     addNew(VirtualRegister { 1 },
410         ValueRecovery::displacedInJSStack(VirtualRegister(1), DataFormatJS));
411
412     // sp will point to head1 since the callee's prologue pushes
413     // the call frame register
414     m_newFrameOffset = -1;
415 #else
416     UNREACHABLE_FOR_PLATFORM();
417 #endif
418
419     if (verbose)
420         dataLog("  Emitting code for computing the new frame base\n");
421
422     // We compute the new frame base by first computing the top of the
423     // old frame (taking into account an argument count higher than
424     // the number of parameters), then substracting to it the aligned
425     // new frame size (adjusted).
426     m_jit.load32(MacroAssembler::Address(GPRInfo::callFrameRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), m_newFrameBase);
427     MacroAssembler::Jump argumentCountOK =
428         m_jit.branch32(MacroAssembler::BelowOrEqual, m_newFrameBase,
429             MacroAssembler::TrustedImm32(m_jit.codeBlock()->numParameters()));
430     m_jit.add32(MacroAssembler::TrustedImm32(stackAlignmentRegisters() - 1 + JSStack::CallFrameHeaderSize), m_newFrameBase);
431     m_jit.and32(MacroAssembler::TrustedImm32(-stackAlignmentRegisters()), m_newFrameBase);
432     m_jit.mul32(MacroAssembler::TrustedImm32(sizeof(Register)), m_newFrameBase, m_newFrameBase);
433     MacroAssembler::Jump done = m_jit.jump();
434     argumentCountOK.link(&m_jit);
435     m_jit.move(
436         MacroAssembler::TrustedImm32(m_alignedOldFrameSize * sizeof(Register)),
437         m_newFrameBase);
438     done.link(&m_jit);
439
440     m_jit.addPtr(GPRInfo::callFrameRegister, m_newFrameBase);
441     m_jit.subPtr(
442         MacroAssembler::TrustedImm32(
443             (m_alignedNewFrameSize + m_newFrameOffset) * sizeof(Register)), 
444         m_newFrameBase);
445
446     // We load the link register manually for architectures that have one
447 #if CPU(ARM) || CPU(SH4) || CPU(ARM64)
448     m_jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister, sizeof(void*)),
449         MacroAssembler::linkRegister);
450 #elif CPU(MIPS)
451     m_jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister, sizeof(void*)),
452         MacroAssembler::returnAddressRegister);
453 #endif
454
455     // We want the frame pointer to always point to a valid frame, and
456     // we are going to trash the current one. Let's make it point to
457     // our caller's frame, since that's what we want to end up with.
458     m_jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister),
459         MacroAssembler::framePointerRegister);
460
461     if (verbose)
462         dataLog("Preparing frame for tail call:\n", *this);
463
464     prepareAny();
465
466 #if CPU(X86)
467     if (verbose)
468         dataLog("  Simulating pop of the call frame register\n");
469     m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(void*)), MacroAssembler::stackPointerRegister);
470 #endif
471
472     if (verbose)
473         dataLog("Ready for tail call!\n");
474 }
475
476 bool CallFrameShuffler::tryWrites(CachedRecovery& cachedRecovery)
477 {
478     ASSERT(m_newFrameBase != InvalidGPRReg);
479
480     // If the value is already set up correctly, we don't have
481     // anything to do.
482     if (isSlowPath() && cachedRecovery.recovery().isInJSStack()
483         && cachedRecovery.targets().size() == 1
484         && newAsOld(cachedRecovery.targets()[0]) == cachedRecovery.recovery().virtualRegister()) {
485         cachedRecovery.clearTargets();
486         if (!cachedRecovery.wantedJSValueRegs() && cachedRecovery.wantedFPR() == InvalidFPRReg)
487             clearCachedRecovery(cachedRecovery.recovery());
488         return true;
489     }
490
491     if (!canLoadAndBox(cachedRecovery))
492         return false;
493
494     emitLoad(cachedRecovery);
495     emitBox(cachedRecovery);
496     ASSERT(cachedRecovery.recovery().isInRegisters()
497         || cachedRecovery.recovery().isConstant());
498
499     if (verbose)
500         dataLog("   * Storing ", cachedRecovery.recovery());
501     for (size_t i = 0; i < cachedRecovery.targets().size(); ++i) {
502         VirtualRegister target { cachedRecovery.targets()[i] };
503         ASSERT(!isDangerNew(target));
504         if (verbose)
505             dataLog(!i ? " into " : ", and ", "NEW ", target);
506         emitStore(cachedRecovery, addressForNew(target));
507         setNew(target, nullptr);
508     }
509     if (verbose)
510         dataLog("\n");
511     cachedRecovery.clearTargets();
512     if (!cachedRecovery.wantedJSValueRegs() && cachedRecovery.wantedFPR() == InvalidFPRReg)
513         clearCachedRecovery(cachedRecovery.recovery());
514
515     return true;
516 }
517
518 bool CallFrameShuffler::performSafeWrites()
519 {
520     VirtualRegister firstSafe;
521     VirtualRegister end { lastNew() + 1 };
522     Vector<VirtualRegister> failures;
523
524     // For all cachedRecoveries that writes to the safe zone, if it
525     // doesn't also write to the danger zone, we try to perform
526     // the writes. This may free up danger slots, so we iterate
527     // again until it doesn't happen anymore.
528     //
529     // Note that even though we have a while block, we look at
530     // each slot of the new call frame at most once since in each
531     // iteration beyond the first, we only load up the portion of
532     // the new call frame that was dangerous and became safe due
533     // to the previous iteration.
534     do {
535         firstSafe = dangerFrontier() + 1;
536         if (verbose)
537             dataLog("  Trying safe writes (between NEW ", firstSafe, " and NEW ", end - 1, ")\n");
538         bool didProgress = false;
539         for (VirtualRegister reg = firstSafe; reg < end; reg += 1) {
540             CachedRecovery* cachedRecovery = getNew(reg);
541             if (!cachedRecovery) {
542                 if (verbose)
543                     dataLog("   + ", reg, " is OK.\n");
544                 continue;
545             }
546             if (!hasOnlySafeWrites(*cachedRecovery)) {
547                 if (verbose) {
548                     dataLog("   - ", cachedRecovery->recovery(), " writes to NEW ", reg,
549                         " but also has dangerous writes.\n");
550                 }
551                 continue;
552             }
553             if (cachedRecovery->wantedJSValueRegs()) {
554                 if (verbose) {
555                     dataLog("   - ", cachedRecovery->recovery(), " writes to NEW ", reg,
556                         " but is also needed in registers.\n");
557                 }
558                 continue;
559             }
560             if (cachedRecovery->wantedFPR() != InvalidFPRReg) {
561                 if (verbose) {
562                     dataLog("   - ", cachedRecovery->recovery(), " writes to NEW ", reg,
563                         " but is also needed in an FPR.\n");
564                 }
565                 continue;
566             }
567             if (!tryWrites(*cachedRecovery)) {
568                 if (verbose)
569                     dataLog("   - Unable to write to NEW ", reg, " from ", cachedRecovery->recovery(), "\n");
570                 failures.append(reg);
571             }
572             didProgress = true;
573         }
574         end = firstSafe;
575
576         // If we have cachedRecoveries that failed to write, it is
577         // because they are on the stack and we didn't have enough
578         // registers available at the time to load them into. If
579         // we have a free register, we should try again because it
580         // could free up some danger slots.
581         if (didProgress && hasFreeRegister()) {
582             Vector<VirtualRegister> stillFailing;
583             for (VirtualRegister failed : failures) {
584                 CachedRecovery* cachedRecovery = getNew(failed);
585                 // It could have been handled later if it had
586                 // several targets
587                 if (!cachedRecovery)
588                     continue;
589
590                 ASSERT(hasOnlySafeWrites(*cachedRecovery)
591                     && !cachedRecovery->wantedJSValueRegs()
592                     && cachedRecovery->wantedFPR() == InvalidFPRReg);
593                 if (!tryWrites(*cachedRecovery))
594                     stillFailing.append(failed);
595             }
596             failures = WTFMove(stillFailing);
597         }
598         if (verbose && firstSafe != dangerFrontier() + 1)
599             dataLog("  We freed up danger slots!\n");
600     } while (firstSafe != dangerFrontier() + 1);
601
602     return failures.isEmpty();
603 }
604
605 void CallFrameShuffler::prepareAny()
606 {
607     ASSERT(!isUndecided());
608
609     updateDangerFrontier();
610
611     // First, we try to store any value that goes above the danger
612     // frontier. This will never use more registers since we are only
613     // loading+storing if we ensure that any register used for the load
614     // will be freed up after the stores (i.e., all stores are above
615     // the danger frontier, and there is no wanted register).
616     performSafeWrites();
617
618     // At this point, we couldn't have more available registers than
619     // we have withouth spilling: all values currently in registers
620     // either require a write to the danger zone, or have a wanted
621     // register, which means that in any case they will have to go
622     // through registers again.
623
624     // We now slowly free up the danger zone by first loading the old
625     // value on the danger frontier, spilling as many registers as
626     // needed to do so and ensuring that the corresponding slot in the
627     // new frame is now ready to be written. Then, we store the old
628     // value to its target location if possible (we could have failed
629     // to load it previously due to high pressure). Finally, we write
630     // to any of the newly safe slots that we can, which could free up
631     // registers (hence why we do it eagerly).
632     for (VirtualRegister reg = dangerFrontier(); reg >= firstNew(); reg -= 1) {
633         if (reg == dangerFrontier()) {
634             if (verbose)
635                 dataLog("  Next slot (NEW ", reg, ") is the danger frontier\n");
636             CachedRecovery* cachedRecovery { getOld(newAsOld(dangerFrontier())) };
637             ASSERT(cachedRecovery);
638             ensureLoad(*cachedRecovery);
639             emitLoad(*cachedRecovery);
640             ensureBox(*cachedRecovery);
641             emitBox(*cachedRecovery);
642             if (hasOnlySafeWrites(*cachedRecovery))
643                 tryWrites(*cachedRecovery);
644         } else if (verbose)
645             dataLog("  Next slot is NEW ", reg, "\n");
646
647         ASSERT(!isDangerNew(reg));
648         CachedRecovery* cachedRecovery = getNew(reg);
649         // This could be one of the header slots we don't care about.
650         if (!cachedRecovery) {
651             if (verbose)
652                 dataLog("   + ", reg, " is OK\n");
653             continue;
654         }
655
656         if (canLoadAndBox(*cachedRecovery) && hasOnlySafeWrites(*cachedRecovery)
657             && !cachedRecovery->wantedJSValueRegs()
658             && cachedRecovery->wantedFPR() == InvalidFPRReg) {
659             emitLoad(*cachedRecovery);
660             emitBox(*cachedRecovery);
661             bool writesOK = tryWrites(*cachedRecovery);
662             ASSERT_UNUSED(writesOK, writesOK);
663         } else if (verbose)
664             dataLog("   - ", cachedRecovery->recovery(), " can't be handled just yet.\n");
665     }
666     ASSERT(dangerFrontier() < firstNew());
667
668     // Now, the danger zone is empty, but we still have a couple of
669     // things to do:
670     //
671     // 1) There could be remaining safe writes that failed earlier due
672     //    to high register pressure and had nothing to do with the
673     //    danger zone whatsoever.
674     //
675     // 2) Some wanted registers could have to be loaded (this could
676     //    happen either when making a call to a new function with a
677     //    lower number of arguments - since above here, we only load
678     //    wanted registers when they are at the danger frontier -, or
679     //    if a wanted register got spilled).
680     //
681     // 3) Some wanted registers could have been loaded in the wrong
682     //    registers
683     //
684     // 4) We have to take care of some bookkeeping - namely, storing
685     //    the argument count and updating the stack pointer.
686
687     // At this point, we must have enough registers available for
688     // handling 1). None of the loads can fail because we have been
689     // eagerly freeing up registers in all the previous phases - so
690     // the only values that are in registers at this point must have
691     // wanted registers.
692     if (verbose)
693         dataLog("  Danger zone is clear, performing remaining writes.\n");
694     for (VirtualRegister reg = firstNew(); reg <= lastNew(); reg += 1) {
695         CachedRecovery* cachedRecovery { getNew(reg) };
696         if (!cachedRecovery)
697             continue;
698
699         emitLoad(*cachedRecovery);
700         emitBox(*cachedRecovery);
701         bool writesOK = tryWrites(*cachedRecovery);
702         ASSERT_UNUSED(writesOK, writesOK);
703     }
704
705 #if USE(JSVALUE64)
706     if (m_tagTypeNumber != InvalidGPRReg && m_newRegisters[m_tagTypeNumber])
707         releaseGPR(m_tagTypeNumber);
708 #endif
709
710     // Handle 2) by loading all registers. We don't have to do any
711     // writes, since they have been taken care of above.
712     if (verbose)
713         dataLog("  Loading wanted registers into registers\n");
714     for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
715         CachedRecovery* cachedRecovery { m_newRegisters[reg] };
716         if (!cachedRecovery)
717             continue;
718
719         emitLoad(*cachedRecovery);
720         emitBox(*cachedRecovery);
721         ASSERT(cachedRecovery->targets().isEmpty());
722     }
723
724 #if USE(JSVALUE64)
725     if (m_tagTypeNumber != InvalidGPRReg)
726         releaseGPR(m_tagTypeNumber);
727 #endif
728
729     // At this point, we have read everything we cared about from the
730     // stack, and written everything we had to to the stack.
731     if (verbose)
732         dataLog("  Callee frame is fully set up\n");
733     if (!ASSERT_DISABLED) {
734         for (VirtualRegister reg = firstNew(); reg <= lastNew(); reg += 1)
735             ASSERT_UNUSED(reg, !getNew(reg));
736
737         for (CachedRecovery* cachedRecovery : m_cachedRecoveries) {
738             ASSERT_UNUSED(cachedRecovery, cachedRecovery->targets().isEmpty());
739             ASSERT(!cachedRecovery->recovery().isInJSStack());
740         }
741     }
742
743     // We need to handle 4) first because it implies releasing
744     // m_newFrameBase, which could be a wanted register.
745     if (verbose)
746         dataLog("   * Storing the argument count into ", VirtualRegister { JSStack::ArgumentCount }, "\n");
747     m_jit.store32(MacroAssembler::TrustedImm32(0),
748         addressForNew(VirtualRegister { JSStack::ArgumentCount }).withOffset(TagOffset));
749     m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
750         addressForNew(VirtualRegister { JSStack::ArgumentCount }).withOffset(PayloadOffset));
751
752     if (!isSlowPath()) {
753         ASSERT(m_newFrameBase != MacroAssembler::stackPointerRegister);
754         if (verbose)
755             dataLog("  Releasing the new frame base pointer\n");
756         m_jit.move(m_newFrameBase, MacroAssembler::stackPointerRegister);
757         releaseGPR(m_newFrameBase);
758     }
759
760     // Finally we handle 3)
761     if (verbose)
762         dataLog("  Ensuring wanted registers are in the right register\n");
763     for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
764         CachedRecovery* cachedRecovery { m_newRegisters[reg] };
765         if (!cachedRecovery)
766             continue;
767
768         emitDisplace(*cachedRecovery);
769     }
770 }
771
772 } // namespace JSC
773
774 #endif // ENABLE(JIT)