void cgFwdCtxStaticCall(IRLS& env, const IRInstruction* inst) { auto const dstCtx = dstLoc(env, inst, 0).reg(); auto const srcCtx = srcLoc(env, inst, 0).reg(); auto const ty = inst->src(0)->type(); auto& v = vmain(env); auto ctx_from_this = [] (Vout& v, Vreg rthis, Vreg dst) { // Load (this->m_cls | 0x1) into `dst'. auto const cls = emitLdObjClass(v, rthis, v.makeReg()); v << orqi{ActRec::kHasClassBit, cls, dst, v.makeReg()}; return dst; }; if (ty <= TCctx) { v << copy{srcCtx, dstCtx}; } else if (ty <= TObj) { ctx_from_this(v, srcCtx, dstCtx); } else { // If we don't know whether we have a $this, we need to check dynamically. auto const sf = v.makeReg(); v << testqi{ActRec::kHasClassBit, srcCtx, sf}; unlikelyCond(v, vcold(env), CC_NZ, sf, dstCtx, [&] (Vout& v) { return srcCtx; }, [&] (Vout& v) { return ctx_from_this(v, srcCtx, v.makeReg()); } ); } }
void cgGetCtxFwdCallDyn(IRLS& env, const IRInstruction* inst) { implGetCtxFwdCall(env, inst, [&] (Vout& v, Vreg rthis, Vreg dst) { auto const extra = inst->extra<ClsMethodData>(); auto const ch = StaticMethodFCache::alloc( extra->clsName, extra->methodName, ctxName(inst->marker()) ); // The StaticMethodFCache here is guaranteed to already be initialized in // RDS by the pre-conditions of this instruction. auto const sf = v.makeReg(); v << cmplim{1, rvmtl()[ch + offsetof(StaticMethodFCache, m_static)], sf}; return cond(v, CC_E, sf, dst, [&] (Vout& v) { // Load (this->m_cls | 0x1) into `dst'. auto cls = v.makeReg(); auto tmp = v.makeReg(); emitLdObjClass(v, rthis, cls); v << orqi{1, cls, tmp, v.makeReg()}; return tmp; }, [&] (Vout& v) { // Just incref $this. emitIncRef(v, rthis); return rthis; } ); }); }
void cgLdClsCtx(IRLS& env, const IRInstruction* inst) { auto dst = dstLoc(env, inst, 0).reg(); auto ctx = srcLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const sf = v.makeReg(); v << testqi{ActRec::kHasClassBit, ctx, sf}; cond(v, CC_NZ, sf, dst, [&] (Vout& v) { return emitLdClsCctx(v, ctx, v.makeReg()); }, // Cctx [&] (Vout& v) { return emitLdObjClass(v, ctx, v.makeReg()); } // This ); }
void cgGetCtxFwdCall(IRLS& env, const IRInstruction* inst) { implGetCtxFwdCall(env, inst, [&] (Vout& v, Vreg rthis, Vreg dst) { auto const callee = inst->src(1)->funcVal(); if (callee->isStatic()) { // Load (this->m_cls | 0x1) into `dst'. auto const cls = v.makeReg(); emitLdObjClass(v, rthis, cls); v << orqi{1, cls, dst, v.makeReg()}; } else { // Just incref $this. emitIncRef(v, rthis); v << copy{rthis, dst}; } return dst; }); }
void cgLdObjClass(IRLS& env, const IRInstruction* inst) { auto dst = dstLoc(env, inst, 0).reg(); auto obj = srcLoc(env, inst, 0).reg(); emitLdObjClass(vmain(env), obj, dst); }