void cgInstanceOfIfaceVtable(IRLS& env, const IRInstruction* inst) { auto const iface = inst->extra<InstanceOfIfaceVtable>()->cls; auto const slot = iface->preClass()->ifaceVtableSlot(); auto const dst = dstLoc(env, inst, 0).reg(); auto const rcls = srcLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const sf = v.makeReg(); emitCmpVecLen(v, sf, static_cast<int32_t>(slot), rcls[Class::vtableVecLenOff()]); cond( v, CC_A, sf, dst, [&] (Vout& v) { auto const vtableVec = v.makeReg(); emitLdLowPtr(v, rcls[Class::vtableVecOff()], vtableVec, sizeof(LowPtr<Class::VtableVecSlot>)); auto const ifaceOff = slot * sizeof(Class::VtableVecSlot) + offsetof(Class::VtableVecSlot, iface); auto const sf = v.makeReg(); emitCmpLowPtr<Class>(v, sf, iface, vtableVec[ifaceOff]); auto tmp = v.makeReg(); v << setcc{CC_E, sf, tmp}; return tmp; }, [&] (Vout& v) { return v.cns(false); } ); }
void cgLdClsRef(IRLS& env, const IRInstruction* inst) { auto const fp = srcLoc(env, inst, 0).reg(); auto const dst = dstLoc(env, inst, 0).reg(); auto const off = frame_clsref_offset( funcFromFp(inst->src(0)), inst->extra<ClsRefSlotData>()->slot ); emitLdLowPtr(vmain(env), fp[off], dst, sizeof(LowPtr<Class>)); }
void cgLdIfaceMethod(IRLS& env, const IRInstruction* inst) { auto const extra = inst->extra<LdIfaceMethod>(); auto const func = dstLoc(env, inst, 0).reg(); auto const cls = srcLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const vtable_vec = v.makeReg(); auto const vtable = v.makeReg(); emitLdLowPtr(v, cls[Class::vtableVecOff()], vtable_vec, sizeof(LowPtr<Class::VtableVecSlot>)); auto const vtableOff = extra->vtableIdx * sizeof(Class::VtableVecSlot) + offsetof(Class::VtableVecSlot, vtable); emitLdLowPtr(v, vtable_vec[vtableOff], vtable, sizeof(Class::VtableVecSlot::vtable)); emitLdLowPtr(v, vtable[extra->methodIdx * sizeof(LowPtr<Func>)], func, sizeof(LowPtr<Func>)); }
void cgLdClsName(IRLS& env, const IRInstruction* inst) { auto const dst = dstLoc(env, inst, 0).reg(); auto const src = srcLoc(env, inst, 0).reg(); auto& v = vmain(env); auto const preclass = v.makeReg(); v << load{src[Class::preClassOff()], preclass}; emitLdLowPtr(v, preclass[PreClass::nameOffset()], dst, sizeof(LowStringPtr)); }
void cgLdObjInvoke(IRLS& env, const IRInstruction* inst) { auto const dst = dstLoc(env, inst, 0).reg(); auto const cls = srcLoc(env, inst, 0).reg(); auto& v = vmain(env); emitLdLowPtr(v, cls[Class::invokeOff()], dst, sizeof(LowPtr<Func>)); auto const sf = v.makeReg(); v << testq{dst, dst, sf}; v << jcc{CC_Z, sf, {label(env, inst->next()), label(env, inst->taken())}}; }
void cgLdClsMethod(IRLS& env, const IRInstruction* inst) { auto const dst = dstLoc(env, inst, 0).reg(); auto const cls = srcLoc(env, inst, 0).reg(); int32_t const mSlotVal = inst->src(1)->rawVal(); // We could have a Cls or a Cctx. The Cctx has the low bit set, so // we need to subtract one in that case. auto const methOff = int32_t(mSlotVal * sizeof(LowPtr<Func>)) - (inst->src(0)->isA(TCctx) ? 1 : 0); auto& v = vmain(env); emitLdLowPtr(v, cls[methOff], dst, sizeof(LowPtr<Func>)); }
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>)); }
Vreg emitLdObjClass(Vout& v, Vreg obj, Vreg d) { emitLdLowPtr(v, obj[ObjectData::getVMClassOffset()], d, sizeof(LowPtr<Class>)); return d; }