bool checkCalleeStackOverflow(const ActRec* calleeAR) { auto const func = calleeAR->func(); auto const limit = func->maxStackCells() + kStackCheckPadding; const void* const needed_top = reinterpret_cast<const TypedValue*>(calleeAR) - limit; const void* const lower_limit = static_cast<char*>(vmRegsUnsafe().stack.getStackLowAddress()) + Stack::sSurprisePageSize; return needed_top < lower_limit; }
/* * Compute the stack and local type postconditions for a * single-entry/single-exit tracelet. */ std::vector<RegionDesc::TypePred> IRBuilder::getKnownTypes() { // This function is only correct when given a single-exit region, as // in TransProfile. Furthermore, its output is only used to guide // formation of profile-driven regions. assert(tx->mode() == TransProfile); // We want the state for the last block on the "main trace". Figure // out which that is. Block* mainExit = nullptr; for (auto* b : rpoSortCfg(m_unit)) { if (isMainExit(b)) { assert(mainExit == nullptr); mainExit = b; } } assert(mainExit != nullptr); // Load state for mainExit. This feels hacky. FTRACE(1, "mainExit: B{}\n", mainExit->id()); m_state.startBlock(mainExit); // Now use the current state to get all the types. std::vector<RegionDesc::TypePred> result; auto const curFunc = m_state.func(); auto const sp = m_state.sp(); auto const spOffset = m_state.spOffset(); for (unsigned i = 0; i < curFunc->maxStackCells(); ++i) { auto t = getStackValue(sp, i).knownType; if (!t.equals(Type::StackElem)) { result.push_back({ RegionDesc::Location::Stack{i, spOffset - i}, t }); } } for (unsigned i = 0; i < curFunc->numLocals(); ++i) { auto t = m_state.localType(i); if (!t.equals(Type::Gen)) { FTRACE(1, "Local {}: {}\n", i, t.toString()); result.push_back({ RegionDesc::Location::Local{i}, t }); } } return result; }
std::vector<RegionDesc::TypePred> IRBuilder::getKnownTypes() const { std::vector<RegionDesc::TypePred> result; auto const curFunc = m_state.func(); auto const sp = m_state.sp(); auto const spOffset = m_state.spOffset(); for (unsigned i = 0; i < curFunc->maxStackCells(); ++i) { auto t = getStackValue(sp, i).knownType; if (!t.equals(Type::StackElem)) { result.push_back({ RegionDesc::Location::Stack{i, spOffset - i}, t }); } } for (unsigned i = 0; i < curFunc->numLocals(); ++i) { auto t = m_state.localType(i); if (!t.equals(Type::Gen)) { result.push_back({ RegionDesc::Location::Local{i}, t }); } } return result; }
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; }); }