void clobberFuncGuards(const Func* func) { int maxNumPrologues = func->getMaxNumPrologues(func->numParams()); int numPrologues = maxNumPrologues > kNumFixedPrologues ? maxNumPrologues : kNumFixedPrologues; for (auto i = 0; i < numPrologues; ++i) { auto const guard = funcGuardFromPrologue(func->getPrologue(i), func); if (funcGuardMatches(guard, func)) { clobberFuncGuard(guard, func); } } }
void emitFuncGuard(const Func* func, CodeBlock& cb, CGMeta& fixups) { ppc64_asm::Assembler a { cb }; const auto tmp1 = ppc64_asm::reg::r3; const auto tmp2 = ppc64_asm::reg::r4; assertx(ppc64::abi(CodeKind::CrossTrace).gpUnreserved.contains(tmp1)); assertx(ppc64::abi(CodeKind::CrossTrace).gpUnreserved.contains(tmp2)); emitSmashableMovq(a.code(), fixups, uint64_t(func), tmp1); a. ld (tmp2, rvmfp()[AROFF(m_func)]); a. cmpd (tmp1, tmp2); a. branchFar(tc::ustubs().funcPrologueRedispatch, ppc64_asm::BranchConditions::NotEqual); DEBUG_ONLY auto guard = funcGuardFromPrologue(a.frontier(), func); assertx(funcGuardMatches(guard, func)); }
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; }
static TCA emitFuncPrologueImpl(Func* func, int argc, TransKind kind) { if (!newTranslation()) { return nullptr; } const int nparams = func->numNonVariadicParams(); const int paramIndex = argc <= nparams ? argc : nparams + 1; auto const funcBody = SrcKey{func, func->getEntryForNumArgs(argc), false}; profileSetHotFuncAttr(); auto codeLock = lockCode(); auto codeView = code().view(kind); TCA mainOrig = codeView.main().frontier(); CGMeta fixups; // If we're close to a cache line boundary, just burn some space to // try to keep the func and its body on fewer total lines. align(codeView.main(), &fixups, Alignment::CacheLineRoundUp, AlignContext::Dead); TransLocMaker maker(codeView); maker.markStart(); // Careful: this isn't necessarily the real entry point. For funcIsMagic // prologues, this is just a possible prologue. TCA aStart = codeView.main().frontier(); // Give the prologue a TransID if we have profiling data. auto const transID = [&]{ if (kind == TransKind::ProfPrologue) { auto const profData = jit::profData(); auto const id = profData->allocTransID(); profData->addTransProfPrologue(id, funcBody, paramIndex); return id; } if (profData() && transdb::enabled()) { return profData()->allocTransID(); } return kInvalidTransID; }(); TCA start = genFuncPrologue(transID, kind, func, argc, codeView, fixups); auto loc = maker.markEnd(); auto metaLock = lockMetadata(); if (RuntimeOption::EvalEnableReusableTC) { TCA UNUSED ms = loc.mainStart(), me = loc.mainEnd(), cs = loc.coldStart(), ce = loc.coldEnd(), fs = loc.frozenStart(), fe = loc.frozenEnd(), oldStart = start; auto const did_relocate = relocateNewTranslation(loc, codeView, fixups, &start); if (did_relocate) { FTRACE_MOD(Trace::reusetc, 1, "Relocated prologue for func {} (id = {}) " "from M[{}, {}], C[{}, {}], F[{}, {}] to M[{}, {}] " "C[{}, {}] F[{}, {}] orig start @ {} new start @ {}\n", func->fullName()->data(), func->getFuncId(), ms, me, cs, ce, fs, fe, loc.mainStart(), loc.mainEnd(), loc.coldStart(), loc.coldEnd(), loc.frozenStart(), loc.frozenEnd(), oldStart, start); } else { FTRACE_MOD(Trace::reusetc, 1, "Created prologue for func {} (id = {}) at " "M[{}, {}], C[{}, {}], F[{}, {}] start @ {}\n", func->fullName()->data(), func->getFuncId(), ms, me, cs, ce, fs, fe, oldStart); } recordFuncPrologue(func, loc); if (loc.mainStart() != aStart) { codeView.main().setFrontier(mainOrig); // we may have shifted to align } } if (RuntimeOption::EvalPerfRelocate) { GrowableVector<IncomingBranch> incomingBranches; recordPerfRelocMap(loc.mainStart(), loc.mainEnd(), loc.coldCodeStart(), loc.coldEnd(), funcBody, paramIndex, incomingBranches, fixups); } fixups.process(nullptr); assertx(funcGuardMatches(funcGuardFromPrologue(start, func), func)); assertx(code().isValidCodeAddress(start)); TRACE(2, "funcPrologue %s(%d) setting prologue %p\n", func->fullName()->data(), argc, start); func->setPrologue(paramIndex, start); assertx(kind == TransKind::LivePrologue || kind == TransKind::ProfPrologue || kind == TransKind::OptPrologue); auto tr = maker.rec(funcBody, transID, kind); transdb::addTranslation(tr); if (RuntimeOption::EvalJitUseVtuneAPI) { reportTraceletToVtune(func->unit(), func, tr); } recordGdbTranslation(funcBody, func, codeView.main(), loc.mainStart(), false, true); recordBCInstr(OpFuncPrologue, loc.mainStart(), loc.mainEnd(), false); return start; }