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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_BYTECODE_H_
18 #define incl_HPHP_VM_BYTECODE_H_
20 #include "hphp/runtime/base/array-iterator.h"
21 #include "hphp/runtime/base/rds.h"
22 #include "hphp/runtime/base/rds-util.h"
23 #include "hphp/runtime/base/record-array.h"
24 #include "hphp/runtime/base/record-data.h"
25 #include "hphp/runtime/base/tv-arith.h"
26 #include "hphp/runtime/base/tv-conversions.h"
27 #include "hphp/runtime/base/tv-mutate.h"
28 #include "hphp/runtime/base/tv-variant.h"
29 #include "hphp/runtime/base/tv-refcount.h"
31 #include "hphp/runtime/vm/act-rec.h"
32 #include "hphp/runtime/vm/call-flags.h"
33 #include "hphp/runtime/vm/class.h"
34 #include "hphp/runtime/vm/class-meth-data-ref.h"
35 #include "hphp/runtime/vm/func.h"
36 #include "hphp/runtime/vm/name-value-table.h"
37 #include "hphp/runtime/vm/unit.h"
39 #include "hphp/runtime/vm/jit/types.h"
41 #include "hphp/util/arena.h"
42 #include "hphp/util/type-traits.h"
44 #include <type_traits>
47 ///////////////////////////////////////////////////////////////////////////////
53 ///////////////////////////////////////////////////////////////////////////////
55 #define EVAL_FILENAME_SUFFIX ") : eval()'d code"
57 // perform the set(op) operation on lhs & rhs, leaving the result in lhs.
58 // The old value of lhs is decrefed. Caller must call tvToCell() if lhs or
59 // rhs might be a ref.
61 void setopBody(tv_lval lhs
, SetOpOp op
, Cell
* rhs
) {
62 assertx(cellIsPlausible(*lhs
));
63 assertx(cellIsPlausible(*rhs
));
66 case SetOpOp::PlusEqual
: cellAddEq(lhs
, *rhs
); return;
67 case SetOpOp::MinusEqual
: cellSubEq(lhs
, *rhs
); return;
68 case SetOpOp::MulEqual
: cellMulEq(lhs
, *rhs
); return;
69 case SetOpOp::DivEqual
: cellDivEq(lhs
, *rhs
); return;
70 case SetOpOp::PowEqual
: cellPowEq(lhs
, *rhs
); return;
71 case SetOpOp::ModEqual
: cellModEq(lhs
, *rhs
); return;
72 case SetOpOp::ConcatEqual
: cellConcatEq(lhs
, *rhs
); return;
73 case SetOpOp::AndEqual
: cellBitAndEq(lhs
, *rhs
); return;
74 case SetOpOp::OrEqual
: cellBitOrEq(lhs
, *rhs
); return;
75 case SetOpOp::XorEqual
: cellBitXorEq(lhs
, *rhs
); return;
76 case SetOpOp::SlEqual
: cellShlEq(lhs
, *rhs
); return;
77 case SetOpOp::SrEqual
: cellShrEq(lhs
, *rhs
); return;
78 case SetOpOp::PlusEqualO
: cellAddEqO(lhs
, *rhs
); return;
79 case SetOpOp::MinusEqualO
: cellSubEqO(lhs
, *rhs
); return;
80 case SetOpOp::MulEqualO
: cellMulEqO(lhs
, *rhs
); return;
85 ///////////////////////////////////////////////////////////////////////////////
88 * Variable environment.
90 * A variable environment consists of the locals for the current function
91 * (either pseudo-main, global function, or method), plus any variables that
92 * are dynamically defined.
94 * Logically, a global function or method starts off with a variable
95 * environment that contains only its locals, but a pseudo-main is handed
96 * its caller's existing variable environment. Generally, however, we don't
97 * create a variable environment for global functions or methods until it
98 * actually needs one (i.e. if it is about to include a pseudo-main, or if
99 * it uses dynamic variable lookups).
101 * Named locals always appear in the expected place on the stack, even after
102 * a VarEnv is attached. Internally uses a NameValueTable to hook up names to
103 * the local locations.
107 NameValueTable m_nvTable
;
113 explicit VarEnv(ActRec
* fp
);
114 explicit VarEnv(const VarEnv
* varEnv
, ActRec
* fp
);
117 // Free the VarEnv and locals for the given frame
118 // which must have a VarEnv
119 static void deallocate(ActRec
* fp
);
121 // Allocates a local VarEnv and attaches it to the existing FP.
122 static VarEnv
* createLocal(ActRec
* fp
);
124 // Allocate a global VarEnv. Initially not attached to any frame.
125 static void createGlobal();
127 VarEnv
* clone(ActRec
* fp
) const;
129 void suspend(const ActRec
* oldFP
, ActRec
* newFP
);
130 void enterFP(ActRec
* oldFP
, ActRec
* newFP
);
131 void exitFP(ActRec
* fp
);
133 void set(const StringData
* name
, tv_rval tv
);
134 TypedValue
* lookup(const StringData
* name
);
135 TypedValue
* lookupAdd(const StringData
* name
);
136 bool unset(const StringData
* name
);
138 Array
getDefinedVariables() const;
140 // Used for save/store m_cfp for debugger
141 ActRec
* getFP() const { return m_nvTable
.getFP(); }
142 bool isGlobalScope() const { return m_global
; }
145 ///////////////////////////////////////////////////////////////////////////////
148 * Returns true iff `ar` represents a frame on the VM eval stack or a Resumable
149 * object on the PHP heap.
151 * The `may_be_non_runtime` flag should be set if we aren't guaranteed to be
152 * running in a "Hack runtime" context---e.g., if we're in the JIT or an
153 * extension thread, etc. This function is pretty much guaranteed to return
154 * false if we're not in the runtime, but the caller might be runtime-agnostic.
156 bool isVMFrame(const ActRec
* ar
, bool may_be_non_runtime
= false);
159 * Returns true iff the given address is one of the special debugger return
162 bool isDebuggerReturnHelper(void* addr
);
165 * If ar->m_savedRip points somewhere in the TC that is not a return helper,
166 * change it to point to an appropriate return helper. The two different
167 * versions are for the different needs of the C++ unwinder and debugger hooks,
170 void unwindPreventReturnToTC(ActRec
* ar
);
171 void debuggerPreventReturnToTC(ActRec
* ar
);
174 * Call debuggerPreventReturnToTC() on all live VM frames in this thread.
176 void debuggerPreventReturnsToTC();
178 ///////////////////////////////////////////////////////////////////////////////
180 void frame_free_locals_no_hook(ActRec
* fp
);
182 #define tvReturn(x) \
185 new (&val_) Variant(x); \
186 assertx(!isRefType(val_.m_type) && val_.m_type != KindOfUninit); \
190 Class
* arGetContextClass(const ActRec
* ar
);
192 ///////////////////////////////////////////////////////////////////////////////
194 // Used by extension functions that take a PHP "callback", since they need to
195 // figure out the callback context once and call it multiple times. (e.g.
196 // array_map, array_filter, ...)
205 constexpr size_t kNumIterCells
= sizeof(Iter
) / sizeof(Cell
);
206 constexpr size_t kNumActRecCells
= sizeof(ActRec
) / sizeof(Cell
);
208 ///////////////////////////////////////////////////////////////////////////////
211 * We pad all stack overflow checks by a small amount to allow for three
214 * - inlining functions without having to either do another stack
215 * check (or chase down prologues to smash checks to be bigger).
217 * - omitting stack overflow checks on leaf functions
219 * - delaying stack overflow checks on reentry
221 constexpr int kStackCheckLeafPadding
= 100;
222 constexpr int kStackCheckReenterPadding
= 9;
223 constexpr int kStackCheckPadding
= kStackCheckLeafPadding
+
224 kStackCheckReenterPadding
;
226 // Interpreter evaluation stack.
231 TypedValue
* m_base
; // Stack grows down, so m_base is beyond the end of
235 bool isAllocated() { return m_elms
!= nullptr; }
236 void* getStackLowAddress() const { return m_elms
; }
237 void* getStackHighAddress() const { return m_base
; }
238 bool isValidAddress(uintptr_t v
) {
239 return v
>= uintptr_t(m_elms
) && v
< uintptr_t(m_base
);
244 static const int sSurprisePageSize
;
245 static const unsigned sMinStackElms
;
246 static void ValidateStackSize();
250 std::string
toString(const ActRec
* fp
, int offset
,
251 std::string prefix
="") const;
253 bool wouldOverflow(int numCells
) const;
257 * topOfStackOffset --
259 * Accessors for the x64 translator. Do not play on or around.
265 static constexpr size_t topOfStackOffset() {
266 return offsetof(Stack
, m_top
);
269 static TypedValue
* anyFrameStackBase(const ActRec
* fp
);
270 static TypedValue
* frameStackBase(const ActRec
* fp
);
271 static TypedValue
* resumableStackBase(const ActRec
* fp
);
274 size_t count() const {
275 return ((uintptr_t)m_base
- (uintptr_t)m_top
) / sizeof(TypedValue
);
278 // Same as discard(), but meant to replace popC() iff the interpreter knows
279 // for certain that decrementing a refcount is unnecessary.
282 assertx(m_top
!= m_base
);
283 assertx(!isRefcountedType(m_top
->m_type
));
290 assertx(m_top
!= m_base
);
291 assertx(cellIsPlausible(*m_top
));
299 assertx(m_top
!= m_base
);
300 assertx(refIsPlausible(*m_top
));
308 assertx(m_top
!= m_base
);
309 assertx(m_top
->m_type
== KindOfUninit
);
316 assertx(m_top
!= m_base
);
317 assertx(tvIsPlausible(*m_top
));
323 // popAR() should only be used to tear down a pre-live ActRec. Once
324 // an ActRec is live, it should be torn down using frame_free_locals()
325 // followed by discardAR() or ret().
328 assertx(m_top
!= m_base
);
329 ActRec
* ar
= (ActRec
*)m_top
;
330 if (ar
->func()->cls() && ar
->hasThis()) decRefObj(ar
->getThis());
331 if (ar
->magicDispatch()) {
332 decRefStr(ar
->getInvName());
339 assertx(m_top
!= m_base
);
341 for (int i
= 0; i
< kNumActRecCells
; ++i
) {
342 tvDebugTrash(m_top
+ i
);
345 m_top
+= kNumActRecCells
;
346 assertx((uintptr_t)m_top
<= (uintptr_t)m_base
);
351 // Leave part of the activation on the stack, since the return value now
354 for (int i
= 0; i
< kNumActRecCells
- 1; ++i
) {
355 tvDebugTrash(m_top
+ i
);
358 m_top
+= kNumActRecCells
- 1;
359 assertx((uintptr_t)m_top
<= (uintptr_t)m_base
);
364 assertx(m_top
!= m_base
);
370 void ndiscard(size_t n
) {
371 assertx((uintptr_t)&m_top
[n
] <= (uintptr_t)m_base
);
373 for (int i
= 0; i
< n
; ++i
) {
374 tvDebugTrash(m_top
+ i
);
382 assertx(c
<= m_base
);
385 while (m_top
< c
) tvDebugTrash(m_top
++);
393 assertx(m_top
!= m_base
);
394 assertx(m_top
!= m_elms
);
395 assertx(!isRefType(m_top
->m_type
));
404 assertx(m_top
!= m_elms
);
406 tvWriteUninit(*m_top
);
411 assertx(m_top
!= m_elms
);
417 void pushNullUninit() {
418 assertx(m_top
!= m_elms
);
420 m_top
->m_data
.num
= 0;
421 m_top
->m_type
= KindOfUninit
;
424 template<DataType t
, class T
> void pushVal(T v
) {
425 assertx(m_top
!= m_elms
);
427 *m_top
= make_tv
<t
>(v
);
429 ALWAYS_INLINE
void pushBool(bool v
) { pushVal
<KindOfBoolean
>(v
); }
430 ALWAYS_INLINE
void pushInt(int64_t v
) { pushVal
<KindOfInt64
>(v
); }
431 ALWAYS_INLINE
void pushDouble(double v
) { pushVal
<KindOfDouble
>(v
); }
432 ALWAYS_INLINE
void pushClass(Class
* v
) { pushVal
<KindOfClass
>(v
); }
434 // This should only be called directly when the caller has
435 // already adjusted the refcount appropriately
437 void pushStringNoRc(StringData
* s
) {
438 assertx(m_top
!= m_elms
);
440 *m_top
= make_tv
<KindOfString
>(s
);
444 void pushStaticString(const StringData
* s
) {
445 assertx(s
->isStatic()); // No need to call s->incRefCount().
446 assertx(m_top
!= m_elms
);
448 *m_top
= make_tv
<KindOfPersistentString
>(s
);
451 // These should only be called directly when the caller has
452 // already adjusted the refcount appropriately
454 void pushArrayNoRc(ArrayData
* a
) {
455 assertx(a
->isPHPArray());
456 assertx(m_top
!= m_elms
);
458 *m_top
= make_tv
<KindOfArray
>(a
);
462 void pushVecNoRc(ArrayData
* a
) {
463 assertx(a
->isVecArray());
464 assertx(m_top
!= m_elms
);
466 *m_top
= make_tv
<KindOfVec
>(a
);
470 void pushDictNoRc(ArrayData
* a
) {
471 assertx(a
->isDict());
472 assertx(m_top
!= m_elms
);
474 *m_top
= make_tv
<KindOfDict
>(a
);
478 void pushKeysetNoRc(ArrayData
* a
) {
479 assertx(a
->isKeyset());
480 assertx(m_top
!= m_elms
);
482 *m_top
= make_tv
<KindOfKeyset
>(a
);
486 void pushArray(ArrayData
* a
) {
493 void pushVec(ArrayData
* a
) {
500 void pushDict(ArrayData
* a
) {
507 void pushKeyset(ArrayData
* a
) {
514 void pushStaticArray(const ArrayData
* a
) {
515 assertx(a
->isStatic()); // No need to call a->incRefCount().
516 assertx(a
->isPHPArray());
517 assertx(m_top
!= m_elms
);
519 *m_top
= make_tv
<KindOfPersistentArray
>(a
);
523 void pushStaticVec(const ArrayData
* a
) {
524 assertx(a
->isStatic()); // No need to call a->incRefCount().
525 assertx(a
->isVecArray());
526 assertx(m_top
!= m_elms
);
528 *m_top
= make_tv
<KindOfPersistentVec
>(a
);
532 void pushStaticDict(const ArrayData
* a
) {
533 assertx(a
->isStatic()); // No need to call a->incRefCount().
534 assertx(a
->isDict());
535 assertx(m_top
!= m_elms
);
537 *m_top
= make_tv
<KindOfPersistentDict
>(a
);
541 void pushStaticKeyset(const ArrayData
* a
) {
542 assertx(a
->isStatic()); // No need to call a->incRefCount().
543 assertx(a
->isKeyset());
544 assertx(m_top
!= m_elms
);
546 *m_top
= make_tv
<KindOfPersistentKeyset
>(a
);
549 // This should only be called directly when the caller has
550 // already adjusted the refcount appropriately
552 void pushObjectNoRc(ObjectData
* o
) {
553 assertx(m_top
!= m_elms
);
555 *m_top
= make_tv
<KindOfObject
>(o
);
559 void pushObject(ObjectData
* o
) {
565 void pushRecordNoRc(RecordData
* r
) {
566 assertx(m_top
!= m_elms
);
568 *m_top
= make_tv
<KindOfRecord
>(r
);
572 void pushRecordArrayNoRc(RecordArray
* r
) {
573 assertx(m_top
!= m_elms
);
575 *m_top
= make_tv
<KindOfArray
>(r
);
579 void pushFunc(Func
* f
) {
581 *m_top
= make_tv
<KindOfFunc
>(f
);
585 void pushClsMethNoRc(ClsMethDataRef clsMeth
) {
587 *m_top
= make_tv
<KindOfClsMeth
>(clsMeth
);
591 void nalloc(size_t n
) {
592 assertx((uintptr_t)(m_top
- n
) <= (uintptr_t)m_base
);
598 assertx(m_top
!= m_elms
);
605 assertx(m_top
!= m_elms
);
611 TypedValue
* allocTV() {
612 assertx(m_top
!= m_elms
);
619 assertx((uintptr_t)(m_top
- kNumActRecCells
) >= (uintptr_t)m_elms
);
620 assertx(kNumActRecCells
* sizeof(Cell
) == sizeof(ActRec
));
621 m_top
-= kNumActRecCells
;
622 return (ActRec
*)m_top
;
627 assertx(kNumIterCells
* sizeof(Cell
) == sizeof(Iter
));
628 assertx((uintptr_t)(m_top
- kNumIterCells
) >= (uintptr_t)m_elms
);
629 m_top
-= kNumIterCells
;
633 void replaceC(const Cell c
) {
634 assertx(m_top
!= m_base
);
635 assertx(!isRefType(m_top
->m_type
));
640 template <DataType DT
>
643 assertx(m_top
!= m_base
);
644 assertx(!isRefType(m_top
->m_type
));
646 *m_top
= make_tv
<DT
>();
649 template <DataType DT
, typename T
>
651 void replaceC(T value
) {
652 assertx(m_top
!= m_base
);
653 assertx(!isRefType(m_top
->m_type
));
655 *m_top
= make_tv
<DT
>(value
);
659 void replaceTV(const TypedValue
& tv
) {
660 assertx(m_top
!= m_base
);
665 template <DataType DT
>
668 assertx(m_top
!= m_base
);
670 *m_top
= make_tv
<DT
>();
673 template <DataType DT
, typename T
>
675 void replaceTV(T value
) {
676 assertx(m_top
!= m_base
);
678 *m_top
= make_tv
<DT
>(value
);
683 assertx(m_top
!= m_base
);
684 return tvAssertCell(m_top
);
689 assertx(m_top
!= m_base
);
690 assertx(isRefType(m_top
->m_type
));
695 TypedValue
* topTV() {
696 assertx(m_top
!= m_base
);
701 ActRec
* indA(size_t ind
) {
702 assertx(m_top
!= m_base
);
703 assertx(count() > ind
+ kNumActRecCells
);
704 return (ActRec
*)&m_top
[ind
];
708 Cell
* indC(size_t ind
) {
709 assertx(m_top
!= m_base
);
710 assertx(!isRefType(m_top
[ind
].m_type
));
711 return tvAssertCell(&m_top
[ind
]);
715 TypedValue
* indTV(size_t ind
) {
716 assertx(m_top
!= m_base
);
721 //////////////////////////////////////////////////////////////////////
724 * Visit all the slots on a live eval stack, stopping when we reach
725 * the supplied activation record.
727 * The stack elements are visited from lower address to higher.
729 * This will not read the VM registers (pc, fp, sp), so it will
730 * perform the requested visitation independent of modifications to
731 * the VM stack or frame pointer.
733 template<class TV
, class TVFun
>
734 typename maybe_const
<TV
, TypedValue
>::type
735 visitStackElems(const ActRec
* const fp
, TV
* const stackTop
, TVFun tvFun
) {
736 const TypedValue
* const base
= Stack::anyFrameStackBase(fp
);
737 auto cursor
= stackTop
;
738 assertx(cursor
<= base
);
740 while (cursor
< base
) {
745 void resetCoverageCounters();
747 // The interpOne*() methods implement individual opcode handlers.
748 using InterpOneFunc
= jit::TCA (*) (ActRec
*, TypedValue
*, Offset
);
749 extern InterpOneFunc interpOneEntryPoints
[];
751 bool doFCallUnpackTC(PC origpc
, int32_t numInputs
, CallFlags callFlags
, void*);
752 bool doFCall(ActRec
* ar
, uint32_t numArgs
, bool hasUnpack
, CallFlags callFlags
);
753 jit::TCA
dispatchBB();
754 void pushFrameSlots(const Func
* func
, int nparams
= 0);
755 Array
getDefinedVariables(const ActRec
*);
757 enum class StackArgsState
{ // tells prepareFuncEntry how much work to do
758 // the stack may contain more arguments than the function expects
760 // the stack has already been trimmed of any extra arguments, which
761 // have been teleported away into a variadic param
764 void enterVMAtPseudoMain(ActRec
* enterFnAr
, VarEnv
* varEnv
);
765 void enterVMAtFunc(ActRec
* enterFnAr
, StackArgsState stk
, Array
&& generics
,
766 bool hasInOut
, bool allowDynCallNoPointer
);
767 void enterVMAtCurPC();
768 void prepareArrayArgs(ActRec
* ar
, const Cell args
, Stack
& stack
,
769 int nregular
, bool checkRefAnnot
);
771 ///////////////////////////////////////////////////////////////////////////////