Enable HHIRInliningUseReachableCost by default, tweak inlining constants
[hiphop-php.git] / hphp / hhbbc / func-util.cpp
blob19bcec11262724af743e3cf689d32f93c1180a29
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/hhbbc/func-util.h"
18 #include "hphp/hhbbc/misc.h"
19 #include "hphp/hhbbc/representation.h"
21 #include "hphp/runtime/vm/func.h"
23 namespace HPHP { namespace HHBBC {
25 //////////////////////////////////////////////////////////////////////
27 const StaticString s_reified_generics_var("0ReifiedGenerics");
29 //////////////////////////////////////////////////////////////////////
31 uint32_t closure_num_use_vars(const php::Func* f) {
32 // Properties on the closure object are use vars.
33 return f->cls->properties.size();
36 bool is_pseudomain(const php::Func* f) {
37 return f->unit->pseudomain.get() == f;
40 bool is_volatile_local(const php::Func* func, LocalId lid) {
41 auto const& l = func->locals[lid];
42 if (!l.name) return false;
44 // Named pseudomain locals are bound to $GLOBALS.
45 if (is_pseudomain(func)) return true;
47 return (RuntimeOption::EnableArgsInBacktraces &&
48 l.name->same(s_reified_generics_var.get())) ||
49 l.name->same(s_86metadata.get());
52 SString memoize_impl_name(const php::Func* func) {
53 always_assert(func->isMemoizeWrapper);
54 return Func::genMemoizeImplName(func->name);
57 bool check_nargs_in_range(const php::Func* func, uint32_t nArgs) {
58 while (nArgs < func->dvEntries.size()) {
59 if (func->dvEntries[nArgs++] == NoBlockId) return false;
61 return true;
64 int dyn_call_error_level(const php::Func* func) {
65 if (!(func->attrs & AttrDynamicallyCallable) ||
66 RuntimeOption::EvalForbidDynamicCallsWithAttr) {
67 if (func->cls) {
68 if (func->attrs & AttrStatic)
69 return RuntimeOption::EvalForbidDynamicCallsToClsMeth;
70 else
71 return RuntimeOption::EvalForbidDynamicCallsToInstMeth;
73 else
74 return RuntimeOption::EvalForbidDynamicCallsToFunc;
76 return 0;
79 //////////////////////////////////////////////////////////////////////
81 namespace {
83 using ExnNode = php::ExnNode;
85 void copy_into(php::FuncBase* dst, const php::FuncBase& other) {
86 hphp_fast_map<ExnNode*, ExnNode*> processed;
88 BlockId delta = dst->blocks.size();
89 always_assert(!dst->exnNodes.size() || !other.exnNodes.size());
90 dst->exnNodes.reserve(dst->exnNodes.size() + other.exnNodes.size());
91 for (auto en : other.exnNodes) {
92 en.region.catchEntry += delta;
93 dst->exnNodes.push_back(std::move(en));
95 for (auto theirs : other.blocks) {
96 if (delta) {
97 auto const ours = theirs.mutate();
98 if (ours->fallthrough != NoBlockId) ours->fallthrough += delta;
99 if (ours->throwExit != NoBlockId) ours->throwExit += delta;
100 for (auto& bc : ours->hhbcs) {
101 // When merging functions (used for 86xints) we have to drop
102 // the src info, because it might reference a different unit
103 // (and as a generated function, the src info isn't very
104 // meaningful anyway).
105 bc.srcLoc = -1;
106 bc.forEachTarget([&] (BlockId& b) { b += delta; });
109 dst->blocks.push_back(std::move(theirs));
113 //////////////////////////////////////////////////////////////////////
117 //////////////////////////////////////////////////////////////////////
119 bool append_func(php::Func* dst, const php::Func& src) {
120 if (src.numIters || src.locals.size()) return false;
121 if (src.exnNodes.size() && dst->exnNodes.size()) return false;
123 bool ok = false;
124 for (auto& b : dst->blocks) {
125 if (b->hhbcs.back().op != Op::RetC) continue;
126 auto const blk = b.mutate();
127 blk->hhbcs.back() = bc::PopC {};
128 blk->fallthrough = dst->blocks.size();
129 ok = true;
131 if (!ok) return false;
132 copy_into(dst, src);
133 return true;
136 php::FuncBase::FuncBase(const FuncBase& other) {
137 copy_into(this, other);
139 assertx(!other.nativeInfo);
142 //////////////////////////////////////////////////////////////////////