Do not spill ActRec in catches of inlined builtins
[hiphop-php.git] / hphp / runtime / vm / bytecode.h
blob41b8b38ddf8bedb3ec988d7fe02b0e92b1170b90
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 #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-data.h"
24 #include "hphp/runtime/base/tv-arith.h"
25 #include "hphp/runtime/base/tv-conversions.h"
26 #include "hphp/runtime/base/tv-mutate.h"
27 #include "hphp/runtime/base/tv-variant.h"
28 #include "hphp/runtime/base/tv-refcount.h"
30 #include "hphp/runtime/vm/act-rec.h"
31 #include "hphp/runtime/vm/class.h"
32 #include "hphp/runtime/vm/class-meth-data-ref.h"
33 #include "hphp/runtime/vm/cls-ref.h"
34 #include "hphp/runtime/vm/func.h"
35 #include "hphp/runtime/vm/name-value-table.h"
36 #include "hphp/runtime/vm/unit.h"
38 #include "hphp/runtime/vm/jit/types.h"
40 #include "hphp/util/arena.h"
41 #include "hphp/util/type-traits.h"
43 #include <type_traits>
45 namespace HPHP {
46 ///////////////////////////////////////////////////////////////////////////////
48 struct ActRec;
49 struct Func;
50 struct Resumable;
52 ///////////////////////////////////////////////////////////////////////////////
54 #define EVAL_FILENAME_SUFFIX ") : eval()'d code"
56 // perform the set(op) operation on lhs & rhs, leaving the result in lhs.
57 // The old value of lhs is decrefed. Caller must call tvToCell() if lhs or
58 // rhs might be a ref.
59 ALWAYS_INLINE
60 void setopBody(tv_lval lhs, SetOpOp op, Cell* rhs) {
61 assertx(cellIsPlausible(*lhs));
62 assertx(cellIsPlausible(*rhs));
64 switch (op) {
65 case SetOpOp::PlusEqual: cellAddEq(lhs, *rhs); return;
66 case SetOpOp::MinusEqual: cellSubEq(lhs, *rhs); return;
67 case SetOpOp::MulEqual: cellMulEq(lhs, *rhs); return;
68 case SetOpOp::DivEqual: cellDivEq(lhs, *rhs); return;
69 case SetOpOp::PowEqual: cellPowEq(lhs, *rhs); return;
70 case SetOpOp::ModEqual: cellModEq(lhs, *rhs); return;
71 case SetOpOp::ConcatEqual: cellConcatEq(lhs, *rhs); return;
72 case SetOpOp::AndEqual: cellBitAndEq(lhs, *rhs); return;
73 case SetOpOp::OrEqual: cellBitOrEq(lhs, *rhs); return;
74 case SetOpOp::XorEqual: cellBitXorEq(lhs, *rhs); return;
75 case SetOpOp::SlEqual: cellShlEq(lhs, *rhs); return;
76 case SetOpOp::SrEqual: cellShrEq(lhs, *rhs); return;
77 case SetOpOp::PlusEqualO: cellAddEqO(lhs, *rhs); return;
78 case SetOpOp::MinusEqualO: cellSubEqO(lhs, *rhs); return;
79 case SetOpOp::MulEqualO: cellMulEqO(lhs, *rhs); return;
81 not_reached();
84 ///////////////////////////////////////////////////////////////////////////////
86 struct ExtraArgs {
87 ExtraArgs(const ExtraArgs&) = delete;
88 ExtraArgs& operator=(const ExtraArgs&) = delete;
91 * Allocate an ExtraArgs structure, with arguments copied from the
92 * evaluation stack. This takes ownership of the args without
93 * adjusting reference counts, so they must be discarded from the
94 * stack.
96 static ExtraArgs* allocateCopy(TypedValue* args, unsigned nargs);
99 * Allocate an ExtraArgs, without initializing any of the arguments.
100 * All arguments must be initialized via getExtraArg before
101 * deallocate() is called for the returned pointer.
103 static ExtraArgs* allocateUninit(unsigned nargs);
106 * Deallocate an extraArgs structure. Either use the one that
107 * exists in a ActRec, or do it explicitly.
109 static void deallocate(ActRec*);
110 static void deallocate(ExtraArgs*, unsigned numArgs);
112 // Just free the memory, don't dec-ref anything.
113 static void deallocateRaw(ExtraArgs*);
116 * Make a copy of ExtraArgs.
118 ExtraArgs* clone(ActRec* fp) const;
121 * Get the slot for extra arg i, where i = argNum - func->numParams.
123 TypedValue* getExtraArg(unsigned argInd) const;
125 private:
126 ExtraArgs();
127 ~ExtraArgs();
129 static void* allocMem(unsigned nargs);
131 private:
132 TypedValue m_extraArgs[0];
133 TYPE_SCAN_FLEXIBLE_ARRAY_FIELD(m_extraArgs);
137 * Variable environment.
139 * A variable environment consists of the locals for the current function
140 * (either pseudo-main, global function, or method), plus any variables that
141 * are dynamically defined.
143 * Logically, a global function or method starts off with a variable
144 * environment that contains only its locals, but a pseudo-main is handed
145 * its caller's existing variable environment. Generally, however, we don't
146 * create a variable environment for global functions or methods until it
147 * actually needs one (i.e. if it is about to include a pseudo-main, or if
148 * it uses dynamic variable lookups).
150 * Named locals always appear in the expected place on the stack, even after
151 * a VarEnv is attached. Internally uses a NameValueTable to hook up names to
152 * the local locations.
154 struct VarEnv {
155 private:
156 NameValueTable m_nvTable;
157 ExtraArgs* m_extraArgs;
158 uint16_t m_depth;
159 const bool m_global;
161 public:
162 explicit VarEnv();
163 explicit VarEnv(ActRec* fp, ExtraArgs* eArgs);
164 explicit VarEnv(const VarEnv* varEnv, ActRec* fp);
165 ~VarEnv();
167 // Free the VarEnv and locals for the given frame
168 // which must have a VarEnv
169 static void deallocate(ActRec* fp);
171 // Allocates a local VarEnv and attaches it to the existing FP.
172 static VarEnv* createLocal(ActRec* fp);
174 // Allocate a global VarEnv. Initially not attached to any frame.
175 static void createGlobal();
177 VarEnv* clone(ActRec* fp) const;
179 void suspend(const ActRec* oldFP, ActRec* newFP);
180 void enterFP(ActRec* oldFP, ActRec* newFP);
181 void exitFP(ActRec* fp);
183 void set(const StringData* name, tv_rval tv);
184 TypedValue* lookup(const StringData* name);
185 TypedValue* lookupAdd(const StringData* name);
186 bool unset(const StringData* name);
188 Array getDefinedVariables() const;
190 // Used for save/store m_cfp for debugger
191 ActRec* getFP() const { return m_nvTable.getFP(); }
192 bool isGlobalScope() const { return m_global; }
194 // Access to wrapped ExtraArgs, if we have one.
195 TypedValue* getExtraArg(unsigned argInd) const;
199 * Action taken to handle any extra arguments passed for a function call.
201 enum class ExtraArgsAction {
202 None, // no extra arguments; zero out m_extraArgs
203 Discard, // discard extra arguments
204 Variadic, // populate `...$args' parameter
205 MayUseVV, // create ExtraArgs
206 VarAndVV, // both of the above
209 inline ExtraArgsAction extra_args_action(const Func* func, uint32_t argc) {
210 using Action = ExtraArgsAction;
212 auto const nparams = func->numNonVariadicParams();
213 if (argc <= nparams) return Action::None;
215 if (LIKELY(func->discardExtraArgs())) {
216 return Action::Discard;
218 if (func->attrs() & AttrMayUseVV) {
219 return func->hasVariadicCaptureParam() ? Action::VarAndVV
220 : Action::MayUseVV;
222 assertx(func->hasVariadicCaptureParam());
223 return Action::Variadic;
226 ///////////////////////////////////////////////////////////////////////////////
229 * Returns true iff ar represents a frame on the VM eval stack or a Resumable
230 * object on the PHP heap.
232 bool isVMFrame(const ActRec* ar);
235 * Returns true iff the given address is one of the special debugger return
236 * helpers.
238 bool isDebuggerReturnHelper(void* addr);
241 * If ar->m_savedRip points somewhere in the TC that is not a return helper,
242 * change it to point to an appropriate return helper. The two different
243 * versions are for the different needs of the C++ unwinder and debugger hooks,
244 * respectively.
246 void unwindPreventReturnToTC(ActRec* ar);
247 void debuggerPreventReturnToTC(ActRec* ar);
250 * Call debuggerPreventReturnToTC() on all live VM frames in this thread.
252 void debuggerPreventReturnsToTC();
254 ///////////////////////////////////////////////////////////////////////////////
256 inline ActRec* arAtOffset(const ActRec* ar, int32_t offset) {
257 return (ActRec*)(intptr_t(ar) + intptr_t(offset * sizeof(TypedValue)));
260 void frame_free_locals_no_hook(ActRec* fp);
262 #define arReturn(a, x) \
263 ([&] { \
264 ActRec* ar_ = (a); \
265 TypedValue val_; \
266 new (&val_) Variant(x); \
267 frame_free_locals_no_hook(ar_); \
268 tvCopy(val_, *ar_->retSlot()); \
269 return ar_->retSlot(); \
270 }())
272 #define tvReturn(x) \
273 ([&] { \
274 TypedValue val_; \
275 new (&val_) Variant(x); \
276 assertx(!isRefType(val_.m_type) && val_.m_type != KindOfUninit); \
277 return val_; \
278 }())
280 template <bool crossBuiltin> Class* arGetContextClassImpl(const ActRec* ar);
281 template <> Class* arGetContextClassImpl<true>(const ActRec* ar);
282 template <> Class* arGetContextClassImpl<false>(const ActRec* ar);
283 inline Class* arGetContextClass(const ActRec* ar) {
284 return arGetContextClassImpl<false>(ar);
286 inline Class* arGetContextClassFromBuiltin(const ActRec* ar) {
287 return arGetContextClassImpl<true>(ar);
290 ///////////////////////////////////////////////////////////////////////////////
292 // Used by extension functions that take a PHP "callback", since they need to
293 // figure out the callback context once and call it multiple times. (e.g.
294 // array_map, array_filter, ...)
295 struct CallCtx {
296 const Func* func;
297 ObjectData* this_;
298 Class* cls;
299 StringData* invName;
300 bool dynamic;
303 constexpr size_t kNumIterCells = sizeof(Iter) / sizeof(Cell);
304 constexpr size_t kNumActRecCells = sizeof(ActRec) / sizeof(Cell);
306 constexpr size_t clsRefCountToCells(size_t n) {
307 return (n * sizeof(cls_ref) + sizeof(Cell) - 1) / sizeof(Cell);
310 ///////////////////////////////////////////////////////////////////////////////
313 * We pad all stack overflow checks by a small amount to allow for three
314 * things:
316 * - inlining functions without having to either do another stack
317 * check (or chase down prologues to smash checks to be bigger).
319 * - omitting stack overflow checks on leaf functions
321 * - delaying stack overflow checks on reentry
323 constexpr int kStackCheckLeafPadding = 20;
324 constexpr int kStackCheckReenterPadding = 9;
325 constexpr int kStackCheckPadding = kStackCheckLeafPadding +
326 kStackCheckReenterPadding;
328 // Interpreter evaluation stack.
329 struct Stack {
330 private:
331 TypedValue* m_elms;
332 TypedValue* m_top;
333 TypedValue* m_base; // Stack grows down, so m_base is beyond the end of
334 // m_elms.
336 public:
337 bool isAllocated() { return m_elms != nullptr; }
338 void* getStackLowAddress() const { return m_elms; }
339 void* getStackHighAddress() const { return m_base; }
340 bool isValidAddress(uintptr_t v) {
341 return v >= uintptr_t(m_elms) && v < uintptr_t(m_base);
343 void requestInit();
344 void requestExit();
346 static const int sSurprisePageSize;
347 static const unsigned sMinStackElms;
348 static void ValidateStackSize();
349 Stack();
350 ~Stack();
352 std::string toString(const ActRec* fp, int offset,
353 std::string prefix="") const;
355 bool wouldOverflow(int numCells) const;
358 * top --
359 * topOfStackOffset --
361 * Accessors for the x64 translator. Do not play on or around.
363 TypedValue*& top() {
364 return m_top;
367 static constexpr size_t topOfStackOffset() {
368 return offsetof(Stack, m_top);
371 static TypedValue* anyFrameStackBase(const ActRec* fp);
372 static TypedValue* frameStackBase(const ActRec* fp);
373 static TypedValue* resumableStackBase(const ActRec* fp);
375 ALWAYS_INLINE
376 size_t count() const {
377 return ((uintptr_t)m_base - (uintptr_t)m_top) / sizeof(TypedValue);
380 // Same as discard(), but meant to replace popC() iff the interpreter knows
381 // for certain that decrementing a refcount is unnecessary.
382 ALWAYS_INLINE
383 void popX() {
384 assertx(m_top != m_base);
385 assertx(!isRefcountedType(m_top->m_type));
386 tvDebugTrash(m_top);
387 m_top++;
390 ALWAYS_INLINE
391 void popC() {
392 assertx(m_top != m_base);
393 assertx(cellIsPlausible(*m_top));
394 tvDecRefGen(m_top);
395 tvDebugTrash(m_top);
396 m_top++;
399 ALWAYS_INLINE
400 void popV() {
401 assertx(m_top != m_base);
402 assertx(refIsPlausible(*m_top));
403 tvDecRefRef(m_top);
404 tvDebugTrash(m_top);
405 m_top++;
408 ALWAYS_INLINE
409 void popU() {
410 assertx(m_top != m_base);
411 assertx(m_top->m_type == KindOfUninit);
412 tvDebugTrash(m_top);
413 ++m_top;
416 ALWAYS_INLINE
417 void popTV() {
418 assertx(m_top != m_base);
419 assertx(tvIsPlausible(*m_top));
420 tvDecRefGen(m_top);
421 tvDebugTrash(m_top);
422 m_top++;
425 // popAR() should only be used to tear down a pre-live ActRec. Once
426 // an ActRec is live, it should be torn down using frame_free_locals()
427 // followed by discardAR() or ret().
428 ALWAYS_INLINE
429 void popAR() {
430 assertx(m_top != m_base);
431 ActRec* ar = (ActRec*)m_top;
432 if (ar->func()->cls() && ar->hasThis()) decRefObj(ar->getThis());
433 if (ar->magicDispatch()) {
434 decRefStr(ar->getInvName());
436 discardAR();
439 ALWAYS_INLINE
440 void discardAR() {
441 assertx(m_top != m_base);
442 if (debug) {
443 for (int i = 0; i < kNumActRecCells; ++i) {
444 tvDebugTrash(m_top + i);
447 m_top += kNumActRecCells;
448 assertx((uintptr_t)m_top <= (uintptr_t)m_base);
451 ALWAYS_INLINE
452 void ret() {
453 // Leave part of the activation on the stack, since the return value now
454 // resides there.
455 if (debug) {
456 for (int i = 0; i < kNumActRecCells - 1; ++i) {
457 tvDebugTrash(m_top + i);
460 m_top += kNumActRecCells - 1;
461 assertx((uintptr_t)m_top <= (uintptr_t)m_base);
464 ALWAYS_INLINE
465 void discard() {
466 assertx(m_top != m_base);
467 tvDebugTrash(m_top);
468 m_top++;
471 ALWAYS_INLINE
472 void ndiscard(size_t n) {
473 assertx((uintptr_t)&m_top[n] <= (uintptr_t)m_base);
474 if (debug) {
475 for (int i = 0; i < n; ++i) {
476 tvDebugTrash(m_top + i);
479 m_top += n;
482 ALWAYS_INLINE
483 void trim(Cell* c) {
484 assertx(c <= m_base);
485 assertx(m_top <= c);
486 if (debug) {
487 while (m_top < c) tvDebugTrash(m_top++);
488 } else {
489 m_top = c;
493 ALWAYS_INLINE
494 void dup() {
495 assertx(m_top != m_base);
496 assertx(m_top != m_elms);
497 assertx(!isRefType(m_top->m_type));
498 Cell* fr = m_top;
499 m_top--;
500 Cell* to = m_top;
501 cellDup(*fr, *to);
504 ALWAYS_INLINE
505 void pushUninit() {
506 assertx(m_top != m_elms);
507 m_top--;
508 tvWriteUninit(*m_top);
511 ALWAYS_INLINE
512 void pushNull() {
513 assertx(m_top != m_elms);
514 m_top--;
515 tvWriteNull(*m_top);
518 ALWAYS_INLINE
519 void pushNullUninit() {
520 assertx(m_top != m_elms);
521 m_top--;
522 m_top->m_data.num = 0;
523 m_top->m_type = KindOfUninit;
526 template<DataType t, class T> void pushVal(T v) {
527 assertx(m_top != m_elms);
528 m_top--;
529 *m_top = make_tv<t>(v);
531 ALWAYS_INLINE void pushBool(bool v) { pushVal<KindOfBoolean>(v); }
532 ALWAYS_INLINE void pushInt(int64_t v) { pushVal<KindOfInt64>(v); }
533 ALWAYS_INLINE void pushDouble(double v) { pushVal<KindOfDouble>(v); }
535 // This should only be called directly when the caller has
536 // already adjusted the refcount appropriately
537 ALWAYS_INLINE
538 void pushStringNoRc(StringData* s) {
539 assertx(m_top != m_elms);
540 m_top--;
541 *m_top = make_tv<KindOfString>(s);
544 ALWAYS_INLINE
545 void pushStaticString(const StringData* s) {
546 assertx(s->isStatic()); // No need to call s->incRefCount().
547 assertx(m_top != m_elms);
548 m_top--;
549 *m_top = make_tv<KindOfPersistentString>(s);
552 // These should only be called directly when the caller has
553 // already adjusted the refcount appropriately
554 ALWAYS_INLINE
555 void pushArrayNoRc(ArrayData* a) {
556 assertx(a->isPHPArray());
557 assertx(m_top != m_elms);
558 m_top--;
559 *m_top = make_tv<KindOfArray>(a);
562 ALWAYS_INLINE
563 void pushVecNoRc(ArrayData* a) {
564 assertx(a->isVecArray());
565 assertx(m_top != m_elms);
566 m_top--;
567 *m_top = make_tv<KindOfVec>(a);
570 ALWAYS_INLINE
571 void pushDictNoRc(ArrayData* a) {
572 assertx(a->isDict());
573 assertx(m_top != m_elms);
574 m_top--;
575 *m_top = make_tv<KindOfDict>(a);
578 ALWAYS_INLINE
579 void pushKeysetNoRc(ArrayData* a) {
580 assertx(a->isKeyset());
581 assertx(m_top != m_elms);
582 m_top--;
583 *m_top = make_tv<KindOfKeyset>(a);
586 ALWAYS_INLINE
587 void pushArray(ArrayData* a) {
588 assertx(a);
589 pushArrayNoRc(a);
590 a->incRefCount();
593 ALWAYS_INLINE
594 void pushVec(ArrayData* a) {
595 assertx(a);
596 pushVecNoRc(a);
597 a->incRefCount();
600 ALWAYS_INLINE
601 void pushDict(ArrayData* a) {
602 assertx(a);
603 pushDictNoRc(a);
604 a->incRefCount();
607 ALWAYS_INLINE
608 void pushKeyset(ArrayData* a) {
609 assertx(a);
610 pushKeysetNoRc(a);
611 a->incRefCount();
614 ALWAYS_INLINE
615 void pushStaticArray(const ArrayData* a) {
616 assertx(a->isStatic()); // No need to call a->incRefCount().
617 assertx(a->isPHPArray());
618 assertx(m_top != m_elms);
619 m_top--;
620 *m_top = make_tv<KindOfPersistentArray>(a);
623 ALWAYS_INLINE
624 void pushStaticVec(const ArrayData* a) {
625 assertx(a->isStatic()); // No need to call a->incRefCount().
626 assertx(a->isVecArray());
627 assertx(m_top != m_elms);
628 m_top--;
629 *m_top = make_tv<KindOfPersistentVec>(a);
632 ALWAYS_INLINE
633 void pushStaticDict(const ArrayData* a) {
634 assertx(a->isStatic()); // No need to call a->incRefCount().
635 assertx(a->isDict());
636 assertx(m_top != m_elms);
637 m_top--;
638 *m_top = make_tv<KindOfPersistentDict>(a);
641 ALWAYS_INLINE
642 void pushStaticKeyset(const ArrayData* a) {
643 assertx(a->isStatic()); // No need to call a->incRefCount().
644 assertx(a->isKeyset());
645 assertx(m_top != m_elms);
646 m_top--;
647 *m_top = make_tv<KindOfPersistentKeyset>(a);
650 // This should only be called directly when the caller has
651 // already adjusted the refcount appropriately
652 ALWAYS_INLINE
653 void pushObjectNoRc(ObjectData* o) {
654 assertx(m_top != m_elms);
655 m_top--;
656 *m_top = make_tv<KindOfObject>(o);
659 ALWAYS_INLINE
660 void pushObject(ObjectData* o) {
661 pushObjectNoRc(o);
662 o->incRefCount();
665 ALWAYS_INLINE
666 void pushRecordNoRc(RecordData* r) {
667 assertx(m_top != m_elms);
668 m_top--;
669 *m_top = make_tv<KindOfRecord>(r);
672 ALWAYS_INLINE
673 void pushFunc(Func* f) {
674 m_top--;
675 *m_top = make_tv<KindOfFunc>(f);
678 ALWAYS_INLINE
679 void pushClsMethNoRc(ClsMethDataRef clsMeth) {
680 m_top--;
681 *m_top = make_tv<KindOfClsMeth>(clsMeth);
684 ALWAYS_INLINE
685 void nalloc(size_t n) {
686 assertx((uintptr_t)(m_top - n) <= (uintptr_t)m_base);
687 m_top -= n;
690 ALWAYS_INLINE
691 Cell* allocC() {
692 assertx(m_top != m_elms);
693 m_top--;
694 return (Cell*)m_top;
697 ALWAYS_INLINE
698 Ref* allocV() {
699 assertx(m_top != m_elms);
700 m_top--;
701 return (Ref*)m_top;
704 ALWAYS_INLINE
705 TypedValue* allocTV() {
706 assertx(m_top != m_elms);
707 m_top--;
708 return m_top;
711 ALWAYS_INLINE
712 ActRec* allocA() {
713 assertx((uintptr_t)(m_top - kNumActRecCells) >= (uintptr_t)m_elms);
714 assertx(kNumActRecCells * sizeof(Cell) == sizeof(ActRec));
715 m_top -= kNumActRecCells;
716 return (ActRec*)m_top;
719 ALWAYS_INLINE
720 void allocI() {
721 assertx(kNumIterCells * sizeof(Cell) == sizeof(Iter));
722 assertx((uintptr_t)(m_top - kNumIterCells) >= (uintptr_t)m_elms);
723 m_top -= kNumIterCells;
726 ALWAYS_INLINE
727 void allocClsRefSlots(size_t n) {
728 assertx((uintptr_t)(m_top - clsRefCountToCells(n)) >= (uintptr_t)m_elms);
729 m_top -= clsRefCountToCells(n);
730 if (debug) {
731 memset(m_top, kTrashClsRef, clsRefCountToCells(n) * sizeof(Cell));
735 ALWAYS_INLINE
736 void replaceC(const Cell c) {
737 assertx(m_top != m_base);
738 assertx(!isRefType(m_top->m_type));
739 tvDecRefGen(m_top);
740 *m_top = c;
743 template <DataType DT>
744 ALWAYS_INLINE
745 void replaceC() {
746 assertx(m_top != m_base);
747 assertx(!isRefType(m_top->m_type));
748 tvDecRefGen(m_top);
749 *m_top = make_tv<DT>();
752 template <DataType DT, typename T>
753 ALWAYS_INLINE
754 void replaceC(T value) {
755 assertx(m_top != m_base);
756 assertx(!isRefType(m_top->m_type));
757 tvDecRefGen(m_top);
758 *m_top = make_tv<DT>(value);
761 ALWAYS_INLINE
762 void replaceTV(const TypedValue& tv) {
763 assertx(m_top != m_base);
764 tvDecRefGen(m_top);
765 *m_top = tv;
768 template <DataType DT>
769 ALWAYS_INLINE
770 void replaceTV() {
771 assertx(m_top != m_base);
772 tvDecRefGen(m_top);
773 *m_top = make_tv<DT>();
776 template <DataType DT, typename T>
777 ALWAYS_INLINE
778 void replaceTV(T value) {
779 assertx(m_top != m_base);
780 tvDecRefGen(m_top);
781 *m_top = make_tv<DT>(value);
784 ALWAYS_INLINE
785 Cell* topC() {
786 assertx(m_top != m_base);
787 return tvAssertCell(m_top);
790 ALWAYS_INLINE
791 Ref* topV() {
792 assertx(m_top != m_base);
793 assertx(isRefType(m_top->m_type));
794 return (Ref*)m_top;
797 ALWAYS_INLINE
798 TypedValue* topTV() {
799 assertx(m_top != m_base);
800 return m_top;
803 ALWAYS_INLINE
804 ActRec* indA(size_t ind) {
805 assertx(m_top != m_base);
806 assertx(count() > ind + kNumActRecCells);
807 return (ActRec*)&m_top[ind];
810 ALWAYS_INLINE
811 Cell* indC(size_t ind) {
812 assertx(m_top != m_base);
813 assertx(!isRefType(m_top[ind].m_type));
814 return tvAssertCell(&m_top[ind]);
817 ALWAYS_INLINE
818 TypedValue* indTV(size_t ind) {
819 assertx(m_top != m_base);
820 return &m_top[ind];
824 //////////////////////////////////////////////////////////////////////
827 * Visit all the slots and pre-live ActRecs on a live eval stack,
828 * handling FPI regions and resumables correctly, and stopping when we
829 * reach the supplied activation record.
831 * The stack elements are visited from lower address to higher, with
832 * ActRecs visited after the stack slots below them.
834 * This will not read the VM registers (pc, fp, sp), so it will
835 * perform the requested visitation independent of modifications to
836 * the VM stack or frame pointer.
838 template<class TV, class ARFun, class TVFun>
839 typename maybe_const<TV, TypedValue>::type
840 visitStackElems(const ActRec* const fp,
841 TV* const stackTop,
842 Offset const bcOffset,
843 ARFun arFun,
844 TVFun tvFun) {
845 const TypedValue* const base = Stack::anyFrameStackBase(fp);
846 auto cursor = stackTop;
847 assertx(cursor <= base);
849 if (auto fe = fp->m_func->findFPI(bcOffset)) {
850 for (;;) {
851 ActRec* ar;
852 if (!fp->resumed()) {
853 ar = arAtOffset(fp, -fe->m_fpOff);
854 } else {
855 // fp is pointing into the Resumable struct. Since fpOff is
856 // given as an offset from the frame pointer as if it were in
857 // the normal place on the main stack, we have to reconstruct
858 // that "normal place".
859 auto const fakePrevFP = reinterpret_cast<const ActRec*>(
860 base + fp->m_func->numSlotsInFrame()
862 ar = arAtOffset(fakePrevFP, -fe->m_fpOff);
865 while (cursor < reinterpret_cast<TypedValue*>(ar)) {
866 tvFun(cursor++);
869 if (cursor == reinterpret_cast<TypedValue*>(ar)) {
870 arFun(ar, fe->m_fpushOff);
871 cursor += kNumActRecCells;
874 assertx(cursor >= reinterpret_cast<TypedValue*>(ar) + kNumActRecCells);
875 if (fe->m_parentIndex == -1) break;
876 fe = &fp->m_func->fpitab()[fe->m_parentIndex];
880 while (cursor < base) {
881 tvFun(cursor++);
885 void resetCoverageCounters();
887 // The interpOne*() methods implement individual opcode handlers.
888 using InterpOneFunc = jit::TCA (*) (ActRec*, TypedValue*, Offset);
889 extern InterpOneFunc interpOneEntryPoints[];
891 bool doFCallUnpackTC(PC origpc, int32_t numArgs, void*);
892 bool doFCall(ActRec* ar, uint32_t numArgs, bool unpack);
893 jit::TCA dispatchBB();
894 void pushFrameSlots(const Func* func, int nparams = 0);
895 Array getDefinedVariables(const ActRec*);
897 enum class StackArgsState { // tells prepareFuncEntry how much work to do
898 // the stack may contain more arguments than the function expects
899 Untrimmed,
900 // the stack has already been trimmed of any extra arguments, which
901 // have been teleported away into ExtraArgs and/or a variadic param
902 Trimmed
904 void enterVMAtFunc(ActRec* enterFnAr, StackArgsState stk, VarEnv* varEnv);
905 void enterVMAtCurPC();
906 bool prepareArrayArgs(ActRec* ar, const Cell args, Stack& stack,
907 int nregular, TypedValue* retval, bool checkRefAnnot);
909 ///////////////////////////////////////////////////////////////////////////////
913 #endif