From 16797e6b6019011a77e5dd8ed0d6bc637e9d8d31 Mon Sep 17 00:00:00 2001 From: Paul Bissonnette Date: Fri, 25 Oct 2019 15:41:26 -0700 Subject: [PATCH] Remove Ref type from hhbbc Summary: Removes the Ref type and Ref specialization from the hhbbc type system. Replaces instances of Gen and InitGen with Cell and InitCell. Reviewed By: ricklavoie Differential Revision: D17859906 fbshipit-source-id: 02b63cc7c1aa3a318a6438b429ed20cbca17ce16 --- hphp/hhbbc/analyze.cpp | 8 +- hphp/hhbbc/dce.cpp | 86 ++++------------- hphp/hhbbc/emit.cpp | 5 +- hphp/hhbbc/index.cpp | 32 +++---- hphp/hhbbc/index.h | 6 +- hphp/hhbbc/interp-internal.h | 31 +++--- hphp/hhbbc/interp-minstr.cpp | 2 +- hphp/hhbbc/interp.cpp | 25 +++-- hphp/hhbbc/optimize.cpp | 19 +--- hphp/hhbbc/show.cpp | 4 - hphp/hhbbc/stats.cpp | 3 - hphp/hhbbc/test/type-system.cpp | 46 ++------- hphp/hhbbc/type-system.cpp | 137 +++------------------------ hphp/hhbbc/type-system.h | 51 ++++------ hphp/runtime/base/repo-auth-type-codec-inl.h | 3 - hphp/runtime/base/repo-auth-type-codec.cpp | 6 -- hphp/runtime/base/repo-auth-type.cpp | 15 --- hphp/runtime/base/repo-auth-type.h | 5 +- hphp/runtime/vm/as.cpp | 6 -- hphp/runtime/vm/func.cpp | 4 +- hphp/runtime/vm/jit/type.cpp | 3 - hphp/runtime/vm/verifier/pretty.cpp | 4 +- 22 files changed, 121 insertions(+), 380 deletions(-) diff --git a/hphp/hhbbc/analyze.cpp b/hphp/hhbbc/analyze.cpp index 538156062c2..a5855f2c071 100644 --- a/hphp/hhbbc/analyze.cpp +++ b/hphp/hhbbc/analyze.cpp @@ -87,7 +87,7 @@ State pseudomain_entry_state(const php::Func* func) { ret.iters.resize(func->numIters); for (auto i = 0; i < ret.locals.size(); ++i) { // Named pseudomain locals are bound to $GLOBALS. - ret.locals[i] = func->locals[i].name ? TGen : TUninit; + ret.locals[i] = func->locals[i].name ? TCell : TUninit; } return ret; } @@ -191,7 +191,7 @@ State entry_state(const Index& index, Context const ctx, // parameters. for (auto locId = uint32_t{0}; locId < ctx.func->locals.size(); ++locId) { if (is_volatile_local(ctx.func, locId)) { - ret.locals[locId] = TGen; + ret.locals[locId] = TCell; } } @@ -459,7 +459,7 @@ FuncAnalysis do_analyze_collect(const Index& index, * In this case, we leave the return type as TBottom, to indicate * the same to callers. */ - assert(ai.inferredReturn.subtypeOf(BGen)); + assert(ai.inferredReturn.subtypeOf(BCell)); // For debugging, print the final input states for each block. FTRACE(2, "{}", [&] { @@ -546,7 +546,7 @@ void expand_hni_prop_types(ClassAnalysis& clsAnalysis) { */ auto const hniTy = clsAnalysis.anyInterceptable - ? TGen + ? TCell : from_hni_constraint(prop.userType); if (it->second.ty.subtypeOf(hniTy)) { it->second.ty = hniTy; diff --git a/hphp/hhbbc/dce.cpp b/hphp/hhbbc/dce.cpp index 64605510cf4..ab592c20650 100644 --- a/hphp/hhbbc/dce.cpp +++ b/hphp/hhbbc/dce.cpp @@ -186,13 +186,6 @@ uint32_t numPush(const Bytecode& bc) { return bc.numPush(); } -// Returns whether a set on something containing type t could have -// side-effects (running destuctors, or modifying arbitrary things via -// a Ref). -bool setCouldHaveSideEffects(const Type& t) { - return t.couldBe(BRef); -} - // Some reads could raise warnings and run arbitrary code. bool readCouldHaveSideEffects(const Type& t) { return t.couldBe(BUninit); @@ -600,40 +593,9 @@ Type locRaw(Env& env, LocalId loc) { return env.stateBefore.locals[loc]; } -bool setLocCouldHaveSideEffects(Env& env, LocalId loc, bool forExit = false) { - // A "this" local is protected by the $this in the ActRec. - if (loc == env.stateBefore.thisLoc) return false; - - // Normally, if there's an equivLocal this isn't the last reference, - // so overwriting it won't run any destructors. But if we're - // destroying all the locals (eg RetC) they can't all protect each - // other; in that case we require a lower equivLoc to ensure that - // one local from each equivalence set will still be marked as - // having effects (choosing lower numbers also means we mark the - // params as live, which makes it more likely that we can eliminate - // a local). - static_assert(NoLocalId == std::numeric_limits::max(), - "NoLocalId must be greater than all valid local ids"); - if (env.stateBefore.equivLocals.size() > loc) { - auto l = env.stateBefore.equivLocals[loc]; - if (l != NoLocalId) { - if (!forExit) return false; - do { - if (l < loc) return false; - l = env.stateBefore.equivLocals[l]; - } while (l != loc); - } - } - - return setCouldHaveSideEffects(locRaw(env, loc)); -} - -void readDtorLocs(Env& env) { - for (auto i = LocalId{0}; i < env.stateBefore.locals.size(); ++i) { - if (setLocCouldHaveSideEffects(env, i, true)) { - addLocGen(env, i); - } - } +bool isLocVolatile(Env& env, uint32_t id) { + if (id >= kMaxTrackedLocals) return true; + return is_volatile_local(env.dceState.ainfo.ctx.func, id); } ////////////////////////////////////////////////////////////////////// @@ -1083,9 +1045,8 @@ void cgetImpl(Env& env, LocalId loc, bool quiet) { return PushFlags::MarkUnused; } if (!isLocLive(env, loc) && - !setCouldHaveSideEffects(locRaw(env, loc)) && !readCouldHaveSideEffects(locRaw(env, loc)) && - !is_volatile_local(env.dceState.ainfo.ctx.func, loc)) { + !isLocVolatile(env, loc)) { // note: PushL does not deal with Uninit, so we need the // readCouldHaveSideEffects here, regardless of quiet. env.dceState.replaceMap.insert({ env.id, { bc::PushL { loc } } }); @@ -1144,11 +1105,11 @@ void dce(Env& env, const bc::BareThis& op) { }); } -void dce(Env& env, const bc::RetC&) { pop(env); readDtorLocs(env); } -void dce(Env& env, const bc::RetCSuspended&) { pop(env); readDtorLocs(env); } -void dce(Env& env, const bc::Throw&) { pop(env); readDtorLocs(env); } -void dce(Env& env, const bc::Fatal&) { pop(env); readDtorLocs(env); } -void dce(Env& env, const bc::Exit&) { stack_ops(env); readDtorLocs(env); } +void dce(Env& env, const bc::RetC&) { pop(env); } +void dce(Env& env, const bc::RetCSuspended&) { pop(env); } +void dce(Env& env, const bc::Throw&) { pop(env); } +void dce(Env& env, const bc::Fatal&) { pop(env); } +void dce(Env& env, const bc::Exit&) { stack_ops(env); } void dce(Env& env, const bc::IsTypeC& op) { stack_ops(env, [&] (UseInfo& ui) { @@ -1344,15 +1305,13 @@ void dce(Env& env, const bc::NewPair& op) { dceNewArrayLike(env, op); } void dce(Env& env, const bc::ColFromArray& op) { dceNewArrayLike(env, op); } void dce(Env& env, const bc::PopL& op) { - auto const effects = setLocCouldHaveSideEffects(env, op.loc1); - if (!isLocLive(env, op.loc1) && !effects) { - assert(!locRaw(env, op.loc1).couldBe(BRef)); + if (!isLocLive(env, op.loc1) && !isLocVolatile(env, op.loc1)) { discard(env); env.dceState.actionMap[env.id] = DceAction::PopInputs; return; } pop(env); - if (effects || locRaw(env, op.loc1).couldBe(BRef)) { + if (isLocVolatile(env, op.loc1)) { addLocGen(env, op.loc1); } else { addLocKill(env, op.loc1); @@ -1366,9 +1325,7 @@ void dce(Env& env, const bc::InitThisLoc& op) { } void dce(Env& env, const bc::SetL& op) { - auto const effects = setLocCouldHaveSideEffects(env, op.loc1); - if (!isLocLive(env, op.loc1) && !effects) { - assert(!locRaw(env, op.loc1).couldBe(BRef)); + if (!isLocLive(env, op.loc1) && !isLocVolatile(env, op.loc1)) { return markDead(env); } stack_ops(env, [&] (UseInfo& ui) { @@ -1380,7 +1337,7 @@ void dce(Env& env, const bc::SetL& op) { ui.actions[env.id] = DceAction::Replace; return PushFlags::MarkDead; }); - if (effects || locRaw(env, op.loc1).couldBe(BRef)) { + if (isLocVolatile(env, op.loc1)) { addLocGen(env, op.loc1); } else { addLocKill(env, op.loc1); @@ -1388,13 +1345,10 @@ void dce(Env& env, const bc::SetL& op) { } void dce(Env& env, const bc::UnsetL& op) { - auto const oldTy = locRaw(env, op.loc1); + auto const oldTy = locRaw(env, op.loc1); if (oldTy.subtypeOf(BUninit)) return markDead(env); - // Unsetting a local bound to a static never has side effects - // because the static itself has a reference to the value. - auto const effects = setLocCouldHaveSideEffects(env, op.loc1); - + auto const effects = isLocVolatile(env, op.loc1); if (!isLocLive(env, op.loc1) && !effects) return markDead(env); if (effects) { addLocGen(env, op.loc1); @@ -1411,8 +1365,8 @@ void dce(Env& env, const bc::UnsetL& op) { */ void dce(Env& env, const bc::IncDecL& op) { auto const oldTy = locRaw(env, op.loc1); - auto const effects = setLocCouldHaveSideEffects(env, op.loc1) || - readCouldHaveSideEffects(oldTy); + auto const effects = readCouldHaveSideEffects(oldTy) || + isLocVolatile(env, op.loc1); stack_ops(env, [&] (const UseInfo& ui) { scheduleGenLoc(env, op.loc1); if (!isLocLive(env, op.loc1) && !effects && allUnused(ui)) { @@ -1458,13 +1412,13 @@ bool setOpLSideEffects(const bc::SetOpL& op, const Type& lhs, const Type& rhs) { * kill it. */ void dce(Env& env, const bc::SetOpL& op) { - auto const oldTy = locRaw(env, op.loc1); + auto const oldTy = locRaw(env, op.loc1); stack_ops(env, [&] (UseInfo& ui) { scheduleGenLoc(env, op.loc1); if (!isLocLive(env, op.loc1) && allUnused(ui)) { - if (!setLocCouldHaveSideEffects(env, op.loc1) && - !readCouldHaveSideEffects(oldTy) && + if (!readCouldHaveSideEffects(oldTy) && + !isLocVolatile(env, op.loc1) && !setOpLSideEffects(op, oldTy, topC(env))) { return PushFlags::MarkUnused; } diff --git a/hphp/hhbbc/emit.cpp b/hphp/hhbbc/emit.cpp index fa975ce38fd..4a30d7ae0e8 100644 --- a/hphp/hhbbc/emit.cpp +++ b/hphp/hhbbc/emit.cpp @@ -1064,7 +1064,6 @@ void merge_repo_auth_type(UnitEmitter& ue, RepoAuthType rat) { case T::OptStrLike: case T::Null: case T::Cell: - case T::Ref: case T::InitUnc: case T::Unc: case T::UncArrKey: @@ -1072,8 +1071,6 @@ void merge_repo_auth_type(UnitEmitter& ue, RepoAuthType rat) { case T::UncStrLike: case T::StrLike: case T::InitCell: - case T::InitGen: - case T::Gen: case T::Uninit: case T::InitNull: case T::Bool: @@ -1356,7 +1353,7 @@ void emit_class(EmitUnitState& state, auto const privateStatics = state.index.lookup_private_statics(&cls, true); for (auto& prop : cls.properties) { auto const makeRat = [&] (const Type& ty) -> RepoAuthType { - if (!ty.subtypeOf(BGen)) return RepoAuthType{}; + if (!ty.subtypeOf(BCell)) return RepoAuthType{}; if (ty.subtypeOf(BBottom)) { // A property can be TBottom if no sets (nor its initial value) is // compatible with its type-constraint, or if its LateInit and there's diff --git a/hphp/hhbbc/index.cpp b/hphp/hhbbc/index.cpp index 48a8d60bee0..80d84e004dd 100644 --- a/hphp/hhbbc/index.cpp +++ b/hphp/hhbbc/index.cpp @@ -290,7 +290,7 @@ PropState make_unknown_propstate(const php::Class* cls, auto ret = PropState{}; for (auto& prop : cls->properties) { if (filter(prop)) { - ret[prop.name].ty = TGen; + ret[prop.name].ty = TCell; } } return ret; @@ -3599,7 +3599,7 @@ PublicSPropEntry lookup_public_static_impl( const ClassInfo* cinfo, SString prop ) { - auto const noInfo = PublicSPropEntry{TInitGen, TInitGen, nullptr, 0, true}; + auto const noInfo = PublicSPropEntry{TInitCell, TInitCell, nullptr, 0, true}; if (data.allPublicSPropsUnknown) return noInfo; @@ -3661,7 +3661,7 @@ PublicSPropEntry lookup_public_static_impl( auto const classes = find_range(data.classInfo, cls->name); if (begin(classes) == end(classes) || std::next(begin(classes)) != end(classes)) { - return PublicSPropEntry{TInitGen, TInitGen, nullptr, 0, true}; + return PublicSPropEntry{TInitCell, TInitCell, nullptr, 0, true}; } return lookup_public_static_impl(data, begin(classes)->second, name); } @@ -3686,14 +3686,14 @@ Type lookup_public_prop_impl( } ); - if (!prop) return TGen; + if (!prop) return TCell; // Make sure its non-static and public. Otherwise its another function's // problem. - if (prop->attrs & (AttrStatic | AttrPrivate)) return TGen; + if (prop->attrs & (AttrStatic | AttrPrivate)) return TCell; // Get a type corresponding to its declared type-hint (if any). auto ty = adjust_type_for_prop( - *data.m_index, *knownCls, &prop->typeConstraint, TGen + *data.m_index, *knownCls, &prop->typeConstraint, TCell ); // We might have to include the initial value which might be outside of the // type-hint. @@ -4902,7 +4902,7 @@ bool Index::prop_tc_maybe_unenforced(const php::Class& propCls, tc.type(), tc.isNullable(), tc.typeName(), - TGen + TCell ); return res.maybeMixed; } @@ -5486,16 +5486,16 @@ Index::lookup_private_statics(const php::Class* cls, Type Index::lookup_public_static(Context ctx, const Type& cls, const Type& name) const { - if (!is_specialized_cls(cls)) return TInitGen; + if (!is_specialized_cls(cls)) return TInitCell; auto const vname = tv(name); - if (!vname || vname->m_type != KindOfPersistentString) return TInitGen; + if (!vname || vname->m_type != KindOfPersistentString) return TInitCell; auto const sname = vname->m_data.pstr; if (ctx.unit) add_dependency(*m_data, sname, ctx, Dep::PublicSPropName); auto const dcls = dcls_of(cls); - if (dcls.cls.val.left()) return TInitGen; + if (dcls.cls.val.left()) return TInitCell; auto const cinfo = dcls.cls.val.right(); switch (dcls.type) { @@ -5570,14 +5570,14 @@ bool Index::lookup_public_static_maybe_late_init(const Type& cls, } Type Index::lookup_public_prop(const Type& cls, const Type& name) const { - if (!is_specialized_cls(cls)) return TGen; + if (!is_specialized_cls(cls)) return TCell; auto const vname = tv(name); - if (!vname || vname->m_type != KindOfPersistentString) return TGen; + if (!vname || vname->m_type != KindOfPersistentString) return TCell; auto const sname = vname->m_data.pstr; auto const dcls = dcls_of(cls); - if (dcls.cls.val.left()) return TGen; + if (dcls.cls.val.left()) return TCell; auto const cinfo = dcls.cls.val.right(); switch (dcls.type) { @@ -5606,7 +5606,7 @@ Type Index::lookup_public_prop(const php::Class* cls, SString name) const { auto const classes = find_range(m_data->classInfo, cls->name); if (begin(classes) == end(classes) || std::next(begin(classes)) != end(classes)) { - return TGen; + return TCell; } return lookup_public_prop_impl(*m_data, begin(classes)->second, name); } @@ -5686,7 +5686,7 @@ void Index::init_public_static_prop_types() { *this, *cinfo->cls, &prop.typeConstraint, - TInitGen + TInitCell ), initial ), @@ -6093,7 +6093,7 @@ void Index::refine_public_statics(DependencyContextSet& deps) { auto it = m_data->unknownClassSProps.find(kv.first); if (it == end(m_data->unknownClassSProps)) { // If this is the first refinement, our previous state was effectively - // TGen for everything, so inserting a type into the map can only + // TCell for everything, so inserting a type into the map can only // refine. However, if this isn't the first refinement, a name not present // in the map means that its TBottom, so we shouldn't be inserting // anything. diff --git a/hphp/hhbbc/index.h b/hphp/hhbbc/index.h index de60aae0fc5..c78d92fb8e9 100644 --- a/hphp/hhbbc/index.h +++ b/hphp/hhbbc/index.h @@ -678,13 +678,13 @@ struct Index { CompactVector args) const; /* * Return the best known return type for a resolved function, in a - * context insensitive way. Returns TInitGen at worst. + * context insensitive way. Returns TInitCell at worst. */ Type lookup_return_type(Context, res::Func) const; /* * Return the best known return type for a resolved function, given - * the supplied calling context. Returns TInitGen at worst. + * the supplied calling context. Returns TInitCell at worst. * * During analyze phases, this function may re-enter analyze in * order to interpret the callee with these argument types. @@ -775,7 +775,7 @@ struct Index { * Lookup the best known type for a public static property, with a given * class and name. * - * This function will always return TInitGen before refine_public_statics has + * This function will always return TInitCell before refine_public_statics has * been called, or if the AnalyzePublicStatics option is off. */ Type lookup_public_static(Context ctx, const Type& cls, diff --git a/hphp/hhbbc/interp-internal.h b/hphp/hhbbc/interp-internal.h index 7597687aa33..0e80367122a 100644 --- a/hphp/hhbbc/interp-internal.h +++ b/hphp/hhbbc/interp-internal.h @@ -273,7 +273,7 @@ Type popT(ISS& env) { assert(!env.state.stack.empty()); auto const ret = env.state.stack.back().type; FTRACE(2, " pop: {}\n", show(ret)); - assert(ret.subtypeOf(BGen)); + assert(ret.subtypeOf(BCell)); env.state.stack.pop_elem(); return ret; } @@ -324,11 +324,8 @@ void push(ISS& env, Type t) { void push(ISS& env, Type t, LocalId l) { if (l == NoLocalId) return push(env, t); - if (l <= MaxLocalId) { - if (peekLocRaw(env, l).couldBe(BRef)) { - return push(env, t); - } - assertx(!is_volatile_local(env.ctx.func, l)); // volatiles are TGen + if (l <= MaxLocalId && is_volatile_local(env.ctx.func, l)) { + return push(env, t); } FTRACE(2, " push: {} (={})\n", show(t), local_string(*env.ctx.func, l)); env.state.stack.push_elem(std::move(t), l, @@ -699,7 +696,7 @@ void setIterKey(ISS& env, IterId id, LocalId key) { Type peekLocRaw(ISS& env, LocalId l) { auto ret = env.state.locals[l]; if (is_volatile_local(env.ctx.func, l)) { - always_assert_flog(ret == TGen, "volatile local was not TGen"); + always_assert_flog(ret == TCell, "volatile local was not TCell"); } return ret; } @@ -717,7 +714,7 @@ void setLocRaw(ISS& env, LocalId l, Type t) { killThisLoc(env, l); if (is_volatile_local(env.ctx.func, l)) { auto current = env.state.locals[l]; - always_assert_flog(current == TGen, "volatile local was not TGen"); + always_assert_flog(current == TCell, "volatile local was not TCell"); return; } env.state.locals[l] = std::move(t); @@ -746,10 +743,6 @@ bool locCouldBeUninit(ISS& env, LocalId l) { return locRaw(env, l).couldBe(BUninit); } -bool locCouldBeRef(ISS& env, LocalId l) { - return locRaw(env, l).couldBe(BRef); -} - /* * Update the known type of a local, based on assertions * (VerifyParamType; or IsType/JmpCC), rather than an actual @@ -757,7 +750,9 @@ bool locCouldBeRef(ISS& env, LocalId l) { */ void refineLocHelper(ISS& env, LocalId l, Type t) { auto v = peekLocRaw(env, l); - if (v.subtypeOf(BCell)) env.state.locals[l] = std::move(t); + if (!is_volatile_local(env.ctx.func, l) && v.subtypeOf(BCell)) { + env.state.locals[l] = std::move(t); + } } template @@ -866,7 +861,7 @@ void loseNonRefLocalTypes(ISS& env) { void killLocals(ISS& env) { FTRACE(2, " killLocals\n"); readUnknownLocals(env); - for (auto& l : env.state.locals) l = TGen; + for (auto& l : env.state.locals) l = TCell; killAllLocEquiv(env); killAllStkEquiv(env); killAllIterEquivs(env); @@ -935,7 +930,7 @@ void killThisProps(ISS& env) { FTRACE(2, " killThisProps\n"); for (auto& kv : env.collect.props.privateProperties()) { kv.second.ty |= - adjust_type_for_prop(env.index, *env.ctx.cls, kv.second.tc, TGen); + adjust_type_for_prop(env.index, *env.ctx.cls, kv.second.tc, TCell); } } @@ -981,7 +976,7 @@ void mergeThisProp(ISS& env, SString name, Type type) { * predicate that returns TBottom when some condition doesn't hold. * * The types given to the map function are the raw tracked types - * (i.e. could be TRef or TUninit). + * (i.e. could be TUninit). */ template void mergeEachThisPropRaw(ISS& env, MapFn fn) { @@ -1035,14 +1030,14 @@ void killSelfProps(ISS& env) { FTRACE(2, " killSelfProps\n"); for (auto& kv : env.collect.props.privateStatics()) { kv.second.ty |= - adjust_type_for_prop(env.index, *env.ctx.cls, kv.second.tc, TGen); + adjust_type_for_prop(env.index, *env.ctx.cls, kv.second.tc, TCell); } } void killSelfProp(ISS& env, SString name) { FTRACE(2, " killSelfProp {}\n", name->data()); if (auto elem = selfPropRaw(env, name)) { - elem->ty |= adjust_type_for_prop(env.index, *env.ctx.cls, elem->tc, TGen); + elem->ty |= adjust_type_for_prop(env.index, *env.ctx.cls, elem->tc, TCell); } } diff --git a/hphp/hhbbc/interp-minstr.cpp b/hphp/hhbbc/interp-minstr.cpp index 4babaf405a5..60b935c619b 100644 --- a/hphp/hhbbc/interp-minstr.cpp +++ b/hphp/hhbbc/interp-minstr.cpp @@ -82,7 +82,7 @@ bool mustBeArrLike(const Type& ty) { ////////////////////////////////////////////////////////////////////// Type baseLocNameType(const Base& b) { - return b.locName ? sval(b.locName) : TInitGen; + return b.locName ? sval(b.locName) : TInitCell; } ////////////////////////////////////////////////////////////////////// diff --git a/hphp/hhbbc/interp.cpp b/hphp/hhbbc/interp.cpp index a045a247eee..45a942bbaae 100644 --- a/hphp/hhbbc/interp.cpp +++ b/hphp/hhbbc/interp.cpp @@ -2343,7 +2343,7 @@ void in(ISS& env, const bc::CGetL& op) { op.loc1 == last->PopL.loc1) { reprocess(env); rewind(env, 1); - if (!locCouldBeRef(env, op.loc1)) setLocRaw(env, op.loc1, TCell); + setLocRaw(env, op.loc1, TCell); return reduce(env, bc::SetL { op.loc1 }); } } @@ -3507,16 +3507,15 @@ folly::Optional> moveToLocImpl(ISS& env, auto equivLoc = topStkEquiv(env); // If the local could be a Ref, don't record equality because the stack // element and the local won't actually have the same type. - if (!locCouldBeRef(env, op.loc1)) { - if (equivLoc == StackThisId && env.state.thisLoc != NoLocalId) { - if (env.state.thisLoc == op.loc1 || - locsAreEquiv(env, env.state.thisLoc, op.loc1)) { - return folly::none; - } else { - equivLoc = env.state.thisLoc; - } + if (equivLoc == StackThisId && env.state.thisLoc != NoLocalId) { + if (env.state.thisLoc == op.loc1 || + locsAreEquiv(env, env.state.thisLoc, op.loc1)) { + return folly::none; + } else { + equivLoc = env.state.thisLoc; } - assertx(!is_volatile_local(env.ctx.func, op.loc1)); + } + if (!is_volatile_local(env.ctx.func, op.loc1)) { if (equivLoc <= MaxLocalId) { if (equivLoc == op.loc1 || locsAreEquiv(env, equivLoc, op.loc1)) { @@ -4683,7 +4682,7 @@ void iterInitKImpl(ISS& env, IterId iter, LocalId valueLoc, LocalId keyLoc, // equivalency. setLoc(env, valueLoc, std::move(ity.value)); setLoc(env, keyLoc, std::move(ity.key)); - if (!locCouldBeRef(env, keyLoc)) setIterKey(env, iter, keyLoc); + setIterKey(env, iter, keyLoc); }; assert(iterIsDead(env, iter)); @@ -4798,7 +4797,7 @@ void iterNextKImpl(ISS& env, IterId iter, LocalId valueLoc, case IterTypes::Count::Any: setLoc(env, valueLoc, ti.types.value); setLoc(env, keyLoc, ti.types.key); - if (!locCouldBeRef(env, keyLoc)) setIterKey(env, iter, keyLoc); + setIterKey(env, iter, keyLoc); return false; case IterTypes::Count::Empty: always_assert(false); @@ -5113,7 +5112,7 @@ bool couldBeMocked(const Type& t) { void in(ISS& env, const bc::VerifyParamType& op) { IgnoreUsedParams _{env}; - if (env.ctx.func->isMemoizeImpl && !locCouldBeRef(env, op.loc1)) { + if (env.ctx.func->isMemoizeImpl) { // a MemoizeImpl's params have already been checked by the wrapper return reduce(env); } diff --git a/hphp/hhbbc/optimize.cpp b/hphp/hhbbc/optimize.cpp index 42d4e9b63b5..d6b68485152 100644 --- a/hphp/hhbbc/optimize.cpp +++ b/hphp/hhbbc/optimize.cpp @@ -83,10 +83,10 @@ folly::Optional makeAssert(ArrayTypeTable::Builder& arrTable, auto const rat = make_repo_type(arrTable, t); using T = RepoAuthType::Tag; if (options.FilterAssertions) { - // Gen and InitGen don't add any useful information, so leave them + // Cell and InitCell don't add any useful information, so leave them // out entirely. - if (rat == RepoAuthType{T::Gen}) return folly::none; - if (rat == RepoAuthType{T::InitGen}) return folly::none; + if (rat == RepoAuthType{T::Cell}) return folly::none; + if (rat == RepoAuthType{T::InitCell}) return folly::none; } return Bytecode { TyBC { arg, rat } }; } @@ -178,13 +178,6 @@ void insert_assertions_step(ArrayTypeTable::Builder& arrTable, * subtypes and adding this to the opcode table. */ bool hasObviousStackOutput(const Bytecode& op, const Interp& interp) { - // Generally consider CGetL obvious because if we knew the type of the local, - // we'll assert that right before the CGetL. - auto cgetlObvious = [&] (LocalId l, int idx) { - return !interp.state.locals[l].couldBe(BRef) || - !interp.state.stack[interp.state.stack.size() - idx - 1]. - type.strictSubtypeOf(TInitCell); - }; switch (op.op) { case Op::Null: case Op::NullUninit: @@ -270,15 +263,11 @@ bool hasObviousStackOutput(const Bytecode& op, const Interp& interp) { return true; case Op::CGetL: - return cgetlObvious(op.CGetL.loc1, 0); case Op::CGetQuietL: - return cgetlObvious(op.CGetQuietL.loc1, 0); case Op::CUGetL: - return cgetlObvious(op.CUGetL.loc1, 0); case Op::CGetL2: - return cgetlObvious(op.CGetL2.loc1, 1); case Op::PushL: - return cgetlObvious(op.PushL.loc1, 0); + return true; // The output of SetL is obvious if you know what its input is // (which we'll assert if we know). diff --git a/hphp/hhbbc/show.cpp b/hphp/hhbbc/show.cpp index ce2881a7625..a2fd73b2bbf 100644 --- a/hphp/hhbbc/show.cpp +++ b/hphp/hhbbc/show.cpp @@ -457,7 +457,6 @@ std::string show(const Type& t) { return ret; case DataTag::Obj: case DataTag::Cls: - case DataTag::RefInner: case DataTag::ArrLikePacked: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMap: @@ -511,9 +510,6 @@ std::string show(const Type& t) { folly::toAppend(" this", &ret); } break; - case DataTag::RefInner: - folly::toAppend("(", show(*t.m_data.inner), ")", &ret); - break; case DataTag::None: break; case DataTag::ArrLikePacked: diff --git a/hphp/hhbbc/stats.cpp b/hphp/hhbbc/stats.cpp index d6f649bc3a6..aa702b5ca0b 100644 --- a/hphp/hhbbc/stats.cpp +++ b/hphp/hhbbc/stats.cpp @@ -60,9 +60,6 @@ TRACE_SET_MOD(hhbbc_stats); ////////////////////////////////////////////////////////////////////// #define STAT_TYPES \ - X(Gen) \ - X(InitGen) \ - X(Ref) \ X(Cell) \ X(InitCell) \ X(Unc) \ diff --git a/hphp/hhbbc/test/type-system.cpp b/hphp/hhbbc/test/type-system.cpp index 187365661b6..450db5c442b 100644 --- a/hphp/hhbbc/test/type-system.cpp +++ b/hphp/hhbbc/test/type-system.cpp @@ -280,7 +280,6 @@ auto const primitives = folly::lazy([] { TObj, TRes, TCls, - TRef, TClsMeth }; }); @@ -335,8 +334,6 @@ auto const non_opt_unions = folly::lazy([] { return std::vector { TInitCell, TCell, - TInitGen, - TGen, TNull, TBool, TNum, @@ -567,7 +564,6 @@ TEST(Type, Prim) { { TInitPrim, sval(s_test.get()) }, { TPrim, sval(s_test.get()) }, { TInitPrim, TUninit }, - { TPrim, TRef }, { TPrim, TObj }, }; @@ -894,36 +890,12 @@ TEST(Type, OptCouldBe) { } } -TEST(Type, Ref) { - EXPECT_TRUE(TRef == TRef); - EXPECT_TRUE(TRef != ref_to(TInt)); - EXPECT_TRUE(ref_to(TInt) == ref_to(TInt)); - EXPECT_TRUE(ref_to(TInt) != ref_to(TOptInt)); - - EXPECT_TRUE(TRef.couldBe(ref_to(TInt))); - EXPECT_TRUE(ref_to(TInt).couldBe(BRef)); - EXPECT_TRUE(!ref_to(TInt).couldBe(ref_to(TObj))); - EXPECT_TRUE(ref_to(TOptInt).couldBe(ref_to(TInt))); - - EXPECT_TRUE(!TRef.subtypeOf(ref_to(TInt))); - EXPECT_TRUE(ref_to(TInt).subtypeOf(BRef)); - EXPECT_TRUE(ref_to(TInt).subtypeOf(ref_to(TOptInt))); - EXPECT_TRUE(!ref_to(TOptInt).subtypeOf(ref_to(TInt))); - EXPECT_TRUE(!ref_to(TObj).subtypeOf(ref_to(TInt))); - EXPECT_TRUE(!ref_to(TInt).subtypeOf(ref_to(TObj))); - - EXPECT_TRUE(union_of(TRef, ref_to(TInt)) == TRef); - EXPECT_TRUE(union_of(ref_to(TInt), ref_to(TObj)) == ref_to(TInitCell)); - EXPECT_TRUE(union_of(ref_to(TInitNull), ref_to(TObj)) == ref_to(TOptObj)); -} - TEST(Type, SpecificExamples) { // Random examples to stress option types, values, etc: EXPECT_TRUE(!TInt.subtypeOf(ival(1))); EXPECT_TRUE(TInitCell.couldBe(ival(1))); - EXPECT_TRUE(TInitCell.subtypeOf(BGen)); EXPECT_TRUE(ival(2).subtypeOf(BInt)); EXPECT_TRUE(!ival(2).subtypeOf(BBool)); EXPECT_TRUE(ival(3).subtypeOrNull(BInt)); @@ -946,8 +918,6 @@ TEST(Type, SpecificExamples) { EXPECT_TRUE(TNull.couldBe(opt(ival(3)))); EXPECT_TRUE(TInitNull.subtypeOf(opt(ival(3)))); EXPECT_TRUE(!TNull.subtypeOf(opt(ival(3)))); - - EXPECT_EQ(TGen, union_of(TRef, TUninit)); } TEST(Type, IndexBased) { @@ -1604,16 +1574,16 @@ TEST(Type, FromHNIConstraint) { EXPECT_EQ(from_hni_constraint(makeStaticString("HH\\int")), TInt); EXPECT_EQ(from_hni_constraint(makeStaticString("HH\\float")), TDbl); EXPECT_EQ(from_hni_constraint(makeStaticString("?HH\\float")), TOptDbl); - EXPECT_EQ(from_hni_constraint(makeStaticString("HH\\mixed")), TInitGen); + EXPECT_EQ(from_hni_constraint(makeStaticString("HH\\mixed")), TInitCell); EXPECT_EQ(from_hni_constraint(makeStaticString("HH\\arraykey")), TArrKey); EXPECT_EQ(from_hni_constraint(makeStaticString("?HH\\arraykey")), TOptArrKey); // These are conservative, but we're testing them that way. If we // make the function better later we'll remove the tests. - EXPECT_EQ(from_hni_constraint(makeStaticString("stdClass")), TGen); - EXPECT_EQ(from_hni_constraint(makeStaticString("?stdClass")), TGen); - EXPECT_EQ(from_hni_constraint(makeStaticString("fooooo")), TGen); - EXPECT_EQ(from_hni_constraint(makeStaticString("")), TGen); + EXPECT_EQ(from_hni_constraint(makeStaticString("stdClass")), TCell); + EXPECT_EQ(from_hni_constraint(makeStaticString("?stdClass")), TCell); + EXPECT_EQ(from_hni_constraint(makeStaticString("fooooo")), TCell); + EXPECT_EQ(from_hni_constraint(makeStaticString("")), TCell); } TEST(Type, ArrPacked1) { @@ -1798,7 +1768,7 @@ TEST(Type, ArrPackedN) { EXPECT_TRUE(s2.subtypeOf(opt(arr_packedn(TInt)))); EXPECT_TRUE(s2.couldBe(arr_packedn(TInt))); - EXPECT_TRUE(s2.couldBe(arr_packedn(TInitGen))); + EXPECT_TRUE(s2.couldBe(arr_packedn(TInitCell))); auto const sn1 = sarr_packedn(TInt); auto const sn2 = sarr_packedn(TInitNull); @@ -2204,7 +2174,7 @@ TEST(Type, LoosenStaticness) { for (auto const& t : all()) { EXPECT_EQ(loosen_staticness(wait_handle(index, t)), wait_handle(index, loosen_staticness(t))); - if (t.subtypeOf(TInitGen)) { + if (t.subtypeOf(TInitCell)) { EXPECT_EQ(loosen_staticness(arr_packedn(t)), arr_packedn(loosen_staticness(t))); EXPECT_EQ(loosen_staticness(sarr_packedn(t)), @@ -2348,7 +2318,6 @@ TEST(Type, LoosenValues) { { sval(s_test.get()), TSStr }, { sval_nonstatic(s_test.get()), TStr }, { aval(test_array_packed_value()), TSPArrN }, - { ref_to(TInt), TRef }, { arr_packedn(TInt), TPArrN }, { arr_packed({TInt, TBool}), TPArrN }, { arr_packed_varray({TInt, TBool}), TVArrN }, @@ -2357,7 +2326,6 @@ TEST(Type, LoosenValues) { }; for (auto const& p : tests) { EXPECT_EQ(loosen_values(p.first), p.second); - if (p.first.subtypeOf(BRef)) continue; EXPECT_EQ(loosen_values(opt(p.first)), opt(p.second)); } diff --git a/hphp/hhbbc/type-system.cpp b/hphp/hhbbc/type-system.cpp index 5b6cd663f1e..84ec64a50a0 100644 --- a/hphp/hhbbc/type-system.cpp +++ b/hphp/hhbbc/type-system.cpp @@ -76,7 +76,7 @@ bool mayHaveData(trep bits) { case BArrN: case BSArrN: case BCArrN: case BOptArr: case BOptSArr: case BOptCArr: case BOptArrN: case BOptSArrN: case BOptCArrN: - case BRef: case BFunc: + case BFunc: case BVec: case BSVec: case BCVec: case BVecN: case BSVecN: case BCVecN: case BOptVec: case BOptSVec: case BOptCVec: @@ -178,8 +178,6 @@ bool mayHaveData(trep bits) { case BOptClsMeth: case BInitCell: case BCell: - case BInitGen: - case BGen: case BTop: break; } @@ -264,9 +262,6 @@ bool canBeOptional(trep bits) { case BKeyset: return true; - case BRef: - return false; - case BOptTrue: case BOptFalse: case BOptBool: @@ -334,9 +329,7 @@ bool canBeOptional(trep bits) { case BInitUnc: case BUnc: case BInitCell: - case BInitGen: case BCell: - case BGen: case BTop: return false; @@ -1625,7 +1618,6 @@ Type Type::unctxHelper(Type t, bool& changed) { case DataTag::Int: case DataTag::Dbl: case DataTag::Str: - case DataTag::RefInner: case DataTag::ArrLikeVal: break; } @@ -1764,7 +1756,6 @@ Ret Type::dd2nd(const Type& o, DDHelperFn f) const { case DataTag::Int: return f(); case DataTag::Dbl: return f(); case DataTag::Cls: return f(); - case DataTag::RefInner: return f(); case DataTag::Str: return f(o.m_data.sval); case DataTag::ArrLikeVal: return f(o.m_data.aval); case DataTag::ArrLikePacked: return f(*o.m_data.packed); @@ -1790,7 +1781,6 @@ Type::dualDispatchDataFn(const Type& o, Function f) const { case DataTag::Int: return f(); case DataTag::Dbl: return f(); case DataTag::Cls: return f(); - case DataTag::RefInner: return f(); case DataTag::Str: return dd2nd(o, ddbind(f, m_data.sval)); case DataTag::ArrLikeVal: return dd2nd(o, ddbind(f, m_data.aval)); case DataTag::ArrLikePacked: return dd2nd(o, ddbind(f, *m_data.packed)); @@ -1847,8 +1837,6 @@ bool Type::equivData(const Type& o) const { return m_data.dcls.type == o.m_data.dcls.type && m_data.dcls.cls.same(o.m_data.dcls.cls) && contextSensitiveCheck(m_data.dcls, o.m_data.dcls); - case DataTag::RefInner: - return m_data.inner->equivImpl(*o.m_data.inner); case DataTag::ArrLikePacked: if (m_data.packed->elems.size() != o.m_data.packed->elems.size()) { return false; @@ -1937,8 +1925,6 @@ bool Type::subtypeData(const Type& o) const { case DataTag::None: // Context sensitivity should not matter here. return equivData(o); - case DataTag::RefInner: - return m_data.inner->subtypeOfImpl(*o.m_data.inner); case DataTag::ArrLikePacked: return subtypePacked(*m_data.packed, *o.m_data.packed); case DataTag::ArrLikePackedN: @@ -1993,8 +1979,6 @@ bool Type::couldBeData(const Type& o) const { return m_data.dcls.cls.couldBe(o.m_data.dcls.cls); } return false; - case DataTag::RefInner: - return m_data.inner->couldBe(*o.m_data.inner); case DataTag::ArrLikeVal: return couldBeArrLike(m_data.aval, o.m_data.aval); case DataTag::Str: @@ -2050,8 +2034,6 @@ size_t Type::hash() const { return (uintptr_t)m_data.dobj.cls.name(); case DataTag::Cls: return (uintptr_t)m_data.dcls.cls.name(); - case DataTag::RefInner: - return 0; case DataTag::Str: return (uintptr_t)m_data.sval; case DataTag::Int: @@ -2089,7 +2071,6 @@ Type project_data(Type t, trep bits) { case DataTag::Obj: return restrict_to(BObj); case DataTag::Cls: return restrict_to(BCls); case DataTag::Str: return restrict_to(BStr); - case DataTag::RefInner: return restrict_to(BRef); case DataTag::ArrLikePacked: return restrict_to(BVecN | BDictN | BKeysetN | BArrN); case DataTag::ArrLikeMap: @@ -2214,8 +2195,7 @@ bool Type::checkInvariants() const { DEBUG_ONLY auto const keyBits = subtypeOrNull(BSArrLike) ? BUncArrKey : BArrKey; - DEBUG_ONLY auto const valBits = isPHPArray ? - BInitGen : isKeyset ? BArrKey : BInitCell; + DEBUG_ONLY auto const valBits = isKeyset ? BArrKey : BInitCell; /* * TODO(#3696042): for static arrays, we could enforce that all @@ -2229,9 +2209,6 @@ bool Type::checkInvariants() const { case DataTag::Str: assert(m_data.sval->isStatic()); break; case DataTag::Dbl: break; case DataTag::Int: break; - case DataTag::RefInner: - assert(!m_data.inner->couldBe(BRef)); - break; case DataTag::Cls: break; case DataTag::Obj: break; case DataTag::ArrLikeVal: @@ -2333,7 +2310,6 @@ ProvTag Type::getProvTag() const { case DataTag::Dbl: case DataTag::Obj: case DataTag::Cls: - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: return folly::none; @@ -2589,18 +2565,6 @@ Type clsExact(res::Class val) { return r; } -Type ref_to(Type t) { - assert(t.subtypeOf(BInitCell)); - auto r = Type{BRef}; - construct_inner(r.m_data.inner, std::move(t)); - r.m_dataTag = DataTag::RefInner; - return r; -} - -bool is_ref_with_inner(const Type& t) { - return t.m_dataTag == DataTag::RefInner; -} - bool is_specialized_array_like(const Type& t) { switch (t.m_dataTag) { case DataTag::None: @@ -2609,7 +2573,6 @@ bool is_specialized_array_like(const Type& t) { case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: return false; case DataTag::ArrLikeVal: case DataTag::ArrLikePacked: @@ -2828,7 +2791,7 @@ Type unnullish(Type t) { } Type return_with_context(Type t, Type context) { - assertx(t.subtypeOf(BInitGen)); + assertx(t.subtypeOf(BInitCell)); // We don't assert the context is a TCls or TObj because sometimes we set it // to TTop when handling dynamic calls. if (((is_specialized_obj(t) && t.m_data.dobj.isCtx) || @@ -2926,7 +2889,6 @@ folly::Optional arr_size(const Type& t) { case DataTag::Int: case DataTag::Dbl: case DataTag::Str: - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -2983,7 +2945,6 @@ Type::ArrayCat categorize_array(const Type& t) { case DataTag::Int: case DataTag::Dbl: case DataTag::Str: - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -3022,7 +2983,6 @@ CompactVector get_string_keys(const Type& t) { case DataTag::Int: case DataTag::Dbl: case DataTag::Str: - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -3200,7 +3160,6 @@ R tvImpl(const Type& t) { folly::none); } break; - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -3246,7 +3205,6 @@ Type scalarize(Type t) { case DataTag::ArrLikeMap: case DataTag::ArrLikePacked: return from_cell(*tv(t)); - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -3265,7 +3223,6 @@ folly::Optional array_size(const Type& t) { case DataTag::Int: case DataTag::Dbl: case DataTag::Str: - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -3289,7 +3246,6 @@ array_get_by_index(const Type& t, ssize_t index) { case DataTag::Int: case DataTag::Dbl: case DataTag::Str: - case DataTag::RefInner: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMapN: case DataTag::Obj: @@ -3575,7 +3531,7 @@ Type from_DataType(DataType dt) { case KindOfRecord: return TRecord; case KindOfPersistentArray: case KindOfArray: return TArr; - case KindOfRef: return TRef; + case KindOfRef: return TBottom; case KindOfObject: return TObj; case KindOfResource: return TRes; case KindOfFunc: return TFunc; @@ -3586,7 +3542,7 @@ Type from_DataType(DataType dt) { } Type from_hni_constraint(SString s) { - if (!s) return TGen; + if (!s) return TCell; auto p = s->data(); auto ret = TBottom; @@ -3627,12 +3583,12 @@ Type from_hni_constraint(SString s) { union_of(TArr, union_of(TVec, union_of(TDict, TKeyset)))); } if (!strcasecmp(p, "array")) return union_of(ret, TArr); - if (!strcasecmp(p, "HH\\mixed")) return TInitGen; - if (!strcasecmp(p, "HH\\nonnull")) return TInitGen; + if (!strcasecmp(p, "HH\\mixed")) return TInitCell; + if (!strcasecmp(p, "HH\\nonnull")) return TInitCell; // It might be an object, or we might want to support type aliases in HNI at // some point. For now just be conservative. - return TGen; + return TCell; } Type intersection_of(Type a, Type b) { @@ -3722,13 +3678,6 @@ Type intersection_of(Type a, Type b) { case DataTag::Dbl: // Neither is a subtype of the other, so the intersection is empty return TBottom; - case DataTag::RefInner: - { - auto inner = intersection_of(*a.m_data.inner, *b.m_data.inner); - if (inner == TBottom) return TBottom; - *a.m_data.inner.mutate() = inner; - return fix(a); - } case DataTag::ArrLikePacked: case DataTag::ArrLikePackedN: case DataTag::ArrLikeMap: @@ -3742,7 +3691,7 @@ Type intersection_of(Type a, Type b) { if (t != TBottom) return t; auto const bits = - isect & ~(BInt|BDbl|BSStr|BArrN|BVecN|BDictN|BKeysetN|BObj|BRef); + isect & ~(BInt|BDbl|BSStr|BArrN|BVecN|BDictN|BKeysetN|BObj); return Type { bits }; } @@ -3867,10 +3816,6 @@ Type union_of(Type a, Type b) { if (t != TBottom) return t; } - if (is_ref_with_inner(a) && is_ref_with_inner(b)) { - return ref_to(union_of(*a.m_data.inner, *b.m_data.inner)); - } - /* * Merging option types tries to preserve subtype information where it's * possible. E.g. if you union InitNull and Obj<=Foo, we want OptObj<=Foo to @@ -3962,8 +3907,6 @@ Type union_of(Type a, Type b) { X(Unc) X(InitCell) X(Cell) - X(InitGen) - X(Gen) #undef Y #undef X @@ -3982,10 +3925,8 @@ Type promote_emptyish(Type a, Type b) { t = BInitPrim; } else if (trep(t & BInitUnc) == t) { t = BInitUnc; - } else if (trep(t & BInitCell) == t) { - t = BInitCell; } else { - t = BInitGen; + t = BInitCell; } return union_of(Type { t }, b); } @@ -4052,9 +3993,6 @@ void widen_type_impl(Type& t, uint32_t depth) { } return; - case DataTag::RefInner: - return widen_type_impl(*t.m_data.inner.mutate(), depth + 1); - case DataTag::ArrLikePacked: { if (checkDepth()) return; auto& packed = *t.m_data.packed.mutate(); @@ -4108,8 +4046,6 @@ Type widening_union(const Type& a, const Type& b) { Type stack_flav(Type a) { if (a.subtypeOf(BUninit)) return TUninit; if (a.subtypeOf(BInitCell)) return TInitCell; - if (a.subtypeOf(BRef)) return TRef; - if (a.subtypeOf(BGen)) return TGen; always_assert(0 && "stack_flav passed invalid type"); } @@ -4153,12 +4089,6 @@ Type loosen_staticness(Type t) { } break; - case DataTag::RefInner: { - auto inner = t.m_data.inner.mutate(); - *inner = loosen_staticness(std::move(*inner)); - break; - } - case DataTag::ArrLikePacked: { auto& packed = *t.m_data.packed.mutate(); for (auto& e : packed.elems) { @@ -4239,12 +4169,6 @@ Type loosen_provenance(Type t) { } break; - case DataTag::RefInner: { - auto inner = t.m_data.inner.mutate(); - *inner = loosen_provenance(std::move(*inner)); - break; - } - case DataTag::ArrLikePacked: { auto& packed = *t.m_data.packed.mutate(); packed.provenance = folly::none; @@ -4294,7 +4218,6 @@ Type loosen_values(Type a) { case DataTag::Str: case DataTag::Int: case DataTag::Dbl: - case DataTag::RefInner: case DataTag::ArrLikeVal: case DataTag::ArrLikePacked: case DataTag::ArrLikePackedN: @@ -4361,13 +4284,13 @@ Type add_nonemptiness(Type t) { } Type remove_uninit(Type t) { - assert(t.subtypeOf(BGen)); + assert(t.subtypeOf(BCell)); if (!t.couldBe(BUninit)) return t; if (isPredefined(t.m_bits & ~BUninit)) { t.m_bits &= ~BUninit; return t; } - return t.subtypeOf(BCell) ? TInitCell : TInitGen; + return TInitCell; } Type to_cell(Type t) { @@ -4899,7 +4822,6 @@ std::pair array_like_elem(const Type& arr, case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: not_reached(); case DataTag::None: { @@ -4983,7 +4905,6 @@ std::pair array_like_set(Type arr, ProvTag loc) { const bool maybeEmpty = arr.couldBe(BArrLikeE); const bool isVector = arr.couldBe(BVec); - const bool isPhpArray = arr.couldBe(BArr); DEBUG_ONLY const bool isVArray = arr.subtypeOrNull(BVArr); const bool validKey = key.type.subtypeOf(isVector ? BInt : BArrKey); @@ -4998,10 +4919,9 @@ std::pair array_like_set(Type arr, } }(); - auto const fixRef = !isPhpArray && valIn.couldBe(BRef); - auto const throwMode = !fixRef && validKey && !key.mayThrow ? + auto const throwMode = validKey && !key.mayThrow ? ThrowMode::None : ThrowMode::BadOperation; - auto const& val = fixRef ? TInitCell : valIn; + auto const& val = valIn; // We don't want to store types more general than TArrKey into specialized // array type keys. If the key was strange (array or object), it will be more // general than TArrKey (this is needed so we can set validKey above), so @@ -5050,7 +4970,6 @@ std::pair array_like_set(Type arr, case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: not_reached(); case DataTag::None: @@ -5130,12 +5049,6 @@ std::pair array_set(Type arr, ProvTag src) { assert(arr.subtypeOf(BArr)); - // Unless you know an array can't cow, you don't know if the TRef - // will stay a TRef or turn back into a TInitCell. Generally you - // want a TInitGen. - always_assert((val == TBottom || !val.subtypeOf(BRef)) && - "You probably don't want to put Ref types into arrays ..."); - auto const key = disect_array_key(undisectedKey); assert(key.type != TBottom); return array_like_set(std::move(arr), key, val, src); @@ -5182,7 +5095,6 @@ std::pair array_like_newelem(Type arr, case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: not_reached(); case DataTag::None: @@ -5261,12 +5173,6 @@ std::pair array_like_newelem(Type arr, std::pair array_newelem(Type arr, const Type& val, ProvTag src) { assert(arr.subtypeOf(BArr)); - // Unless you know an array can't cow, you don't know if the TRef - // will stay a TRef or turn back into a TInitCell. Generally you - // want a TInitGen. - always_assert((val == TBottom || !val.subtypeOf(BRef)) && - "You probably don't want to put Ref types into arrays ..."); - return array_like_newelem(std::move(arr), val, src); } @@ -5346,7 +5252,6 @@ IterTypes iter_types(const Type& iterable) { case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: always_assert(0); case DataTag::ArrLikeVal: { auto kv = val_key_values(iterable.m_data.aval); @@ -5403,13 +5308,6 @@ bool could_contain_objects(const Type& t) { auto const couldBeArrWithDestructors = t.m_bits & (BCArrN | BCVecN | BCDictN); - if (t.couldBe(BRef)) { - if (!couldBeArrWithDestructors && is_ref_with_inner(t)) { - return could_contain_objects(*t.m_data.inner); - } - return true; - } - if (!couldBeArrWithDestructors) return false; switch (t.m_dataTag) { @@ -5419,7 +5317,6 @@ bool could_contain_objects(const Type& t) { case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: return true; case DataTag::ArrLikeVal: return false; case DataTag::ArrLikePacked: @@ -5506,7 +5403,6 @@ bool inner_types_might_raise(const Type& t1, const Type& t2) { case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: not_reached(); case DataTag::ArrLikeVal: @@ -5554,7 +5450,6 @@ bool inner_types_might_raise(const Type& t1, const Type& t2) { case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: not_reached(); case DataTag::ArrLikeVal: @@ -5766,7 +5661,6 @@ RepoAuthType make_repo_type_arr(ArrayTypeTable::Builder& arrTable, case DataTag::Int: case DataTag::Dbl: case DataTag::Cls: - case DataTag::RefInner: case DataTag::ArrLikeVal: case DataTag::ArrLikeMap: case DataTag::ArrLikeMapN: @@ -5913,9 +5807,6 @@ RepoAuthType make_repo_type(ArrayTypeTable::Builder& arrTable, const Type& t) { X(Unc) X(InitCell) X(Cell) - X(Ref) - X(InitGen) - X(Gen) #undef X not_reached(); } diff --git a/hphp/hhbbc/type-system.h b/hphp/hhbbc/type-system.h index c5ff067d6de..0a01e105b45 100644 --- a/hphp/hhbbc/type-system.h +++ b/hphp/hhbbc/type-system.h @@ -46,11 +46,11 @@ struct Type; * * Top * | - * +-----+ InitGen := Gen - Uninit + * +-----+ * | | InitCell := Cell - Uninit - * Cls Gen---+ ?X := X + InitNull - * | | | - * Cls<=c Cell Ref + * Cls | ?X := X + InitNull + * | | + * Cls<=c Cell * | | * Cls=c +-------------+--------+-------+-------+-----+ * | | | | | | @@ -226,22 +226,21 @@ enum trep : uint64_t { BObj = 1ULL << 22, BRes = 1ULL << 23, BCls = 1ULL << 24, - BRef = 1ULL << 25, - - BSVecE = 1ULL << 26, // static empty vec - BCVecE = 1ULL << 27, // counted empty vec - BSVecN = 1ULL << 28, // static non-empty vec - BCVecN = 1ULL << 29, // counted non-empty vec - BSDictE = 1ULL << 30, // static empty dict - BCDictE = 1ULL << 31, // counted empty dict - BSDictN = 1ULL << 32, // static non-empty dict - BCDictN = 1ULL << 33, // counted non-empty dict - BSKeysetE = 1ULL << 34, // static empty keyset - BCKeysetE = 1ULL << 35, // counted empty keyset - BSKeysetN = 1ULL << 36, // static non-empty keyset - BCKeysetN = 1ULL << 37, // counted non-empty keyset - - BRecord = 1ULL << 38, + + BSVecE = 1ULL << 25, // static empty vec + BCVecE = 1ULL << 26, // counted empty vec + BSVecN = 1ULL << 27, // static non-empty vec + BCVecN = 1ULL << 28, // counted non-empty vec + BSDictE = 1ULL << 29, // static empty dict + BCDictE = 1ULL << 30, // counted empty dict + BSDictN = 1ULL << 31, // static non-empty dict + BCDictN = 1ULL << 32, // counted non-empty dict + BSKeysetE = 1ULL << 33, // static empty keyset + BCKeysetE = 1ULL << 34, // counted empty keyset + BSKeysetN = 1ULL << 35, // static non-empty keyset + BCKeysetN = 1ULL << 36, // counted non-empty keyset + + BRecord = 1ULL << 37, BSPArr = BSPArrE | BSPArrN, BCPArr = BCPArrE | BCPArrN, @@ -394,8 +393,6 @@ enum trep : uint64_t { BInitCell = BInitNull | BBool | BInt | BDbl | BStr | BArr | BObj | BRes | BVec | BDict | BKeyset | BFunc | BCls | BClsMeth | BRecord, BCell = BUninit | BInitCell, - BInitGen = BInitCell | BRef, - BGen = BUninit | BInitGen, BTop = static_cast(-1), }; @@ -436,7 +433,6 @@ constexpr auto BSArrLike = BSArr | BSVec | BSDict | BSKeyset; DT(ArrLikeVal, SArray, aval) \ DT(Obj, DObj, dobj) \ DT(Cls, DCls, dcls) \ - DT(RefInner, copy_ptr, inner) \ DT(ArrLikePacked, copy_ptr, packed) \ DT(ArrLikePackedN, copy_ptr, packedn) \ DT(ArrLikeMap, copy_ptr, map) \ @@ -646,7 +642,6 @@ private: friend bool is_specialized_array_like(const Type& t); friend bool is_specialized_obj(const Type&); friend bool is_specialized_cls(const Type&); - friend bool is_ref_with_inner(const Type&); friend bool is_specialized_string(const Type&); friend Type wait_handle_inner(const Type&); friend Type sval(SString); @@ -658,7 +653,6 @@ private: friend Type objExact(res::Class); friend Type subCls(res::Class); friend Type clsExact(res::Class); - friend Type ref_to(Type); friend Type rname(SString); friend Type packed_impl(trep, std::vector, ProvTag); friend Type packedn_impl(trep, Type); @@ -853,7 +847,6 @@ X(SArrN) \ X(Obj) \ X(Res) \ X(Cls) \ -X(Ref) \ X(Func) \ X(ClsMeth) \ X(Record) \ @@ -971,8 +964,6 @@ X(OptUncStrLike) \ X(OptStrLike) \ X(InitCell) \ X(Cell) \ -X(InitGen) \ -X(Gen) \ X(Top) #define X(y) extern const Type T##y; @@ -1471,9 +1462,9 @@ bool could_have_magic_bool_conversion(const Type&); /* * Returns the smallest type that `a' is a subtype of, from the - * following set: TGen, TInitCell, TRef, TUninit, TCls. + * following set: TInitCell, TUninit. * - * Pre: `a' is a subtype of TGen, or TCls. + * Pre: `a' is a subtype of TCell. */ Type stack_flav(Type a); diff --git a/hphp/runtime/base/repo-auth-type-codec-inl.h b/hphp/runtime/base/repo-auth-type-codec-inl.h index 7acc2d80a11..90b00c38964 100644 --- a/hphp/runtime/base/repo-auth-type-codec-inl.h +++ b/hphp/runtime/base/repo-auth-type-codec-inl.h @@ -83,9 +83,6 @@ size_t encodedRATSize(const unsigned char* pc) { case T::Unc: case T::InitCell: case T::Cell: - case T::Ref: - case T::InitGen: - case T::Gen: assertx(!highBitSet); return tagSize; case T::SArr: diff --git a/hphp/runtime/base/repo-auth-type-codec.cpp b/hphp/runtime/base/repo-auth-type-codec.cpp index 2effcce1fb3..5e1ab43dde4 100644 --- a/hphp/runtime/base/repo-auth-type-codec.cpp +++ b/hphp/runtime/base/repo-auth-type-codec.cpp @@ -78,9 +78,6 @@ RepoAuthType decodeRATImpl(const unsigned char*& pc, LookupStr lookupStr, case T::Unc: case T::InitCell: case T::Cell: - case T::Ref: - case T::InitGen: - case T::Gen: assertx(!highBitSet); return RepoAuthType{tag}; @@ -204,9 +201,6 @@ void encodeRAT(UnitEmitter& ue, RepoAuthType rat) { case T::Unc: case T::InitCell: case T::Cell: - case T::Ref: - case T::InitGen: - case T::Gen: break; case T::SArr: diff --git a/hphp/runtime/base/repo-auth-type.cpp b/hphp/runtime/base/repo-auth-type.cpp index c67343c0811..04aafea3626 100644 --- a/hphp/runtime/base/repo-auth-type.cpp +++ b/hphp/runtime/base/repo-auth-type.cpp @@ -120,7 +120,6 @@ bool RepoAuthType::operator==(RepoAuthType o) const { case T::OptUncStrLike: case T::Null: case T::Cell: - case T::Ref: case T::InitUnc: case T::Unc: case T::ArrKey: @@ -128,8 +127,6 @@ bool RepoAuthType::operator==(RepoAuthType o) const { case T::StrLike: case T::UncStrLike: case T::InitCell: - case T::InitGen: - case T::Gen: case T::Uninit: case T::InitNull: case T::Bool: @@ -468,15 +465,6 @@ bool tvMatchesRepoAuthType(TypedValue tv, RepoAuthType ty) { // fallthrough case T::Cell: return !isRefType(tv.m_type); - - case T::Ref: - return isRefType(tv.m_type); - - case T::InitGen: - if (tv.m_type == KindOfUninit) return false; - // fallthrough - case T::Gen: - return true; } not_reached(); } @@ -502,7 +490,6 @@ std::string show(RepoAuthType rat) { case T::OptStrLike: return "?StrLike"; case T::Null: return "Null"; case T::Cell: return "Cell"; - case T::Ref: return "Ref"; case T::InitUnc: return "InitUnc"; case T::Unc: return "Unc"; case T::UncArrKey: return "UncArrKey"; @@ -510,8 +497,6 @@ std::string show(RepoAuthType rat) { case T::UncStrLike: return "UncStrLike"; case T::StrLike: return "StrLike"; case T::InitCell: return "InitCell"; - case T::InitGen: return "InitGen"; - case T::Gen: return "Gen"; case T::Uninit: return "Uninit"; case T::InitNull: return "InitNull"; case T::Bool: return "Bool"; diff --git a/hphp/runtime/base/repo-auth-type.h b/hphp/runtime/base/repo-auth-type.h index b3def3b8572..9001de4dee3 100644 --- a/hphp/runtime/base/repo-auth-type.h +++ b/hphp/runtime/base/repo-auth-type.h @@ -94,9 +94,6 @@ struct RepoAuthType { TAG(OptStrLike) \ TAG(InitCell) \ TAG(Cell) \ - TAG(Ref) \ - TAG(InitGen) \ - TAG(Gen) \ /* Types where array() may be non-null. */ \ TAG(SArr) \ TAG(OptSArr) \ @@ -138,7 +135,7 @@ struct RepoAuthType { #undef TAG }; - explicit RepoAuthType(Tag tag = Tag::Gen, const StringData* sd = nullptr) { + explicit RepoAuthType(Tag tag = Tag::Cell, const StringData* sd = nullptr) { m_data.set(static_cast(tag), sd); switch (tag) { case Tag::OptSubObj: case Tag::OptExactObj: diff --git a/hphp/runtime/vm/as.cpp b/hphp/runtime/vm/as.cpp index 56e9b40affe..65433015648 100644 --- a/hphp/runtime/vm/as.cpp +++ b/hphp/runtime/vm/as.cpp @@ -1013,9 +1013,7 @@ RepoAuthType read_repo_auth_type(AsmState& as) { X("Cell", T::Cell); X("Dbl", T::Dbl); X("?Dbl", T::OptDbl); - X("Gen", T::Gen); X("InitCell", T::InitCell); - X("InitGen", T::InitGen); X("InitNull", T::InitNull); X("InitUnc", T::InitUnc); X("Int", T::Int); @@ -1031,7 +1029,6 @@ RepoAuthType read_repo_auth_type(AsmState& as) { X("?ClsMeth", T::OptClsMeth); X("Record", T::Record); X("?Record", T::OptRecord); - X("Ref", T::Ref); X("?Res", T::OptRes); X("Res", T::Res); X("?SArr", T::OptSArr); @@ -1128,9 +1125,6 @@ RepoAuthType read_repo_auth_type(AsmState& as) { case T::StrLike: case T::InitCell: case T::Cell: - case T::Ref: - case T::InitGen: - case T::Gen: case T::ExactObj: case T::SubObj: case T::OptExactObj: diff --git a/hphp/runtime/vm/func.cpp b/hphp/runtime/vm/func.cpp index fbdd076b5fe..edc523c554b 100644 --- a/hphp/runtime/vm/func.cpp +++ b/hphp/runtime/vm/func.cpp @@ -643,10 +643,10 @@ void Func::prettyPrint(std::ostream& out, const PrintOpts& opts) const { out << std::endl; } - if (repoReturnType().tag() != RepoAuthType::Tag::Gen) { + if (repoReturnType().tag() != RepoAuthType::Tag::Cell) { out << "repoReturnType: " << show(repoReturnType()) << '\n'; } - if (repoAwaitedReturnType().tag() != RepoAuthType::Tag::Gen) { + if (repoAwaitedReturnType().tag() != RepoAuthType::Tag::Cell) { out << "repoAwaitedReturnType: " << show(repoAwaitedReturnType()) << '\n'; } out << "maxStackCells: " << maxStackCells() << '\n' diff --git a/hphp/runtime/vm/jit/type.cpp b/hphp/runtime/vm/jit/type.cpp index 3ee791de307..c5db025e1b5 100644 --- a/hphp/runtime/vm/jit/type.cpp +++ b/hphp/runtime/vm/jit/type.cpp @@ -913,7 +913,6 @@ Type typeFromRAT(RepoAuthType ty, const Class* ctx) { case T::Record: return TRecord; case T::Cell: return TCell; - case T::Ref: return TBoxedInitCell; case T::UncArrKey: return TInt | TPersistentStr; case T::ArrKey: return TInt | TStr; case T::UncStrLike: return TFunc | TPersistentStr; @@ -921,8 +920,6 @@ Type typeFromRAT(RepoAuthType ty, const Class* ctx) { case T::InitUnc: return TUncountedInit; case T::Unc: return TUncounted; case T::InitCell: return TInitCell; - case T::InitGen: return TInitGen; - case T::Gen: return TGen; #define X(A, B) \ [&]{ \ diff --git a/hphp/runtime/vm/verifier/pretty.cpp b/hphp/runtime/vm/verifier/pretty.cpp index 6375868d008..1abd68e1236 100644 --- a/hphp/runtime/vm/verifier/pretty.cpp +++ b/hphp/runtime/vm/verifier/pretty.cpp @@ -82,10 +82,10 @@ void pretty_print(const FuncEmitter* fe, std::ostream& out) { out << std::endl; } - if (fe->repoReturnType.tag() != RepoAuthType::Tag::Gen) { + if (fe->repoReturnType.tag() != RepoAuthType::Tag::Cell) { out << "repoReturnType: " << show(fe->repoReturnType) << '\n'; } - if (fe->repoAwaitedReturnType.tag() != RepoAuthType::Tag::Gen) { + if (fe->repoAwaitedReturnType.tag() != RepoAuthType::Tag::Cell) { out << "repoAwaitedReturnType: " << show(fe->repoAwaitedReturnType) << '\n'; } out << "maxStackCells: " << fe->maxStackCells << '\n' -- 2.11.4.GIT