void reclaimFunction(const Func* func) { BlockingLeaseHolder writer(Translator::WriteLease()); auto it = s_funcTCData.find(func); if (it == s_funcTCData.end()) return; ITRACE(1, "Tearing down func {} (id={})\n", func->fullName()->data(), func->getFuncId()); Trace::Indent _i; auto& data = it->second; auto& us = mcg->ustubs(); ITRACE(1, "Smashing prologues\n"); clobberFuncGuards(func); for (auto& caller : data.callers) { ITRACE(1, "Unsmashing call @ {} (guard = {})\n", caller.first, caller.second.isGuard); // It should be impossible to reach a prologue that has been reclaimed // through an immutable stub, as this would imply the function is still // reachable. auto addr = caller.second.isGuard ? us.bindCallStub : nullptr; smashCall(caller.first, addr); s_smashedCalls.erase(caller.first); } auto movedData = folly::makeMoveWrapper(std::move(data)); auto fname = func->fullName()->data(); auto fid = func->getFuncId(); // We just smashed all of those callers-- treadmill the free to avoid a // race (threads executing callers may end up inside the guard even though // the function is now unreachable). Once the following block runs the guards // should be unreachable. Treadmill::enqueue([fname, fid, movedData] { BlockingLeaseHolder writer(Translator::WriteLease()); ITRACE(1, "Reclaiming func {} (id={})\n", fname, fid); Trace::Indent _i; { ITRACE(1, "Reclaiming Prologues\n"); Trace::Indent _i; for (auto& loc : movedData->prologues) { reclaimTranslation(loc); } } for (auto* rec : movedData->srcRecs) { reclaimSrcRec(rec); } }); s_funcTCData.erase(it); }
folly::Optional<std::pair<SrcKey,TransID>> updateFuncPrologue(TCA start, ProfTransRec* rec) { auto func = rec->func(); auto nArgs = rec->prologueArgs(); auto codeLock = lockCode(); // Smash callers of the old prologue with the address of the new one. for (auto toSmash : rec->mainCallers()) { smashCall(toSmash, start); } // If the prologue has a matching guard, then smash its guard-callers as // well. auto const guard = funcGuardFromPrologue(start, func); if (funcGuardMatches(guard, func)) { for (auto toSmash : rec->guardCallers()) { smashCall(toSmash, guard); } } rec->clearAllCallers(); // If this prologue has a DV funclet, then invalidate it and return its SrcKey // and TransID if (nArgs < func->numNonVariadicParams()) { auto paramInfo = func->params()[nArgs]; if (paramInfo.hasDefaultValue()) { SrcKey funcletSK(func, paramInfo.funcletOff, false); auto funcletTransId = profData()->dvFuncletTransId(func, nArgs); if (funcletTransId != kInvalidTransID) { invalidateSrcKey(funcletSK); return std::make_pair(funcletSK, funcletTransId); } } } return folly::none; }
void bindCall(TCA toSmash, TCA start, Func* callee, int nArgs, bool immutable) { auto codeLock = lockCode(); if (!start || smashableCallTarget(toSmash) == start) return; assertx(smashableCallTarget(toSmash)); TRACE(2, "bindCall smash %p -> %p\n", toSmash, start); smashCall(toSmash, start); bool is_profiled = false; // For functions to be PGO'ed, if their current prologues are still // profiling ones (living in code.prof()), then save toSmash as a // caller to the prologue, so that it can later be smashed to call a // new prologue when it's generated. int calleeNumParams = callee->numNonVariadicParams(); int calledPrologNumArgs = (nArgs <= calleeNumParams ? nArgs : calleeNumParams + 1); auto const profData = jit::profData(); if (profData != nullptr && code().prof().contains(start)) { auto rec = profData->prologueTransRec( callee, calledPrologNumArgs ); if (immutable) { rec->addMainCaller(toSmash); } else { rec->addGuardCaller(toSmash); } is_profiled = true; } // We need to be able to reclaim the function prologues once the unit // associated with this function is treadmilled-- so record all of the // callers that will need to be re-smashed // // Additionally for profiled calls we need to remove them from the main // and guard caller maps. if (RuntimeOption::EvalEnableReusableTC) { if (debug || is_profiled || !immutable) { auto metaLock = lockMetadata(); recordFuncCaller(callee, toSmash, immutable, is_profiled, calledPrologNumArgs); } } }