Skip to content

Commit

Permalink
Clean up func resolution code in HHBBC
Browse files Browse the repository at this point in the history
Summary:
Remove the renamable flag since it was only ever false. Remove some no
longer needed helper functions.

Reviewed By: mdko

Differential Revision: D45878545

fbshipit-source-id: 3d3dfab801b3df701b27127eed5e1d395a9b1224
  • Loading branch information
ricklavoie authored and facebook-github-bot committed May 16, 2023
1 parent 0e6fc5f commit 5ce4374
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 82 deletions.
75 changes: 26 additions & 49 deletions hphp/hhbbc/index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3163,6 +3163,20 @@ const php::Func* Func::exactFunc() const {
);
}

TriBool Func::exists() const {
return match<TriBool>(
val,
[&](FuncName) { return TriBool::Maybe; },
[&](MethodName) { return TriBool::Maybe; },
[&](FuncInfo*) { return TriBool::Yes; },
[&](Method) { return TriBool::Yes; },
[&](MethodFamily) { return TriBool::Maybe; },
[&](MethodOrMissing) { return TriBool::Maybe; },
[&](Missing) { return TriBool::No; },
[&](const Isect&) { return TriBool::Maybe; }
);
}

bool Func::isFoldable() const {
return match<bool>(
val,
Expand Down Expand Up @@ -3241,9 +3255,7 @@ bool Func::mightCareAboutDynCalls() const {
bool Func::mightBeBuiltin() const {
return match<bool>(
val,
// Builtins are always uniquely resolvable unless renaming is
// involved.
[&](FuncName s) { return s.renamable; },
[&](FuncName s) { return true; },
[&](MethodName) { return true; },
[&](FuncInfo* fi) { return fi->func->attrs & AttrBuiltin; },
[&](Method m) { return m.func->attrs & AttrBuiltin; },
Expand Down Expand Up @@ -3379,7 +3391,7 @@ std::string show(const Func& f) {
auto ret = f.name()->toCppString();
match<void>(
f.val,
[&](Func::FuncName s) { if (s.renamable) ret += '?'; },
[&](Func::FuncName s) {},
[&](Func::MethodName) {},
[&](FuncInfo*) { ret += "*"; },
[&](Func::Method) { ret += "*"; },
Expand Down Expand Up @@ -14216,24 +14228,13 @@ res::Func Index::resolve_ctor(const Type& obj) const {
);
}

res::Func
Index::resolve_func_helper(const php::Func* func, SString name) const {
auto name_only = [&] (bool renamable) {
return res::Func { res::Func::FuncName { name, renamable } };
};

// no resolution
if (func == nullptr) return name_only(false);

// single resolution, in whole-program mode, that's it
assertx(func->attrs & AttrUnique);
return do_resolve(func);
}

res::Func Index::resolve_func(Context /*ctx*/, SString name) const {
res::Func Index::resolve_func(SString name) const {
name = normalizeNS(name);
auto const it = m_data->funcs.find(name);
return resolve_func_helper((it != end(m_data->funcs)) ? it->second : nullptr, name);
if (it == end(m_data->funcs)) return res::Func { res::Func::Missing {} };
auto const func = it->second;
assertx(func->attrs & AttrUnique);
return res::Func { func_info(*m_data, func) };
}

bool Index::could_have_reified_type(Context ctx,
Expand Down Expand Up @@ -14651,7 +14652,7 @@ Type Index::lookup_constant(Context ctx, SString cnsName) const {
auto const func_name = Constant::funcNameFromName(cnsName);
assertx(func_name && "func_name will never be nullptr");

auto rfunc = resolve_func(ctx, func_name);
auto rfunc = resolve_func(func_name);
return lookup_return_type(ctx, nullptr, rfunc, Dep::ConstVal);
}

Expand Down Expand Up @@ -14932,11 +14933,7 @@ Optional<uint32_t> Index::lookup_num_inout_params(
return match<Optional<uint32_t>>(
rfunc.val,
[&] (res::Func::FuncName s) -> Optional<uint32_t> {
if (s.renamable) return std::nullopt;
auto const it = m_data->funcs.find(s.name);
return it != end(m_data->funcs)
? func_num_inout(it->second)
: 0;
return std::nullopt;
},
[&] (res::Func::MethodName s) -> Optional<uint32_t> {
return std::nullopt;
Expand Down Expand Up @@ -14981,11 +14978,7 @@ PrepKind Index::lookup_param_prep(Context,
return match<PrepKind>(
rfunc.val,
[&] (res::Func::FuncName s) {
if (s.renamable) return PrepKind{TriBool::Maybe, TriBool::Maybe};
auto const it = m_data->funcs.find(s.name);
return it != end(m_data->funcs)
? func_param_prep(it->second, paramId)
: PrepKind{TriBool::No, TriBool::Yes};
return PrepKind{TriBool::Maybe, TriBool::Maybe};
},
[&] (res::Func::MethodName s) {
return PrepKind{TriBool::Maybe, TriBool::Maybe};
Expand Down Expand Up @@ -15035,13 +15028,7 @@ TriBool Index::lookup_return_readonly(
) const {
return match<TriBool>(
rfunc.val,
[&] (res::Func::FuncName s) {
if (s.renamable) return TriBool::Maybe;
auto const it = m_data->funcs.find(s.name);
return it != end(m_data->funcs)
? yesOrNo(it->second->isReadonlyReturn)
: TriBool::No; // if the function doesnt exist, we will error anyway
},
[&] (res::Func::FuncName s) { return TriBool::Maybe; },
[&] (res::Func::MethodName s) { return TriBool::Maybe; },
[&] (FuncInfo* finfo) {
return yesOrNo(finfo->func->isReadonlyReturn);
Expand Down Expand Up @@ -15076,13 +15063,7 @@ TriBool Index::lookup_readonly_this(
) const {
return match<TriBool>(
rfunc.val,
[&] (res::Func::FuncName s) {
if (s.renamable) return TriBool::Maybe;
auto const it = m_data->funcs.find(s.name);
return it != end(m_data->funcs)
? yesOrNo(it->second->isReadonlyThis)
: TriBool::Yes; // if the function doesnt exist, we will error anyway
},
[&] (res::Func::FuncName s) { return TriBool::Maybe; },
[&] (res::Func::MethodName s) { return TriBool::Maybe; },
[&] (FuncInfo* finfo) {
return yesOrNo(finfo->func->isReadonlyThis);
Expand Down Expand Up @@ -16081,10 +16062,6 @@ void Index::thaw() {

//////////////////////////////////////////////////////////////////////

res::Func Index::do_resolve(const php::Func* f) const {
return res::Func { func_info(*m_data, f) };
};

// Return true if we know for sure that one php::Class must derive
// from another at runtime, in all possible instantiations.
bool Index::must_be_derived_from(const php::Class* cls,
Expand Down
21 changes: 11 additions & 10 deletions hphp/hhbbc/index.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,12 @@ struct Func {
*/
const php::Func* exactFunc() const;

/*
* Whether this function definitely exists or definitely does not
* exist.
*/
TriBool exists() const;

/*
* Returns whether this resolved function is definitely safe to constant fold.
*/
Expand Down Expand Up @@ -636,10 +642,9 @@ struct Func {
private:
friend struct ::HPHP::HHBBC::Index;
struct FuncName {
FuncName(SString n, bool r) : name{n}, renamable{r} {}
explicit FuncName(SString n) : name{n} {}
bool operator==(FuncName o) const { return name == o.name; }
SString name;
bool renamable;
};
struct MethodName {
bool operator==(MethodName o) const { return name == o.name; }
Expand Down Expand Up @@ -951,13 +956,12 @@ struct Index {
res::Class builtin_class(SString name) const;

/*
* Try to resolve a function named `name' from a given context.
* Try to resolve a function named `name'.
*
* Note, the returned function may or may not be defined at the
* program point (it could require a function autoload that might
* fail).
* Returns std::nullopt if no such function with that name is known
* to exist.
*/
res::Func resolve_func(Context, SString name) const;
res::Func resolve_func(SString name) const;

/*
* Try to resolve a method named `name' with a this type of
Expand Down Expand Up @@ -1418,9 +1422,6 @@ struct Index {
private:
friend struct PublicSPropMutations;

res::Func resolve_func_helper(const php::Func*, SString) const;
res::Func do_resolve(const php::Func*) const;

template <typename F>
bool visit_every_dcls_cls(const DCls&, const F&) const;

Expand Down
28 changes: 16 additions & 12 deletions hphp/hhbbc/interp-builtin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,23 @@ TypeOrReduced builtin_is_numeric(ISS& env, const php::Func* func,
TypeOrReduced builtin_function_exists(ISS& env, const php::Func* func,
const FCallArgs& fca) {
assertx(fca.numArgs() >= 1 && fca.numArgs() <= 2);
if (!handle_function_exists(env, getArg(env, func, fca, 0))) {
return NoReduced{};

auto const name = getArg(env, func, fca, 0);
if (!name.strictSubtypeOf(BStr)) return NoReduced{};
auto const v = tv(name);
if (!v) return NoReduced{};
auto const rfunc = env.index.resolve_func(v->m_data.pstr);
switch (rfunc.exists()) {
case TriBool::Yes:
constprop(env);
return TTrue;
case TriBool::No:
constprop(env);
return TFalse;
case TriBool::Maybe:
return NoReduced{};
}
constprop(env);
return TTrue;
not_reached();
}

TypeOrReduced handle_oodecl_exists(ISS& env,
Expand Down Expand Up @@ -636,14 +648,6 @@ bool optimize_builtin(ISS& env, const php::Func* func, const FCallArgs& fca) {
return handle_builtin(env, func, fca);
}

bool handle_function_exists(ISS& env, const Type& name) {
if (!name.strictSubtypeOf(BStr)) return false;
auto const v = tv(name);
if (!v) return false;
auto const rfunc = env.index.resolve_func(env.ctx, v->m_data.pstr);
return rfunc.exactFunc();
}

Optional<Type> const_fold(ISS& env,
uint32_t nArgs,
uint32_t numExtraInputs,
Expand Down
12 changes: 3 additions & 9 deletions hphp/hhbbc/interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1803,7 +1803,7 @@ std::pair<Type, bool> memoizeImplRetType(ISS& env) {
memoize_impl_name(env.ctx.func)
);
}
return env.index.resolve_func(env.ctx, memoize_impl_name(env.ctx.func));
return env.index.resolve_func(memoize_impl_name(env.ctx.func));
}();

// Infer the return type of the wrapped function, taking into account the
Expand Down Expand Up @@ -3851,12 +3851,6 @@ void fcallKnownImpl(
return;
}

if (func.name()->isame(s_function_exists.get()) &&
(numArgs == 1 || numArgs == 2) &&
!fca.hasUnpack() && !fca.hasGenerics()) {
handle_function_exists(env, topT(env, numExtraInputs + numArgs - 1));
}

for (auto i = uint32_t{0}; i < numExtraInputs; ++i) popC(env);
if (fca.hasGenerics()) popC(env);
if (fca.hasUnpack()) popC(env);
Expand Down Expand Up @@ -3896,7 +3890,7 @@ void fcallUnknownImpl(ISS& env,
}

void in(ISS& env, const bc::FCallFuncD& op) {
auto const rfunc = env.index.resolve_func(env.ctx, op.str2);
auto const rfunc = env.index.resolve_func(op.str2);

if (op.fca.hasGenerics()) {
auto const tsList = topC(env);
Expand Down Expand Up @@ -4135,7 +4129,7 @@ void fcallFuncStr(ISS& env, const bc::FCallFunc& op) {
return fcallFuncUnknown(env, op);
}

auto const rfunc = env.index.resolve_func(env.ctx, funcName);
auto const rfunc = env.index.resolve_func(funcName);
if (!rfunc.mightCareAboutDynCalls()) {
return reduce(env, bc::PopC {}, bc::FCallFuncD { op.fca, funcName });
}
Expand Down
2 changes: 0 additions & 2 deletions hphp/hhbbc/interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ void default_dispatch(ISS&, const Bytecode&);
*/
bool optimize_builtin(ISS& env, const php::Func* func, const FCallArgs& fca);

bool handle_function_exists(ISS& env, const Type& name);

Optional<Type>
const_fold(ISS& env, uint32_t nArgs, uint32_t numExtraInputs,
const php::Func& phpFunc, bool variadicsPacked);
Expand Down

0 comments on commit 5ce4374

Please sign in to comment.