Handle magic calls to unknown methods in interpreter
[hiphop-php.git] / hphp / runtime / vm / jit / ir-instruction-inl.h
blobd9b0236ebae7856dea7dcd1df7301087e62a2eb0
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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/edge.h"
19 #include <utility>
21 namespace HPHP { namespace jit {
22 ///////////////////////////////////////////////////////////////////////////////
24 inline IRInstruction::IRInstruction(Opcode op,
25 BCContext bcctx,
26 Edge* edges,
27 uint32_t numSrcs,
28 SSATmp** srcs)
29 : m_op(op)
30 , m_iroff(bcctx.iroff)
31 , m_numSrcs(numSrcs)
32 , m_numDsts(0)
33 , m_hasTypeParam{false}
34 , m_marker(bcctx.marker)
35 , m_srcs(srcs)
36 , m_dest(nullptr)
37 , m_edges(edges)
39 if (op != DefConst) {
40 // DefConst is the only opcode that's allowed to not have a marker, since
41 // it's not part of the instruction stream.
42 assertx(m_marker.valid());
46 ///////////////////////////////////////////////////////////////////////////////
48 inline bool IRInstruction::hasDst() const {
49 return opcodeHasFlags(op(), HasDest);
52 inline bool IRInstruction::naryDst() const {
53 return opcodeHasFlags(op(), NaryDest);
56 inline bool IRInstruction::consumesReferences() const {
57 return opcodeHasFlags(op(), ConsumesRC);
60 inline bool IRInstruction::mayRaiseError() const {
61 return opcodeMayRaise(op());
64 inline bool IRInstruction::isTerminal() const {
65 return opcodeHasFlags(op(), Terminal);
68 inline bool IRInstruction::hasEdges() const {
69 return jit::hasEdges(op());
72 inline bool IRInstruction::isPassthrough() const {
73 return opcodeHasFlags(op(), Passthrough);
76 inline bool IRInstruction::producesReference() const {
77 return opcodeHasFlags(op(), ProducesRC);
80 inline SSATmp* IRInstruction::getPassthroughValue() const {
81 assertx(isPassthrough());
82 assertx(is(CheckType, CheckVArray, CheckDArray,
83 AssertType, AssertNonNull, Mov,
84 ConvPtrToLval));
85 return src(0);
88 ///////////////////////////////////////////////////////////////////////////////
90 inline uint32_t IRInstruction::id() const {
91 assertx(m_id != kTransient);
92 return m_id;
95 inline bool IRInstruction::isTransient() const {
96 return m_id == kTransient;
99 inline uint16_t IRInstruction::iroff() const {
100 return m_iroff;
103 template<typename... Args>
104 bool IRInstruction::is(Opcode op, Args&&... args) const {
105 return m_op == op || is(std::forward<Args>(args)...);
108 inline bool IRInstruction::is() const {
109 return false;
112 inline Opcode IRInstruction::op() const {
113 return m_op;
116 inline const BCMarker& IRInstruction::marker() const {
117 return m_marker;
120 inline BCMarker& IRInstruction::marker() {
121 return m_marker;
124 inline BCContext IRInstruction::bcctx() const {
125 return BCContext { m_marker, m_iroff };
128 inline const Func* IRInstruction::func() const {
129 return m_marker.hasFunc() ? m_marker.func() : nullptr;
132 inline const Class* IRInstruction::ctx() const {
133 return m_marker.hasFunc() ? m_marker.func()->cls() : nullptr;
136 inline bool IRInstruction::hasTypeParam() const { return m_hasTypeParam; }
138 inline Type IRInstruction::typeParam() const {
139 assertx(m_hasTypeParam);
140 return m_typeParam;
143 inline void IRInstruction::setTypeParam(Type t) {
144 m_hasTypeParam = true;
145 m_typeParam = t;
148 ///////////////////////////////////////////////////////////////////////////////
150 inline void IRInstruction::initializeSrcs(uint32_t numSrcs, SSATmp** srcs) {
151 assertx(!m_srcs && !m_numSrcs);
152 m_numSrcs = numSrcs;
153 m_srcs = srcs;
156 inline uint32_t IRInstruction::numSrcs() const {
157 return m_numSrcs;
160 inline uint32_t IRInstruction::numDsts() const {
161 return m_numDsts;
164 inline SSATmp* IRInstruction::src(uint32_t i) const {
165 always_assert_flog(i < numSrcs(), "src {} out of range in {}", i, toString());
166 return m_srcs[i];
169 inline SSATmp* IRInstruction::dst() const {
170 assertx(!naryDst());
171 return m_dest;
174 inline folly::Range<SSATmp**> IRInstruction::srcs() const {
175 return folly::Range<SSATmp**>(m_srcs, m_numSrcs);
178 inline folly::Range<SSATmp**> IRInstruction::dsts() {
179 assertx(naryDst() || m_numDsts <= 1);
180 if (hasDst()) return folly::Range<SSATmp**>(&m_dest, m_numDsts);
181 return folly::Range<SSATmp**>(m_dsts, m_numDsts);
184 inline void IRInstruction::setSrc(uint32_t i, SSATmp* newSrc) {
185 always_assert(i < numSrcs());
186 m_srcs[i] = newSrc;
189 inline void IRInstruction::setSrcs(uint32_t numSrcs, SSATmp** newSrcs) {
190 m_numSrcs = numSrcs;
191 m_srcs = newSrcs;
194 inline void IRInstruction::deleteSrc(uint32_t i) {
195 always_assert(i < numSrcs());
196 std::copy(m_srcs + i + 1, m_srcs + m_numSrcs, m_srcs + i);
197 --m_numSrcs;
200 inline void IRInstruction::setDst(SSATmp* newDst) {
201 assertx(hasDst());
202 m_dest = newDst;
203 m_numDsts = newDst ? 1 : 0;
206 inline void IRInstruction::setDsts(uint32_t numDsts, SSATmp** newDsts) {
207 assertx(naryDst());
208 m_numDsts = numDsts;
209 m_dsts = newDsts;
212 inline void IRInstruction::deleteDst(uint32_t i) {
213 always_assert(i < numDsts());
214 assertx(naryDst());
215 std::copy(m_dsts + i + 1, m_dsts + m_numDsts, m_dsts + i);
216 --m_numDsts;
219 ///////////////////////////////////////////////////////////////////////////////
221 inline bool IRInstruction::hasExtra() const {
222 return m_extra;
225 template<Opcode opc>
226 const typename IRExtraDataType<opc>::type* IRInstruction::extra() const {
227 assertx(opc == op() && "ExtraData type error");
228 assertx(m_extra != nullptr);
229 return static_cast<typename IRExtraDataType<opc>::type*>(m_extra);
232 template<Opcode opc>
233 typename IRExtraDataType<opc>::type* IRInstruction::extra() {
234 assertx(opc == op() && "ExtraData type error");
235 return static_cast<typename IRExtraDataType<opc>::type*>(m_extra);
238 template<typename T>
239 const T* IRInstruction::extra() const {
240 if (debug) assert_opcode_extra<T>(op());
241 return static_cast<const T*>(m_extra);
244 template<typename T>
245 T* IRInstruction::extra() {
246 if (debug) assert_opcode_extra<T>(op());
247 return static_cast<T*>(m_extra);
250 inline const IRExtraData* IRInstruction::rawExtra() const {
251 return m_extra;
254 inline void IRInstruction::setExtra(IRExtraData* data) {
255 assertx(!m_extra);
256 m_extra = data;
259 inline void IRInstruction::clearExtra() {
260 m_extra = nullptr;
263 ///////////////////////////////////////////////////////////////////////////////
265 inline Block* IRInstruction::block() const {
266 return m_block;
269 inline void IRInstruction::setBlock(Block* b) {
270 m_block = b;
273 inline Block* IRInstruction::next() const {
274 return succ(0);
277 inline Edge* IRInstruction::nextEdge() {
278 return succEdge(0);
281 inline void IRInstruction::setNext(Block* b) {
282 return setSucc(0, b);
285 inline Block* IRInstruction::taken() const {
286 return succ(1);
289 inline Edge* IRInstruction::takenEdge() {
290 return succEdge(1);
293 inline void IRInstruction::setTaken(Block* b) {
294 return setSucc(1, b);
297 inline bool IRInstruction::isControlFlow() const {
298 return bool(taken());
301 inline bool IRInstruction::isBlockEnd() const {
302 return taken() || isTerminal();
305 inline Block* IRInstruction::succ(int i) const {
306 assertx(!m_edges || hasEdges());
307 return m_edges ? m_edges[i].to() : nullptr;
310 inline Edge* IRInstruction::succEdge(int i) {
311 assertx(!m_edges || hasEdges());
312 return m_edges && m_edges[i].to() ? &m_edges[i] : nullptr;
315 inline void IRInstruction::setSucc(int i, Block* b) {
316 if (hasEdges()) {
317 if (isTransient()) m_edges[i].setTransientTo(b);
318 else m_edges[i].setTo(b);
319 } else {
320 assertx(!b && !m_edges);
324 inline void IRInstruction::clearEdges() {
325 setSucc(0, nullptr);
326 setSucc(1, nullptr);
327 m_edges = nullptr;
330 ///////////////////////////////////////////////////////////////////////////////