void cgCheckSurpriseAndStack(IRLS& env, const IRInstruction* inst) { auto const fp = srcLoc(env, inst, 0).reg(); auto const extra = inst->extra<CheckSurpriseAndStack>(); auto const func = extra->func; auto const off = func->getEntryForNumArgs(extra->argc) - func->base(); auto const fixup = Fixup(off, func->numSlotsInFrame()); auto& v = vmain(env); auto const sf = v.makeReg(); auto const needed_top = v.makeReg(); v << lea{fp[-cellsToBytes(func->maxStackCells())], needed_top}; v << cmpqm{needed_top, rvmtl()[rds::kSurpriseFlagsOff], sf}; unlikelyIfThen(v, vcold(env), CC_AE, sf, [&] (Vout& v) { auto const stub = tc::ustubs().functionSurprisedOrStackOverflow; auto const done = v.makeBlock(); v << vinvoke{CallSpec::stub(stub), v.makeVcallArgs({}), v.makeTuple({}), {done, label(env, inst->taken())}, fixup }; v = done; }); }
bool RegionFormer::tryInline(uint32_t& instrSize) { assertx(m_inst.source == m_sk); assertx(m_inst.func() == curFunc()); assertx(m_sk.resumed() == resumed()); instrSize = 0; if (!m_inl.canInlineAt(m_inst.source, m_inst.funcd, *m_region)) { return false; } auto refuse = [this](const std::string& str) { FTRACE(2, "selectTracelet not inlining {}: {}\n", m_inst.toString(), str); return false; }; auto callee = m_inst.funcd; // Make sure the FPushOp wasn't interpreted. if (m_irgs.fpiStack.empty()) { return refuse("fpistack empty; fpush was in a different region"); } auto spillFrame = m_irgs.fpiStack.top().spillFrame; if (!spillFrame) { return refuse("couldn't find SpillFrame for FPushOp"); } auto numArgs = m_inst.imm[0].u_IVA; auto numParams = callee->numParams(); // Set up the region context, mapping stack slots in the caller to locals in // the callee. RegionContext ctx; ctx.func = callee; ctx.bcOffset = callee->getEntryForNumArgs(numArgs); ctx.spOffset = FPInvOffset{safe_cast<int32_t>(callee->numSlotsInFrame())}; ctx.resumed = false; for (int i = 0; i < numArgs; ++i) { auto type = irgen::publicTopType(m_irgs, BCSPOffset{i}); uint32_t paramIdx = numArgs - 1 - i; ctx.liveTypes.push_back({RegionDesc::Location::Local{paramIdx}, type}); } for (unsigned i = numArgs; i < numParams; ++i) { // These locals will be populated by DV init funclets but they'll start // out as Uninit. ctx.liveTypes.push_back({RegionDesc::Location::Local{i}, TUninit}); } FTRACE(1, "selectTracelet analyzing callee {} with context:\n{}", callee->fullName()->data(), show(ctx)); auto region = selectTracelet(ctx, m_profiling, false /* noinline */); if (!region) { return refuse("failed to select region in callee"); } instrSize = region->instrSize(); auto newInstrSize = instrSize + m_numBCInstrs + m_pendingInlinedInstrs; if (newInstrSize > RuntimeOption::EvalJitMaxRegionInstrs) { return refuse("new region would be too large"); } if (!m_inl.shouldInline(callee, *region)) { return refuse("shouldIRInline failed"); } return true; }