void emitUnbox(HTS& env) { auto const exit = makeExit(env); auto const srcBox = popV(env); auto const unboxed = unbox(env, srcBox, exit); pushIncRef(env, unboxed); gen(env, DecRef, srcBox); }
void emitCGetL(HTS& env, int32_t id) { auto const ldrefExit = makeExit(env); auto const ldPMExit = makePseudoMainExit(env); // Mimic hhbc guard relaxation for now. auto cat = curSrcKey(env).op() == OpFPassL ? DataTypeSpecific : DataTypeCountnessInit; pushIncRef(env, ldLocInnerWarn(env, id, ldrefExit, ldPMExit, cat)); }
void emitContCurrent(HTS& env) { assert(curClass(env)); auto const cont = ldThis(env); gen(env, ContStartedCheck, makeExitSlow(env), cont); auto const offset = cns(env, offsetof(c_Generator, m_value)); auto const value = gen(env, LdContField, Type::Cell, cont, offset); pushIncRef(env, value); }
void emitContCurrent(IRGS& env) { assertx(curClass(env)); auto const cont = ldThis(env); gen(env, ContStartedCheck, IsAsyncData(false), makeExitSlow(env), cont); auto const offset = cns(env, offsetof(Generator, m_value) - Generator::objectOff()); auto const value = gen(env, LdContField, TCell, cont, offset); pushIncRef(env, value); }
void emitVGetG(IRGS& env) { auto const name = topC(env); if (!name->isA(TStr)) PUNT(VGetG-NonStrName); auto const ptr = gen(env, LdGblAddrDef, name); destroyName(env, name); pushIncRef( env, gen(env, LdMem, TBoxedInitCell, gen(env, BoxPtr, ptr)) ); }
void emitCGetG(IRGS& env) { auto const exit = makeExitSlow(env); auto const name = topC(env); if (!name->isA(TStr)) PUNT(CGetG-NonStrName); auto const ptr = gen(env, LdGblAddr, exit, name); destroyName(env, name); pushIncRef( env, gen(env, LdMem, TCell, gen(env, UnboxPtr, ptr)) ); }
void emitBareThis(HTS& env, BareThisOp subop) { if (!curClass(env)) { interpOne(env, Type::InitNull, 0); // will raise notice and push null return; } auto const ctx = gen(env, LdCtx, fp(env)); if (subop == BareThisOp::NeverNull) { env.irb->setThisAvailable(); } else { gen(env, CheckCtxThis, makeExitSlow(env), ctx); } pushIncRef(env, gen(env, CastCtxThis, ctx)); }
void emitCGetL2(HTS& env, int32_t id) { auto const ldrefExit = makeExit(env); auto const ldPMExit = makePseudoMainExit(env); auto const oldTop = pop(env, Type::StkElem); auto const val = ldLocInnerWarn( env, id, ldrefExit, ldPMExit, DataTypeCountnessInit ); pushIncRef(env, val); push(env, oldTop); }
void emitVGetL(HTS& env, int32_t id) { auto value = ldLoc(env, id, makeExit(env), DataTypeCountnessInit); auto const t = value->type(); always_assert(t.isBoxed() || t.notBoxed()); if (t.notBoxed()) { if (value->isA(Type::Uninit)) { value = cns(env, Type::InitNull); } value = gen(env, Box, value); stLocRaw(env, id, fp(env), value); } pushIncRef(env, value); }
void emitCGetS(IRGS& env) { auto const ssaPropName = topC(env, BCSPOffset{1}); if (!ssaPropName->isA(TStr)) { PUNT(CGetS-PropNameNotString); } auto const ssaCls = popA(env); auto const propAddr = ldClsPropAddr(env, ssaCls, ssaPropName, true); auto const unboxed = gen(env, UnboxPtr, propAddr); auto const ldMem = gen(env, LdMem, unboxed->type().deref(), unboxed); destroyName(env, ssaPropName); pushIncRef(env, ldMem); }
void emitBindL(HTS& env, int32_t id) { if (curFunc(env)->isPseudoMain()) { interpOne(env, Type::BoxedInitCell, 1); return; } auto const ldPMExit = makePseudoMainExit(env); auto const newValue = popV(env); // Note that the IncRef must happen first, for correctness in a // pseudo-main: the destructor could decref the value again after // we've stored it into the local. pushIncRef(env, newValue); auto const oldValue = ldLoc(env, id, ldPMExit, DataTypeSpecific); stLocRaw(env, id, fp(env), newValue); gen(env, DecRef, oldValue); }
void emitVGetS(IRGS& env) { auto const ssaPropName = topC(env, BCSPOffset{1}); if (!ssaPropName->isA(TStr)) { PUNT(VGetS-PropNameNotString); } auto const ssaCls = popA(env); auto const propAddr = ldClsPropAddr(env, ssaCls, ssaPropName, true); destroyName(env, ssaPropName); auto const val = gen( env, LdMem, TBoxedInitCell, gen(env, BoxPtr, propAddr) ); pushIncRef(env, val); }
void inlSingletonSProp(IRGS& env, const Func* func, const Op* clsOp, const Op* propOp) { assertx(*clsOp == Op::String); assertx(*propOp == Op::String); TransFlags trflags; trflags.noinlineSingleton = true; auto exitBlock = makeExit(env, trflags); // Pull the class and property names. auto const unit = func->unit(); auto const clsName = unit->lookupLitstrId(getImmPtr(clsOp, 0)->u_SA); auto const propName = unit->lookupLitstrId(getImmPtr(propOp, 0)->u_SA); // Make sure we have a valid class. auto const cls = Unit::lookupClass(clsName); if (UNLIKELY(!classHasPersistentRDS(cls))) { PUNT(SingletonSProp-Persistent); } // Make sure the sprop is accessible from the singleton method's context. auto const lookup = cls->findSProp(func->cls(), propName); if (UNLIKELY(lookup.prop == kInvalidSlot || !lookup.accessible)) { PUNT(SingletonSProp-Accessibility); } // Look up the static property. auto const sprop = ldClsPropAddrKnown(env, cls, propName); auto const unboxed = gen(env, UnboxPtr, sprop); auto const value = gen(env, LdMem, unboxed->type().deref(), unboxed); // Side exit if the static property is null. auto isnull = gen(env, IsType, TNull, value); gen(env, JmpNZero, exitBlock, isnull); // Return the singleton. pushIncRef(env, value); }
void inlSingletonSLoc(IRGS& env, const Func* func, const Op* op) { assertx(*op == Op::StaticLocInit); TransFlags trflags; trflags.noinlineSingleton = true; auto exit = makeExit(env, trflags); auto const name = func->unit()->lookupLitstrId(getImmPtr(op, 1)->u_SA); // Side exit if the static local is uninitialized. auto const box = gen(env, LdStaticLocCached, StaticLocName { func, name }); gen(env, CheckStaticLocInit, exit, box); // Side exit if the static local is null. auto const value = gen(env, LdRef, TInitCell, box); auto const isnull = gen(env, IsType, TInitNull, value); gen(env, JmpNZero, exit, isnull); // Return the singleton. pushIncRef(env, value); }
void emitDup(HTS& env) { pushIncRef(env, topC(env)); }
void emitThis(HTS& env) { auto const ctx = gen(env, LdCtx, fp(env)); checkThis(env, ctx); auto const this_ = gen(env, CastCtxThis, ctx); pushIncRef(env, this_); }