Add mode to EndCatch
[hiphop-php.git] / hphp / runtime / vm / act-rec.h
blob4dd9506e490f831f1267b8ac50e563430c1cbcad
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_ACT_REC_H_
18 #define incl_HPHP_ACT_REC_H_
20 #include "hphp/runtime/base/types.h"
21 #include "hphp/runtime/base/typed-value.h"
22 #include "hphp/runtime/vm/rx.h"
23 #include "hphp/util/compact-tagged-ptrs.h"
26 * These header dependencies need to stay as minimal as possible.
29 namespace HPHP {
31 ///////////////////////////////////////////////////////////////////////////////
33 struct ActRec;
34 struct Class;
35 struct ExtraArgs;
36 struct Func;
37 struct ObjectData;
38 struct StringData;
39 struct Unit;
40 struct VarEnv;
42 using ReifiedGenericsPtr = CompactTaggedPtr<ArrayData,uint16_t>;
44 ///////////////////////////////////////////////////////////////////////////////
47 * An "ActRec" is a call activation record. The ordering of the fields assumes
48 * that stacks grow toward lower addresses.
50 * For most purposes, an ActRec can be considered to be in one of three
51 * possible states:
52 * Pre-live:
53 * After the FPush* instruction which materialized the ActRec on the stack
54 * but before the corresponding FCall instruction.
55 * Live:
56 * After the corresponding FCall instruction but before the ActRec fields
57 * and locals/iters have been decref'd (either by return or unwinding).
58 * Post-live:
59 * After the ActRec fields and locals/iters have been decref'd.
61 * Note that when a function is invoked by the runtime via invokeFunc(), the
62 * "pre-live" state is skipped and the ActRec is materialized in the "live"
63 * state.
65 struct ActRec {
66 #if defined(__powerpc64__)
67 ActRec* m_sfp; // Previous hardware frame pointer/ActRec.
68 uint32_t m_savedCR; // PPC64's sign flags (CR)
69 uint32_t m_reserved; // Reserved word as on ABI
70 uint64_t m_savedRip; // In-TC address to return to.
71 uint64_t m_savedToc; // TOC save doubleword
72 #else // X64 style
73 // This pair of uint64_t's must be the first two elements in the structure
74 // so that the pointer to the ActRec can also be used for RBP chaining.
75 // Note that ActRecs are also native frames, so this is an implicit machine
76 // dependency.
77 ActRec* m_sfp; // Previous hardware frame pointer/ActRec
78 uint64_t m_savedRip; // native (in-TC) return address
79 #endif
80 const Func* m_func; // Function.
81 uint32_t m_callOff; // bc offset of call opcode from caller func entry.
82 uint32_t m_numArgsAndFlags; // arg_count:26, flags:6
83 union {
84 ObjectData* m_thisUnsafe; // This.
85 Class* m_clsUnsafe; // Late bound class.
87 union {
88 VarEnv* m_varEnv; // Variable environment when live
89 ExtraArgs* m_extraArgs; // Lightweight extra args, when live
90 StringData* m_invName; // Invoked name, used for __call(), when pre-live
91 // Used to store a pointer to reified generics and a bit map of
92 // which generics are reified
93 ReifiedGenericsPtr m_reifiedGenerics{};
96 TYPE_SCAN_CUSTOM_FIELD(m_thisUnsafe) {
97 // skip if "this" is a class
98 if (checkThisOrNull(m_thisUnsafe)) scanner.scan(m_thisUnsafe);
100 TYPE_SCAN_CUSTOM_FIELD(m_varEnv) {
101 // All three union members could be heap pointers, but we don't care
102 // which kind; PtrMap will resolve things.
103 scanner.scan(m_varEnv);
106 /////////////////////////////////////////////////////////////////////////////
108 enum Flags : uint32_t {
109 None = 0,
111 // Set if the function was called using FCall instruction with more
112 // than one return values and must return a value via RetM.
113 MultiReturn = (1u << 26),
115 // Set if this corresponds to a dynamic call
116 DynamicCall = (1u << 27),
118 // Set if m_reifiedGenerics contains valid data
119 HasReifiedGenerics = (1u << 28),
121 // This bit can be independently set on ActRecs with any other flag state.
122 // It's used by the unwinder to know that an ActRec has been partially torn
123 // down (locals freed).
124 LocalsDecRefd = (1u << 29),
126 // Four mutually exclusive execution mode states in these 2 bits.
127 InResumed = (1u << 30),
128 AsyncEagerRet = (1u << 31),
129 MagicDispatch = InResumed|AsyncEagerRet,
132 static constexpr int kNumArgsBits = 26;
133 static constexpr int kNumArgsMask = (1 << kNumArgsBits) - 1;
134 static constexpr int kFlagsMask = ~kNumArgsMask;
135 static constexpr int kExecutionModeMask =
136 ~(LocalsDecRefd | DynamicCall | MultiReturn);
139 * To conserve space, we use unions for pairs of mutually exclusive fields
140 * (fields that are not used at the same time).
142 * The least significant bit is used as a marker for each pair of fields so
143 * that we can distinguish at runtime which field is valid. We define
144 * accessors (below) to encapsulate this logic.
146 static auto constexpr kHasClassBit = 0x1; // unset for m_this
147 static auto constexpr kExtraArgsBit = 0x1; // unset for m_varEnv
149 static constexpr uintptr_t kTrashedVarEnvSlot = 0xfeeefeee000f000f;
150 static constexpr uintptr_t kTrashedThisSlot = 0xfeeefeeef00fe00e;
151 static constexpr uintptr_t kTrashedFuncSlot = 0xfeeefeeef00fe00d;
152 static constexpr uintptr_t kTrashedReifiedGenericsSlot = 0xfeeefeeef00fe00c;
154 /////////////////////////////////////////////////////////////////////////////
157 * The next outermost VM frame, or nullptr if this is a reentry frame.
159 ActRec* sfp() const;
162 * The Func and Unit for this frame.
164 const Func* func() const;
165 const Unit* unit() const;
168 * Set up frame linkage with the caller ActRec.
170 void setReturn(ActRec* fp, PC callPC, void* retAddr);
171 void setJitReturn(void* retAddr);
174 * Hijack the frame such that a PHP return will cause us to leave the current
175 * VM nesting layer.
177 void setReturnVMExit();
180 * Whether this frame should be skipped when searching for context.
182 * @returns: func() && func()->isSkipFrame().
184 bool skipFrame() const;
186 /////////////////////////////////////////////////////////////////////////////
187 // NumArgs / Flags.
190 * Number of arguments passed for this invocation.
192 int32_t numArgs() const;
195 * Raw flags accessors.
197 Flags flags() const;
198 bool localsDecRefd() const;
199 bool resumed() const;
200 bool isAsyncEagerReturn() const;
201 bool magicDispatch() const;
202 bool isDynamicCall() const;
203 bool isFCallM() const;
204 bool hasReifiedGenerics() const;
207 * Pack `numArgs' and `flags' into the format expected by m_numArgsAndFlags.
209 static uint32_t encodeNumArgsAndFlags(uint32_t numArgs, Flags flags);
212 * Set the numArgs component of m_numArgsAndFlags to `numArgs'.
214 * The init* flavor zeroes the flags component, whereas the set* flavor
215 * preserves flags.
217 void initNumArgs(uint32_t numArgs);
218 void setNumArgs(uint32_t numArgs);
221 * Flags setters.
223 void setLocalsDecRefd();
224 void setResumed();
225 void setAsyncEagerReturn();
226 void setDynamicCall();
227 void setFCallM();
228 void setHasReifiedGenerics();
231 * Set or clear both m_invName and the MagicDispatch flag.
233 void setMagicDispatch(StringData* invName);
234 StringData* clearMagicDispatch();
236 /////////////////////////////////////////////////////////////////////////////
237 // This / Class.
240 * Encode `obj' or `cls' for the m_this/m_cls union.
242 static void* encodeThis(ObjectData* obj);
243 static void* encodeClass(const Class* cls);
246 * Determine whether p is a Class* or an ObjectData* based
247 * on kHasClassBit.
249 * @requires: p != nullptr
251 static bool checkThis(void* p);
254 * Determine whether p is a Class* based on kHasClassBit.
256 * @requires: p is a Cctx, an ObjectData* or a nullptr
258 static bool checkThisOrNull(void* p);
261 * Decode `p', encoded in the format of m_this/m_cls.
263 * If `p' has the other encoding (or is nullptr), return nullptr.
265 static ObjectData* decodeThis(void* p);
266 static Class* decodeClass(void* p);
269 * Set m_this/m_cls to the pre-encoded `objOrCls'.
271 * One of these asserts if `objOrCls' is null, but it is a mystery which one.
273 void setThisOrClass(void* objOrCls);
274 void setThisOrClassAllowNull(void* objOrCls);
277 * Whether the m_this/m_cls union is discriminated in the desired way.
279 * @requires: m_func->implCls() != nullptr
281 bool hasThis() const;
282 bool hasClass() const;
285 * Get the (encoded) value of the m_this/m_cls union.
287 * @requires: hasThis() || hasClass()
289 void* getThisOrClass() const;
292 * Get m_thisUnsafe. Caller takes responsibility for its meaning.
294 ObjectData* getThisUnsafe() const;
296 * Get and decode the value of m_this/m_cls.
298 * @requires: hasThis() or hasClass(), respectively
300 ObjectData* getThis() const;
301 Class* getClass() const;
304 * Encode and set `val' to m_this/m_cls
306 * @requires: m_func->implClass() and
307 * !m_func->isStaticInPrologue()
309 void setThis(ObjectData* val);
311 * Encode and set `val' to m_this/m_cls
313 * @requires: m_func->implClass() and
314 * !(m_func->attrs() & AttrRequiresThis)
316 void setClass(Class* val);
319 * Write garbage to the m_this/m_cls union (in debug mode only).
321 void trashThis();
323 /////////////////////////////////////////////////////////////////////////////
324 // Reified Generics.
327 * Sets to reified generics slot
328 * It also sets HasReifiedGenerics on the m_numArgsAndFlags
330 void setReifiedGenerics(ArrayData* rg);
333 * Gets reified generics
335 ArrayData* getReifiedGenerics() const;
338 * Trashes the reified generics
340 void trashReifiedGenerics();
342 /////////////////////////////////////////////////////////////////////////////
343 // VarEnv / ExtraArgs.
346 * Write garbage to the m_varEnv/m_extraArgs union (in debug mode only).
348 void trashVarEnv();
351 * Check that the m_varEnv/m_extraArgs union is not the special garbage
352 * value.
354 bool checkVarEnv() const;
357 * Whether the m_varEnv/m_extraArgs union is discriminated in the desired
358 * way.
360 bool hasVarEnv() const;
361 bool hasExtraArgs() const;
364 * Get and decode the VarEnv.
366 * @requires: hasVarEnv()
368 VarEnv* getVarEnv() const;
371 * Get and decode the ExtraArgs.
373 * If !hasExtraArgs(), returns nullptr.
375 ExtraArgs* getExtraArgs() const;
378 * Get and decode the magic invocation name.
380 * @requires: magicDispatch()
382 StringData* getInvName() const;
385 * Encode and set `val' to the m_varEnv/m_extraArgs union.
387 void setVarEnv(VarEnv* val);
388 void setExtraArgs(ExtraArgs* val);
389 void resetExtraArgs();
392 * Get the extra argument with index `ind', from either the VarEnv or the
393 * ExtraArgs, whichever is set.
395 * Returns nullptr if there are no extra arguments.
397 TypedValue* getExtraArg(unsigned ind) const;
400 * Get the minimum possible effective level of reactivity.
402 * Doesn't return precise level as conditional reactivity is not tracked yet.
404 RxLevel rxMinLevel() const;
407 * address to teleport the return value after destroying this actrec.
409 TypedValue* retSlot() {
410 return reinterpret_cast<TypedValue*>(this + 1) - 1;
414 static_assert(offsetof(ActRec, m_sfp) == 0,
415 "m_sfp should be at offset 0 of ActRec");
418 * Size in bytes of the target architecture's call frame.
420 constexpr auto kNativeFrameSize = offsetof(ActRec, m_func);
423 * offset from frame ptr to return value slot after teardown
425 constexpr auto kArRetOff = sizeof(ActRec) - sizeof(TypedValue);
426 static_assert(kArRetOff % sizeof(TypedValue) == 0, "");
429 * Whether `address' is a helper stub that we're permitted to set
430 * ActRec::m_savedRip to.
432 bool isReturnHelper(void* address);
433 bool isDebuggerReturnHelper(void* address);
435 /* Offset of the m_func and m_thisUnsafe fields in cells */
437 static_assert(offsetof(ActRec, m_func) % sizeof(Cell) == 0, "");
438 static_assert(offsetof(ActRec, m_thisUnsafe) % sizeof(Cell) == 0, "");
440 constexpr auto kActRecFuncCellOff = offsetof(ActRec, m_func) /
441 sizeof(Cell);
442 constexpr auto kActRecCtxCellOff = offsetof(ActRec, m_thisUnsafe) /
443 sizeof(Cell);
445 ///////////////////////////////////////////////////////////////////////////////
449 #include "hphp/runtime/vm/act-rec-inl.h"
451 #endif