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 +----------------------------------------------------------------------+
19 #include "hphp/runtime/base/rds.h"
20 #include "hphp/runtime/base/rds-util.h"
21 #include "hphp/runtime/base/tv-arith.h"
22 #include "hphp/runtime/base/tv-array-like.h"
23 #include "hphp/runtime/base/tv-conversions.h"
24 #include "hphp/runtime/base/tv-mutate.h"
25 #include "hphp/runtime/base/tv-variant.h"
26 #include "hphp/runtime/base/tv-refcount.h"
27 #include "hphp/runtime/base/type-string.h"
29 #include "hphp/runtime/vm/act-rec.h"
30 #include "hphp/runtime/vm/class.h"
31 #include "hphp/runtime/vm/class-meth-data-ref.h"
32 #include "hphp/runtime/vm/func.h"
33 #include "hphp/runtime/vm/iter.h"
34 #include "hphp/runtime/vm/name-value-table.h"
35 #include "hphp/runtime/vm/prologue-flags.h"
36 #include "hphp/runtime/vm/unit.h"
38 #include "hphp/runtime/vm/jit/jit-resume-addr.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.
60 void setopBody(tv_lval lhs
, SetOpOp op
, TypedValue
* rhs
) {
61 assertx(tvIsPlausible(*lhs
));
62 assertx(tvIsPlausible(*rhs
));
65 case SetOpOp::PlusEqual
: tvAddEq(lhs
, *rhs
); return;
66 case SetOpOp::MinusEqual
: tvSubEq(lhs
, *rhs
); return;
67 case SetOpOp::MulEqual
: tvMulEq(lhs
, *rhs
); return;
68 case SetOpOp::DivEqual
: tvDivEq(lhs
, *rhs
); return;
69 case SetOpOp::PowEqual
: tvPowEq(lhs
, *rhs
); return;
70 case SetOpOp::ModEqual
: tvModEq(lhs
, *rhs
); return;
71 case SetOpOp::ConcatEqual
: tvConcatEq(lhs
, *rhs
); return;
72 case SetOpOp::AndEqual
: tvBitAndEq(lhs
, *rhs
); return;
73 case SetOpOp::OrEqual
: tvBitOrEq(lhs
, *rhs
); return;
74 case SetOpOp::XorEqual
: tvBitXorEq(lhs
, *rhs
); return;
75 case SetOpOp::SlEqual
: tvShlEq(lhs
, *rhs
); return;
76 case SetOpOp::SrEqual
: tvShrEq(lhs
, *rhs
); return;
81 ///////////////////////////////////////////////////////////////////////////////
83 // Creates and initializes the global NamedValue table
84 void createGlobalNVTable();
85 // Collects the variables defined on the global NamedValue table
86 Array
getDefinedVariables();
88 ///////////////////////////////////////////////////////////////////////////////
91 * Returns true iff `ar` represents a frame on the VM eval stack or a Resumable
92 * object on the PHP heap.
94 * The `may_be_non_runtime` flag should be set if we aren't guaranteed to be
95 * running in a "Hack runtime" context---e.g., if we're in the JIT or an
96 * extension thread, etc. This function is pretty much guaranteed to return
97 * false if we're not in the runtime, but the caller might be runtime-agnostic.
99 bool isVMFrame(const ActRec
* ar
, bool may_be_non_runtime
= false);
101 ///////////////////////////////////////////////////////////////////////////////
103 void frame_free_locals_no_hook(ActRec
* fp
);
105 #define tvReturn(x) \
108 new (&val_) Variant(x); \
109 assertx(val_.m_type != KindOfUninit); \
113 Class
* arGetContextClass(const ActRec
* ar
);
115 ///////////////////////////////////////////////////////////////////////////////
117 // Used by extension functions that take a PHP "callback", since they need to
118 // figure out the callback context once and call it multiple times. (e.g.
119 // array_map, array_filter, ...)
127 constexpr size_t kNumIterCells
= sizeof(Iter
) / sizeof(TypedValue
);
128 constexpr size_t kNumActRecCells
= sizeof(ActRec
) / sizeof(TypedValue
);
130 ///////////////////////////////////////////////////////////////////////////////
133 * We pad all stack overflow checks by a small amount to allow for three
136 * - inlining functions without having to either do another stack
137 * check (or chase down prologues to smash checks to be bigger).
139 * - omitting stack overflow checks on leaf functions
141 * - delaying stack overflow checks on reentry
143 constexpr int kStackCheckReenterPadding
= 9;
146 int stackCheckPadding() {
147 return Cfg::Eval::StackCheckLeafPadding
+ kStackCheckReenterPadding
;
150 // Interpreter evaluation stack.
155 TypedValue
* m_base
; // Stack grows down, so m_base is beyond the end of
159 bool isAllocated() { return m_elms
!= nullptr; }
160 void* getStackLowAddress() const { return m_elms
; }
161 void* getStackHighAddress() const { return m_base
; }
162 bool isValidAddress(uintptr_t v
) {
163 return v
>= uintptr_t(m_elms
) && v
< uintptr_t(m_base
);
168 static const int sSurprisePageSize
;
169 static const unsigned sMinStackElms
;
170 static void ValidateStackSize();
174 std::string
toString(const ActRec
* fp
, int offset
,
175 std::string prefix
="") const;
177 bool wouldOverflow(int numCells
) const;
181 * topOfStackOffset --
183 * Accessors for the x64 translator. Do not play on or around.
189 static constexpr size_t topOfStackOffset() {
190 return offsetof(Stack
, m_top
);
193 static TypedValue
* anyFrameStackBase(const ActRec
* fp
);
194 static TypedValue
* frameStackBase(const ActRec
* fp
);
195 static TypedValue
* resumableStackBase(const ActRec
* fp
);
198 size_t count() const {
199 return ((uintptr_t)m_base
- (uintptr_t)m_top
) / sizeof(TypedValue
);
202 // Same as discard(), but meant to replace popC() iff the interpreter knows
203 // for certain that decrementing a refcount is unnecessary.
206 assertx(m_top
!= m_base
);
207 assertx(!isRefcountedType(m_top
->m_type
));
214 assertx(m_top
!= m_base
);
215 assertx(tvIsPlausible(*m_top
));
223 assertx(m_top
!= m_base
);
224 assertx(m_top
->m_type
== KindOfUninit
);
231 assertx(m_top
!= m_base
);
232 assertx(tvIsPlausible(*m_top
));
238 // popAR() should only be used to tear down a pre-live ActRec. Once
239 // an ActRec is live, it should be torn down using frame_free_locals()
240 // followed by discardAR() or ret().
243 assertx(m_top
!= m_base
);
244 ActRec
* ar
= (ActRec
*)m_top
;
245 if (ar
->func()->cls() && ar
->hasThis()) decRefObj(ar
->getThis());
251 assertx(m_top
!= m_base
);
253 for (int i
= 0; i
< kNumActRecCells
; ++i
) {
254 tvDebugTrash(m_top
+ i
);
257 m_top
+= kNumActRecCells
;
258 assertx((uintptr_t)m_top
<= (uintptr_t)m_base
);
263 m_top
+= kNumActRecCells
- 1;
264 assertx((uintptr_t)m_top
<= (uintptr_t)m_base
);
269 // Leave part of the activation on the stack, since the return value now
272 for (int i
= 0; i
< kNumActRecCells
- 1; ++i
) {
273 tvDebugTrash(m_top
+ i
);
276 m_top
+= kNumActRecCells
- 1;
277 assertx((uintptr_t)m_top
<= (uintptr_t)m_base
);
282 assertx(m_top
!= m_base
);
288 void ndiscard(size_t n
) {
289 assertx((uintptr_t)&m_top
[n
] <= (uintptr_t)m_base
);
291 for (int i
= 0; i
< n
; ++i
) {
292 tvDebugTrash(m_top
+ i
);
299 void trim(TypedValue
* c
) {
300 assertx(c
<= m_base
);
303 while (m_top
< c
) tvDebugTrash(m_top
++);
311 assertx(m_top
!= m_base
);
312 assertx(m_top
!= m_elms
);
313 TypedValue
* fr
= m_top
;
315 TypedValue
* to
= m_top
;
321 assertx(m_top
!= m_elms
);
323 tvWriteUninit(*m_top
);
328 assertx(m_top
!= m_elms
);
334 void pushNullUninit() {
335 assertx(m_top
!= m_elms
);
337 m_top
->m_data
.num
= 0;
338 m_top
->m_type
= KindOfUninit
;
341 template<DataType t
, class T
> void pushVal(T v
) {
342 assertx(m_top
!= m_elms
);
344 *m_top
= make_tv
<t
>(v
);
346 ALWAYS_INLINE
void pushBool(bool v
) { pushVal
<KindOfBoolean
>(v
); }
347 ALWAYS_INLINE
void pushInt(int64_t v
) { pushVal
<KindOfInt64
>(v
); }
348 ALWAYS_INLINE
void pushDouble(double v
) { pushVal
<KindOfDouble
>(v
); }
349 ALWAYS_INLINE
void pushClass(Class
* v
) { pushVal
<KindOfClass
>(v
); }
351 // This should only be called directly when the caller has
352 // already adjusted the refcount appropriately
354 void pushStringNoRc(StringData
* s
) {
355 assertx(m_top
!= m_elms
);
357 *m_top
= make_tv
<KindOfString
>(s
);
361 void pushStaticString(const StringData
* s
) {
362 assertx(s
->isStatic()); // No need to call s->incRefCount().
363 assertx(m_top
!= m_elms
);
365 *m_top
= make_tv
<KindOfPersistentString
>(s
);
369 void pushLazyClass(LazyClassData l
) {
370 assertx(m_top
!= m_elms
);
372 *m_top
= make_tv
<KindOfLazyClass
>(l
);
376 void pushEnumClassLabel(const StringData
* s
) {
377 assertx(s
->isStatic()); // No need to call s->incRefCount().
378 assertx(m_top
!= m_elms
);
380 *m_top
= make_tv
<KindOfEnumClassLabel
>(s
);
384 void pushArrayLikeNoRc(ArrayData
* a
) {
385 assertx(m_top
!= m_elms
);
387 *m_top
= make_array_like_tv(a
);
391 void pushVecNoRc(ArrayData
* a
) {
392 assertx(a
->isVecType());
393 assertx(m_top
!= m_elms
);
395 *m_top
= make_tv
<KindOfVec
>(a
);
399 void pushDictNoRc(ArrayData
* a
) {
400 assertx(a
->isDictType());
401 assertx(m_top
!= m_elms
);
403 *m_top
= make_tv
<KindOfDict
>(a
);
407 void pushKeysetNoRc(ArrayData
* a
) {
408 assertx(a
->isKeysetType());
409 assertx(m_top
!= m_elms
);
411 *m_top
= make_tv
<KindOfKeyset
>(a
);
415 void pushArrayLike(ArrayData
* a
) {
417 pushArrayLikeNoRc(a
);
422 void pushVec(ArrayData
* a
) {
429 void pushDict(ArrayData
* a
) {
436 void pushKeyset(ArrayData
* a
) {
443 void pushStaticArrayLike(const ArrayData
* a
) {
444 assertx(a
->isStatic()); // No need to call a->incRefCount().
445 assertx(m_top
!= m_elms
);
447 *m_top
= make_persistent_array_like_tv(const_cast<ArrayData
*>(a
));
451 void pushStaticVec(const ArrayData
* a
) {
452 assertx(a
->isStatic()); // No need to call a->incRefCount().
453 assertx(a
->isVecType());
454 assertx(m_top
!= m_elms
);
456 *m_top
= make_tv
<KindOfPersistentVec
>(a
);
460 void pushStaticDict(const ArrayData
* a
) {
461 assertx(a
->isStatic()); // No need to call a->incRefCount().
462 assertx(a
->isDictType());
463 assertx(m_top
!= m_elms
);
465 *m_top
= make_tv
<KindOfPersistentDict
>(a
);
469 void pushStaticKeyset(const ArrayData
* a
) {
470 assertx(a
->isStatic()); // No need to call a->incRefCount().
471 assertx(a
->isKeysetType());
472 assertx(m_top
!= m_elms
);
474 *m_top
= make_tv
<KindOfPersistentKeyset
>(a
);
477 // This should only be called directly when the caller has
478 // already adjusted the refcount appropriately
480 void pushObjectNoRc(ObjectData
* o
) {
481 assertx(m_top
!= m_elms
);
483 *m_top
= make_tv
<KindOfObject
>(o
);
487 void pushObject(ObjectData
* o
) {
493 void pushFunc(Func
* f
) {
495 *m_top
= make_tv
<KindOfFunc
>(f
);
499 void pushRFuncNoRc(RFuncData
* f
) {
501 *m_top
= make_tv
<KindOfRFunc
>(f
);
505 void pushRFunc(RFuncData
* f
) {
511 void pushClsMethNoRc(ClsMethDataRef clsMeth
) {
513 *m_top
= make_tv
<KindOfClsMeth
>(clsMeth
);
517 void pushRClsMethNoRc(RClsMethData
* clsMeth
) {
519 *m_top
= make_tv
<KindOfRClsMeth
>(clsMeth
);
523 void nalloc(size_t n
) {
524 assertx((uintptr_t)(m_top
- n
) <= (uintptr_t)m_base
);
529 TypedValue
* allocC() {
530 assertx(m_top
!= m_elms
);
532 return (TypedValue
*)m_top
;
536 TypedValue
* allocTV() {
537 assertx(m_top
!= m_elms
);
544 assertx((uintptr_t)(m_top
- kNumActRecCells
) >= (uintptr_t)m_elms
);
545 assertx(kNumActRecCells
* sizeof(TypedValue
) == sizeof(ActRec
));
546 m_top
-= kNumActRecCells
;
547 return (ActRec
*)m_top
;
552 assertx(kNumIterCells
* sizeof(TypedValue
) == sizeof(Iter
));
553 assertx((uintptr_t)(m_top
- kNumIterCells
) >= (uintptr_t)m_elms
);
554 m_top
-= kNumIterCells
;
558 void replaceC(const TypedValue c
) {
559 assertx(m_top
!= m_base
);
564 template <DataType DT
>
567 assertx(m_top
!= m_base
);
569 *m_top
= make_tv
<DT
>();
572 template <DataType DT
, typename T
>
574 void replaceC(T value
) {
575 assertx(m_top
!= m_base
);
577 *m_top
= make_tv
<DT
>(value
);
581 void replaceTV(const TypedValue
& tv
) {
582 assertx(m_top
!= m_base
);
587 template <DataType DT
>
590 assertx(m_top
!= m_base
);
592 *m_top
= make_tv
<DT
>();
595 template <DataType DT
, typename T
>
597 void replaceTV(T value
) {
598 assertx(m_top
!= m_base
);
600 *m_top
= make_tv
<DT
>(value
);
605 assertx(m_top
!= m_base
);
606 return tvAssertPlausible(m_top
);
610 TypedValue
* topTV() {
611 assertx(m_top
!= m_base
);
616 ActRec
* indA(size_t ind
) {
617 assertx(m_top
!= m_base
);
618 assertx(count() >= ind
+ kNumActRecCells
);
619 return (ActRec
*)&m_top
[ind
];
623 TypedValue
* indC(size_t ind
) {
624 assertx(m_top
!= m_base
);
625 return tvAssertPlausible(&m_top
[ind
]);
629 TypedValue
* indTV(size_t ind
) {
630 assertx(m_top
!= m_base
);
635 //////////////////////////////////////////////////////////////////////
637 void flush_evaluation_stack();
640 * Visit all the slots on a live eval stack, stopping when we reach
641 * the supplied activation record.
643 * The stack elements are visited from lower address to higher.
645 * This will not read the VM registers (pc, fp, sp), so it will
646 * perform the requested visitation independent of modifications to
647 * the VM stack or frame pointer.
649 template<class TV
, class TVFun
>
650 typename maybe_const
<TV
, TypedValue
>::type
651 visitStackElems(const ActRec
* const fp
, TV
* const stackTop
, TVFun tvFun
) {
652 const TypedValue
* const base
= Stack::anyFrameStackBase(fp
);
653 auto cursor
= stackTop
;
654 assertx(cursor
<= base
);
656 while (cursor
< base
) {
661 void resetCoverageCounters();
663 // Resolve a Static / Self / Parent class reference to a class.
664 Class
* specialClsRefToCls(SpecialClsRef ref
);
666 // The interpOne*() methods implement individual opcode handlers.
667 using InterpOneFunc
= jit::JitResumeAddr (*) (ActRec
*, TypedValue
*, Offset
);
668 extern InterpOneFunc interpOneEntryPoints
[];
670 void doFCall(PrologueFlags prologueFlags
, const Func
* func
,
671 uint32_t numArgsInclUnpack
, void* ctx
, jit::TCA retAddr
);
673 jit::JitResumeAddr
dispatchBB();
674 Array
getDefinedVariables(const ActRec
*);
677 * Start a new nested instance of VM either at the beginning of a function
678 * determined by the enterFnAr frame, or at the current vmpc() location.
680 * Execution finishes by either returning, awaiting or yielding from the top
681 * level frame, in which case vmfp()/vmpc() are set to nullptr, or by throwing
682 * an exception, which callers usually process via exception_handler().
684 void enterVMAtFunc(ActRec
* enterFnAr
, uint32_t numArgsInclUnpack
);
685 void enterVMAtCurPC();
686 uint32_t prepareUnpackArgs(const Func
* func
, uint32_t numArgs
,
687 bool checkInOutAnnot
);
689 ///////////////////////////////////////////////////////////////////////////////
693 #define incl_HPHP_VM_BYTECODE_INL_H_
694 #include "hphp/runtime/vm/bytecode-inl.h"
695 #undef incl_HPHP_VM_BYTECODE_INL_H_