void IRTranslator::translateAsyncSuspend(const NormalizedInstruction& i) { if (m_hhbcTrans.resumed()) { HHIR_EMIT(AsyncSuspendR, i.nextSk().offset()); } else { HHIR_EMIT(AsyncSuspendE, i.nextSk().offset(), i.imm[0].u_IVA); } }
void IRTranslator::translateFCallArray(const NormalizedInstruction& i) { const Offset pcOffset = i.offset(); SrcKey next = i.nextSk(); const Offset after = next.offset(); HHIR_EMIT(FCallArray, pcOffset, after, jit::callDestroysLocals(i, m_hhbcTrans.curFunc())); }
void IRTranslator::translateFCall(const NormalizedInstruction& i) { auto const numArgs = i.imm[0].u_IVA; const PC after = m_hhbcTrans.curUnit()->at(i.nextSk().offset()); const Func* srcFunc = m_hhbcTrans.curFunc(); Offset returnBcOffset = srcFunc->unit()->offsetOf(after - srcFunc->base()); HHIR_EMIT(FCall, numArgs, returnBcOffset, i.funcd, jit::callDestroysLocals(i, m_hhbcTrans.curFunc())); }
void IRTranslator::translateFCall(const NormalizedInstruction& i) { auto const numArgs = i.imm[0].u_IVA; const PC after = m_hhbcTrans.curUnit()->at(i.nextSk().offset()); const Func* srcFunc = m_hhbcTrans.curFunc(); Offset returnBcOffset = srcFunc->unit()->offsetOf(after - srcFunc->base()); /* * If we have a calleeTrace, we're going to see if we should inline * the call. */ if (i.calleeTrace) { if (!i.calleeTrace->m_inliningFailed) { assert(shouldIRInline(m_hhbcTrans.curFunc(), i.funcd, *i.calleeTrace)); m_hhbcTrans.beginInlining(numArgs, i.funcd, returnBcOffset); static const bool shapeStats = Stats::enabledAny() && getenv("HHVM_STATS_INLINESHAPE"); if (shapeStats) { m_hhbcTrans.profileInlineFunctionShape(traceletShape(*i.calleeTrace)); } for (auto* ni = i.calleeTrace->m_instrStream.first; ni; ni = ni->next) { if (isAlwaysNop(ni->op())) { // This might not be necessary---but for now it's preserving // side effects of the call to readMetaData that used to // exist here. ni->noOp = true; } translateInstr(*ni); } return; } static const auto enabled = Stats::enabledAny() && getenv("HHVM_STATS_FAILEDINL"); if (enabled) { m_hhbcTrans.profileFunctionEntry("FailedCandidate"); m_hhbcTrans.profileFailedInlShape(traceletShape(*i.calleeTrace)); } } HHIR_EMIT(FCall, numArgs, returnBcOffset, i.funcd, JIT::callDestroysLocals(i, m_hhbcTrans.curFunc())); }
void IRTranslator::translateFCall(const NormalizedInstruction& i) { auto const numArgs = i.imm[0].u_IVA; const PC after = m_hhbcTrans.curUnit()->at(i.nextSk().offset()); const Func* srcFunc = m_hhbcTrans.curFunc(); Offset returnBcOffset = srcFunc->unit()->offsetOf(after - srcFunc->base()); /* * If we have a calleeTrace, we're going to see if we should inline * the call. */ if (i.calleeTrace) { if (!i.calleeTrace->m_inliningFailed) { assert(shouldIRInline(m_hhbcTrans.curFunc(), i.funcd, *i.calleeTrace)); m_hhbcTrans.beginInlining(numArgs, i.funcd, returnBcOffset); static const bool shapeStats = Stats::enabledAny() && getenv("HHVM_STATS_INLINESHAPE"); if (shapeStats) { m_hhbcTrans.profileInlineFunctionShape(traceletShape(*i.calleeTrace)); } Unit::MetaHandle metaHand; for (auto* ni = i.calleeTrace->m_instrStream.first; ni; ni = ni->next) { readMetaData(metaHand, *ni, m_hhbcTrans, false, MetaMode::Legacy); translateInstr(*ni); } return; } static const auto enabled = Stats::enabledAny() && getenv("HHVM_STATS_FAILEDINL"); if (enabled) { m_hhbcTrans.profileFunctionEntry("FailedCandidate"); m_hhbcTrans.profileFailedInlShape(traceletShape(*i.calleeTrace)); } } HHIR_EMIT(FCall, numArgs, returnBcOffset, i.funcd, JIT::callDestroysLocals(i, m_hhbcTrans.curFunc())); }
bool IRTranslator::tryTranslateSingletonInline(const NormalizedInstruction& i, const Func* funcd) { using Atom = BCPattern::Atom; using Captures = BCPattern::CaptureVec; if (!funcd) return false; // Make sure we have an acceptable FPush and non-null callee. assert(i.op() == Op::FPushFuncD || i.op() == Op::FPushClsMethodD); auto fcall = i.nextSk(); // Check if the next instruction is an acceptable FCall. if ((fcall.op() != Op::FCall && fcall.op() != Op::FCallD) || funcd->isResumable() || funcd->isReturnRef()) { return false; } // First, check for the static local singleton pattern... // Lambda to check if CGetL and StaticLocInit refer to the same local. auto has_same_local = [] (PC pc, const Captures& captures) { if (captures.size() == 0) return false; auto cgetl = (const Op*)pc; auto sli = (const Op*)captures[0]; assert(*cgetl == Op::CGetL); assert(*sli == Op::StaticLocInit); return (getImm(sli, 0).u_IVA == getImm(cgetl, 0).u_IVA); }; auto cgetl = Atom(Op::CGetL).onlyif(has_same_local); auto retc = Atom(Op::RetC); // Look for a static local singleton pattern. auto result = BCPattern { Atom(Op::Null), Atom(Op::StaticLocInit).capture(), Atom(Op::IsTypeL), Atom::alt( Atom(Op::JmpZ).taken({cgetl, retc}), Atom::seq(Atom(Op::JmpNZ), cgetl, retc) ) }.ignore( {Op::AssertRATL, Op::AssertRATStk} ).matchAnchored(funcd); if (result.found()) { try { hhbcTrans().emitSingletonSLoc( funcd, (const Op*)result.getCapture(0) ); } catch (const FailedIRGen& e) { return false; } catch (const FailedCodeGen& e) { return false; } TRACE(1, "[singleton-sloc] %s <- %s\n", funcd->fullName()->data(), fcall.func()->fullName()->data()); return true; } // Not found; check for the static property pattern. // Factory for String atoms that are required to match another captured // String opcode. auto same_string_as = [&] (int i) { return Atom(Op::String).onlyif([=] (PC pc, const Captures& captures) { auto string1 = (const Op*)pc; auto string2 = (const Op*)captures[i]; assert(*string1 == Op::String); assert(*string2 == Op::String); auto const unit = funcd->unit(); auto sd1 = unit->lookupLitstrId(getImmPtr(string1, 0)->u_SA); auto sd2 = unit->lookupLitstrId(getImmPtr(string2, 0)->u_SA); return (sd1 && sd1 == sd2); }); }; auto stringProp = same_string_as(0); auto stringCls = same_string_as(1); auto agetc = Atom(Op::AGetC); auto cgets = Atom(Op::CGetS); // Look for a class static singleton pattern. result = BCPattern { Atom(Op::String).capture(), Atom(Op::String).capture(), Atom(Op::AGetC), Atom(Op::CGetS), Atom(Op::IsTypeC), Atom::alt( Atom(Op::JmpZ).taken({stringProp, stringCls, agetc, cgets, retc}), Atom::seq(Atom(Op::JmpNZ), stringProp, stringCls, agetc, cgets, retc) ) }.ignore( {Op::AssertRATL, Op::AssertRATStk} ).matchAnchored(funcd); if (result.found()) { try { hhbcTrans().emitSingletonSProp( funcd, (const Op*)result.getCapture(1), (const Op*)result.getCapture(0) ); } catch (const FailedIRGen& e) { return false; } catch (const FailedCodeGen& e) { return false; } TRACE(1, "[singleton-sprop] %s <- %s\n", funcd->fullName()->data(), fcall.func()->fullName()->data()); return true; } return false; }
void IRTranslator::translateAwait(const NormalizedInstruction& i) { HHIR_EMIT(Await, i.nextSk().offset(), i.imm[0].u_IVA); }
void IRTranslator::translateYieldK(const NormalizedInstruction& i) { HHIR_EMIT(YieldK, i.nextSk().offset()); }
void IRTranslator::translateContEnter(const NormalizedInstruction& i) { HHIR_EMIT(ContEnter, i.nextSk().offset()); }