DEBUG_ONLY bool throwable_has_expected_props() { auto const erCls = SystemLib::s_ErrorClass; auto const exCls = SystemLib::s_ExceptionClass; return erCls->lookupDeclProp(s_previous.get()) == s_previousIdx && exCls->lookupDeclProp(s_previous.get()) == s_previousIdx; }
void emitInitProp(IRGS& env, const StringData* propName, InitPropOp op) { auto const val = popC(env); auto const ctx = curClass(env); SSATmp* base; Slot idx = 0; switch (op) { case InitPropOp::Static: { // For sinit, the context class is always the same as the late-bound // class, so we can just use curClass(). auto const handle = ctx->sPropHandle(ctx->lookupSProp(propName)); base = gen( env, LdRDSAddr, RDSHandleData { handle }, TPtrToSPropCell ); } break; case InitPropOp::NonStatic: { // The above is not the case for pinit, so we need to load. auto const cctx = gen(env, LdCctx, fp(env)); auto const cls = gen(env, LdClsCtx, cctx); base = gen(env, LdClsInitData, cls); idx = ctx->lookupDeclProp(propName); } break; } gen(env, StElem, base, cns(env, idx * sizeof(TypedValue)), val); }
static void unserializeProp(VariableUnserializer* uns, ObjectData* obj, const String& key, Class* ctx, const String& realKey, int nProp) { // Do a two-step look up auto const lookup = obj->getProp(ctx, key.get()); Variant* t; if (!lookup.prop || !lookup.accessible) { // Dynamic property. If this is the first, and we're using MixedArray, // we need to pre-allocate space in the array to ensure the elements // dont move during unserialization. // // TODO(#2881866): this assumption means we can't do reallocations // when promoting kPackedKind -> kMixedKind. t = &obj->reserveProperties(nProp).lvalAt(realKey, AccessFlags::Key); } else { t = &tvAsVariant(lookup.prop); } if (UNLIKELY(IS_REFCOUNTED_TYPE(t->getRawType()))) { uns->putInOverwrittenList(*t); } unserializeVariant(*t, uns); if (!RuntimeOption::RepoAuthoritative) return; if (!Repo::get().global().HardPrivatePropInference) return; /* * We assume for performance reasons in repo authoriative mode that * we can see all the sets to private properties in a class. * * It's a hole in this if we don't check unserialization doesn't * violate what we've seen, which we handle by throwing if the repo * was built with this option. */ auto const cls = obj->getVMClass(); auto const slot = cls->lookupDeclProp(key.get()); if (UNLIKELY(slot == kInvalidSlot)) return; auto const repoTy = obj->getVMClass()->declPropRepoAuthType(slot); if (LIKELY(tvMatchesRepoAuthType(*t->asTypedValue(), repoTy))) { return; } auto msg = folly::format( "Property {} for class {} was deserialized with type ({}) that " "didn't match what we inferred in static analysis", key.data(), obj->getVMClass()->name()->data(), tname(t->asTypedValue()->m_type) ).str(); throw Exception(msg); }
void emitCheckProp(IRGS& env, const StringData* propName) { auto const cctx = gen(env, LdCctx, fp(env)); auto const cls = gen(env, LdClsCtx, cctx); auto const propInitVec = gen(env, LdClsInitData, cls); auto const ctx = curClass(env); auto const idx = ctx->lookupDeclProp(propName); auto const curVal = gen(env, LdElem, propInitVec, cns(env, idx * sizeof(TypedValue))); push(env, gen(env, IsNType, TUninit, curVal)); }
// Defined here so it can be inlined below. RefData* lookupStaticFromClosure(ObjectData* closure, StringData* name, bool& inited) { assert(closure->instanceof(c_Closure::classof())); String str(StringData::Make(s_staticPrefix->slice(), name->slice())); auto const cls = closure->getVMClass(); auto const slot = cls->lookupDeclProp(str.get()); assert(slot != kInvalidSlot); auto const val = static_cast<c_Closure*>(closure)->getStaticVar(slot); if (val->m_type == KindOfUninit) { inited = false; val->m_type = KindOfNull; tvBox(val); return val->m_data.pref; } inited = true; assert(val->m_type == KindOfRef); return val->m_data.pref; }