static void registerClobberCheck(AssemblyHelpers& jit, RegisterSet dontClobber) { if (!Options::clobberAllRegsInFTLICSlowPath()) return; RegisterSet clobber = RegisterSet::allRegisters(); clobber.exclude(RegisterSet::reservedHardwareRegisters()); clobber.exclude(RegisterSet::stackRegisters()); clobber.exclude(RegisterSet::calleeSaveRegisters()); clobber.exclude(dontClobber); GPRReg someGPR; for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) { if (!clobber.get(reg) || !reg.isGPR()) continue; jit.move(AssemblyHelpers::TrustedImm32(0x1337beef), reg.gpr()); someGPR = reg.gpr(); } for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) { if (!clobber.get(reg) || !reg.isFPR()) continue; jit.move64ToDouble(someGPR, reg.fpr()); } }
void CallFrameShuffler::emitDisplace(CachedRecovery& cachedRecovery) { Reg wantedReg; if (!(wantedReg = Reg { cachedRecovery.wantedJSValueRegs().gpr() })) wantedReg = Reg { cachedRecovery.wantedFPR() }; ASSERT(wantedReg); ASSERT(!m_lockedRegisters.get(wantedReg)); if (CachedRecovery* current = m_registers[wantedReg]) { if (current == &cachedRecovery) { if (verbose) dataLog(" + ", wantedReg, " is OK\n"); return; } // We could do a more complex thing by finding cycles // etc. in that case. // However, ending up in this situation will be super // rare, and should actually be outright impossible for // non-FTL tiers, since: // (a) All doubles have been converted into JSValues with // ValueRep nodes, so FPRs are initially free // // (b) The only recoveries with wanted registers are the // callee (which always starts out in a register) and // the callee-save registers // // (c) The callee-save registers are the first things we // load (after the return PC), and they are loaded as JSValues // // (d) We prefer loading JSValues into FPRs if their // wanted GPR is not available // // (e) If we end up spilling some registers with a // target, we won't load them again before the very // end of the algorithm // // Combined, this means that we will never load a recovery // with a wanted GPR into any GPR other than its wanted // GPR. The callee could however have been initially in // one of the callee-save registers - but since the wanted // GPR for the callee is always regT0, it will be the // first one to be displaced, and we won't see it when // handling any of the callee-save registers. // // Thus, the only way we could ever reach this path is in // the FTL, when there is so much pressure that we // absolutely need to load the callee-save registers into // different GPRs initially but not enough pressure to // then have to spill all of them. And even in that case, // depending on the order in which B3 saves the // callee-saves, we will probably still be safe. Anyway, // the couple extra move instructions compared to an // efficient cycle-based algorithm are not going to hurt // us. if (wantedReg.isFPR()) { FPRReg tempFPR = getFreeFPR(); if (verbose) dataLog(" * Moving ", wantedReg, " into ", tempFPR, "\n"); m_jit.moveDouble(wantedReg.fpr(), tempFPR); updateRecovery(*current, ValueRecovery::inFPR(tempFPR, current->recovery().dataFormat())); } else { GPRReg tempGPR = getFreeGPR(); if (verbose) dataLog(" * Moving ", wantedReg.gpr(), " into ", tempGPR, "\n"); m_jit.move(wantedReg.gpr(), tempGPR); updateRecovery(*current, ValueRecovery::inGPR(tempGPR, current->recovery().dataFormat())); } } ASSERT(!m_registers[wantedReg]); if (cachedRecovery.recovery().isConstant()) { // We only care about callee saves for wanted FPRs, and those are never constants ASSERT(wantedReg.isGPR()); if (verbose) dataLog(" * Loading ", cachedRecovery.recovery().constant(), " into ", wantedReg, "\n"); m_jit.moveTrustedValue(cachedRecovery.recovery().constant(), JSValueRegs { wantedReg.gpr() }); updateRecovery( cachedRecovery, ValueRecovery::inRegister(wantedReg, DataFormatJS)); } else if (cachedRecovery.recovery().isInGPR()) { if (verbose) dataLog(" * Moving ", cachedRecovery.recovery(), " into ", wantedReg, "\n"); if (wantedReg.isGPR()) m_jit.move(cachedRecovery.recovery().gpr(), wantedReg.gpr()); else m_jit.move64ToDouble(cachedRecovery.recovery().gpr(), wantedReg.fpr()); RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS); updateRecovery(cachedRecovery, ValueRecovery::inRegister(wantedReg, DataFormatJS)); } else { ASSERT(cachedRecovery.recovery().isInFPR()); if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) { // We only care about callee saves for wanted FPRs, and those are always DataFormatJS ASSERT(wantedReg.isGPR()); // This will automatically pick the wanted GPR emitBox(cachedRecovery); } else { if (verbose) dataLog(" * Moving ", cachedRecovery.recovery().fpr(), " into ", wantedReg, "\n"); if (wantedReg.isGPR()) m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), wantedReg.gpr()); else m_jit.moveDouble(cachedRecovery.recovery().fpr(), wantedReg.fpr()); RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS); updateRecovery(cachedRecovery, ValueRecovery::inRegister(wantedReg, DataFormatJS)); } } ASSERT(m_registers[wantedReg] == &cachedRecovery); }