2 +----------------------------------------------------------------------+
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;
64 int dyn_call_error_level(const php::Func
* func
) {
65 if (!(func
->attrs
& AttrDynamicallyCallable
) ||
66 RuntimeOption::EvalForbidDynamicCallsWithAttr
) {
68 if (func
->attrs
& AttrStatic
)
69 return RuntimeOption::EvalForbidDynamicCallsToClsMeth
;
71 return RuntimeOption::EvalForbidDynamicCallsToInstMeth
;
74 return RuntimeOption::EvalForbidDynamicCallsToFunc
;
79 //////////////////////////////////////////////////////////////////////
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
) {
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).
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;
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();
131 if (!ok
) return false;
136 php::FuncBase::FuncBase(const FuncBase
& other
) {
137 copy_into(this, other
);
139 assertx(!other
.nativeInfo
);
142 //////////////////////////////////////////////////////////////////////