2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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/runtime/vm/jit/ref-deps.h"
20 #include "hphp/runtime/vm/jit/normalized-instruction.h"
21 #include "hphp/runtime/vm/jit/translator-inline.h"
23 namespace HPHP
{ namespace jit
{
27 std::string
RefDeps::Record::pretty() const {
28 std::ostringstream out
;
30 for (size_t i
= 0; i
< m_mask
.size(); ++i
) {
31 out
<< (m_mask
[i
] ? "1" : "0");
34 for (size_t i
= 0; i
< m_vals
.size(); ++i
) {
35 out
<< (m_vals
[i
] ? "1" : "0");
40 void RefDeps::addDep(int entryArDelta
, unsigned argNum
, bool isRef
) {
41 if (m_arMap
.find(entryArDelta
) == m_arMap
.end()) {
42 m_arMap
[entryArDelta
] = Record();
44 Record
& r
= m_arMap
[entryArDelta
];
45 if (argNum
>= r
.m_mask
.size()) {
46 assertx(argNum
>= r
.m_vals
.size());
47 r
.m_mask
.resize(argNum
+ 1);
48 r
.m_vals
.resize(argNum
+ 1);
50 r
.m_mask
[argNum
] = true;
51 r
.m_vals
[argNum
] = isRef
;
55 ActRecState::pushFunc(const NormalizedInstruction
& inst
) {
56 assertx(isFPush(inst
.op()));
57 if (inst
.op() == OpFPushFuncD
|| inst
.op() == OpFPushFuncU
) {
58 const Unit
& unit
= *inst
.unit();
59 Id funcId
= inst
.imm
[1].u_SA
;
60 auto const& nep
= unit
.lookupNamedEntityPairId(funcId
);
61 auto const func
= Unit::lookupFunc(nep
.second
);
62 if (func
) func
->validate();
63 if (func
&& func
->isNameBindingImmutable(&unit
)) {
72 ActRecState::pushFuncD(const Func
* func
) {
73 TRACE(2, "ActRecState: pushStatic func %p(%s)\n", func
, func
->name()->data());
76 r
.m_state
= State::KNOWN
;
78 r
.m_entryArDelta
= InvalidEntryArDelta
;
79 m_arStack
.push_back(r
);
83 ActRecState::pushDynFunc() {
84 TRACE(2, "ActRecState: pushDynFunc\n");
86 r
.m_state
= State::UNKNOWABLE
;
87 r
.m_topFunc
= nullptr;
88 r
.m_entryArDelta
= InvalidEntryArDelta
;
89 m_arStack
.push_back(r
);
94 if (!m_arStack
.empty()) {
100 * checkByRef() returns true if the parameter specified by argNum is pass
101 * by reference, otherwise it returns false. This function may also throw an
102 * UnknownInputException if the reffiness cannot be determined.
104 * Note that the 'entryArDelta' parameter specifies the delta between sp at
105 * the beginning of the tracelet and ar.
108 ActRecState::checkByRef(int argNum
, int entryArDelta
, RefDeps
* refDeps
) {
109 FTRACE(2, "ActRecState: getting reffiness for arg {}, arDelta {}\n",
110 argNum
, entryArDelta
);
111 if (m_arStack
.empty()) {
112 // The ActRec in question was pushed before the beginning of the
113 // tracelet, so we can make a guess about parameter reffiness and
114 // record our assumptions about parameter reffiness as tracelet
116 const ActRec
* ar
= arFromSpOffset((ActRec
*)vmsp(), entryArDelta
);
118 r
.m_state
= State::GUESSABLE
;
119 r
.m_entryArDelta
= entryArDelta
;
120 ar
->m_func
->validate();
121 r
.m_topFunc
= ar
->m_func
;
122 m_arStack
.push_back(r
);
124 Record
& r
= m_arStack
.back();
125 if (r
.m_state
== State::UNKNOWABLE
) {
126 TRACE(2, "ActRecState: unknowable, throwing in the towel\n");
130 assertx(r
.m_topFunc
);
131 bool retval
= r
.m_topFunc
->byRef(argNum
);
132 if (r
.m_state
== State::GUESSABLE
) {
133 assertx(r
.m_entryArDelta
!= InvalidEntryArDelta
);
134 TRACE(2, "ActRecState: guessing arg%d -> %d\n", argNum
, retval
);
135 refDeps
->addDep(r
.m_entryArDelta
, argNum
, retval
);
141 ActRecState::knownFunc() {
142 if (currentState() != State::KNOWN
) return nullptr;
143 assertx(!m_arStack
.empty());
144 return m_arStack
.back().m_topFunc
;
148 ActRecState::currentState() {
149 if (m_arStack
.empty()) return State::GUESSABLE
;
150 return m_arStack
.back().m_state
;