void cgLookupClsMethodFCache(IRLS& env, const IRInstruction* inst) { auto const extra = inst->extra<ClsMethodData>(); auto const dst = dstLoc(env, inst, 0).reg(0); auto const cls = inst->src(0)->clsVal(); auto const fp = srcLoc(env, inst, 1).reg(); auto& v = vmain(env); auto const ch = StaticMethodFCache::alloc( cls->name(), extra->methodName, ctxName(inst->marker()) ); assertx(rds::isNormalHandle(ch)); const Func* (*lookup)(rds::Handle, const Class*, const StringData*, TypedValue*) = StaticMethodFCache::lookup; auto const args = argGroup(env, inst) .imm(ch) .immPtr(cls) .immPtr(extra->methodName) .reg(fp); cgCallHelper(v, env, CallSpec::direct(lookup), callDest(dst), SyncOptions::Sync, args); }
void cgLookupClsMethodCache(IRLS& env, const IRInstruction* inst) { auto const extra = inst->extra<ClsMethodData>(); auto const dst = dstLoc(env, inst, 0).reg(); auto const fp = srcLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const ch = StaticMethodCache::alloc( extra->clsName, extra->methodName, ctxName(inst->marker()) ); if (false) { // typecheck UNUSED TypedValue* fake_fp = nullptr; const UNUSED Func* f = StaticMethodCache::lookup( ch, extra->namedEntity, extra->clsName, extra->methodName, fake_fp ); } auto const args = argGroup(env, inst) .imm(ch) .immPtr(extra->namedEntity) .immPtr(extra->clsName) .immPtr(extra->methodName) .reg(fp); // May raise an error if the class is undefined. cgCallHelper(v, env, CallSpec::direct(StaticMethodCache::lookup), callDest(dst), SyncOptions::Sync, args); }
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 cgLdClsMethodFCacheFunc(IRLS& env, const IRInstruction* inst) { auto const extra = inst->extra<ClsMethodData>(); auto const dst = dstLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const ch = StaticMethodFCache::alloc( extra->clsName, extra->methodName, ctxName(inst->marker()) ); auto const sf = checkRDSHandleInitialized(v, ch); fwdJcc(v, env, CC_NE, sf, inst->taken()); emitLdLowPtr(v, rvmtl()[ch + offsetof(StaticMethodFCache, m_func)], dst, sizeof(LowPtr<const Func>)); }
void cgLdClsMethodCacheCls(IRLS& env, const IRInstruction* inst) { auto const extra = inst->extra<ClsMethodData>(); auto const dst = dstLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const ch = StaticMethodCache::alloc( extra->clsName, extra->methodName, ctxName(inst->marker()) ); // The StaticMethodCache here is guaranteed to already be initialized in RDS // by the pre-conditions of this instruction. emitLdLowPtr(v, rvmtl()[ch + offsetof(StaticMethodCache, m_cls)], dst, sizeof(LowPtr<const Class>)); }