Add mode to EndCatch
[hiphop-php.git] / hphp / runtime / vm / resumable.h
blobda6a213487b5e3ad126aa4226e17bdac8678f72a
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_RUNTIME_VM_RESUMABLE_H_
18 #define incl_HPHP_RUNTIME_VM_RESUMABLE_H_
20 #include "hphp/runtime/vm/act-rec.h"
21 #include "hphp/runtime/vm/bytecode.h"
22 #include "hphp/runtime/vm/func.h"
23 #include "hphp/runtime/vm/native-data.h"
24 #include "hphp/runtime/vm/jit/types.h"
26 namespace HPHP {
28 //////////////////////////////////////////////////////////////////////
30 /**
31 * Indicates how a function got resumed.
33 enum class ResumeMode : uint8_t {
34 // The function was regularly called and its frame is located on the stack.
35 // This is the only valid mode for regular (non-async, non-generator)
36 // functions. Async functions are executed in this mode (also called eager
37 // execution) until reaching the first blocking await statement. Generators
38 // and async generators run in this mode only during argument type enforcement
39 // and suspend their execution immediately afterwards using the CreateCont
40 // opcode.
41 None = 0,
43 // Execution of the function was resumed by the asio scheduler upon completion
44 // of the awaited WaitHandle. Frame of the function is stored on the heap
45 // colocated with the Resumable structure. Valid only for async functions and
46 // async generators. An AsyncGeneratorWaitHandle is associated with async
47 // generators.
48 Async = 1,
50 // Execution of the function was resumed by generator iteration (e.g. by
51 // calling next() or send()). Frame of the function is stored on the heap
52 // colocated with the Resumable structure. Valid only for generators and
53 // async generators. Async generators are considered to be eagerly executed
54 // in this mode and don't have any associated AsyncGeneratorWaitHandle.
55 GenIter = 2,
58 char* resumeModeShortName(ResumeMode resumeMode);
60 ResumeMode resumeModeFromActRecImpl(ActRec* ar);
61 ALWAYS_INLINE ResumeMode resumeModeFromActRec(ActRec* ar) {
62 if (LIKELY(!ar->resumed())) return ResumeMode::None;
63 return resumeModeFromActRecImpl(ar);
66 /**
67 * Header of the resumable frame used by async functions:
69 * NativeNode* -> +--------------------------------+ low address
70 * | kind=AsyncFuncFrame |
71 * +--------------------------------+
72 * | Function locals and iterators |
73 * Resumable* -> +--------------------------------+
74 * | ActRec in Resumable |
75 * +--------------------------------+
76 * | Rest of Resumable |
77 * ObjectData* -> +--------------------------------+
78 * | c_AsyncFuncWaitHandle |
79 * +--------------------------------+ high address
81 * Header of the native frame used by generators:
83 * NativeNode* -> +--------------------------------+ low address
84 * | kind=NativeData |
85 * +--------------------------------+
86 * | Function locals and iterators |
87 * BaseGenerator* -> +--------------------------------+
88 * < NativeData > | ActRec in Resumable |
89 * +--------------------------------+
90 * | Rest of Resumable |
91 * +--------------------------------+
92 * | Rest of [Async]Generator |
93 * ObjectData* -> +--------------------------------+
94 * | Parent object |
95 * +--------------------------------+ high address
97 struct alignas(16) Resumable {
98 // This function is used only by AFWH, temporary till AFWH is converted to HNI
99 static Resumable* FromObj(ObjectData* obj) {
100 return reinterpret_cast<Resumable*>(obj) - 1;
102 static const Resumable* FromObj(const ObjectData* obj) {
103 return reinterpret_cast<const Resumable*>(obj) - 1;
105 static constexpr ptrdiff_t arOff() {
106 return offsetof(Resumable, m_actRec);
108 static constexpr ptrdiff_t resumeAddrOff() {
109 return offsetof(Resumable, m_resumeAddr);
111 static constexpr ptrdiff_t resumeOffsetOff() {
112 return offsetof(Resumable, m_resumeOffset);
114 static constexpr ptrdiff_t dataOff() {
115 return sizeof(Resumable);
117 static constexpr size_t getFrameSize(size_t numSlots) {
118 return numSlots * sizeof(TypedValue);
121 // This function is temporary till we move AFWH to HNI
122 static Resumable* Create(size_t frameSize, size_t totalSize) {
123 // Allocate memory.
124 (void)type_scan::getIndexForMalloc<ActRec>();
125 auto node = new (tl_heap->objMalloc(totalSize))
126 NativeNode(HeaderKind::AsyncFuncFrame,
127 sizeof(NativeNode) + frameSize + sizeof(Resumable));
128 auto frame = reinterpret_cast<char*>(node + 1);
129 return reinterpret_cast<Resumable*>(frame + frameSize);
132 template<bool clone,
133 bool mayUseVV = true>
134 void initialize(const ActRec* fp, jit::TCA resumeAddr,
135 Offset resumeOffset, size_t frameSize, size_t totalSize) {
136 assertx(fp);
137 assertx(fp->resumed() == clone);
138 auto const func = fp->func();
139 assertx(func);
140 assertx(func->isResumable());
141 assertx(func->contains(resumeOffset));
142 // Check memory alignment
143 assertx((((uintptr_t) actRec()) & (sizeof(Cell) - 1)) == 0);
145 if (!clone) {
146 // Copy ActRec, locals and iterators
147 auto src = reinterpret_cast<const char*>(fp) - frameSize;
148 auto dst = reinterpret_cast<char*>(actRec()) - frameSize;
149 wordcpy(dst, src, frameSize + sizeof(ActRec));
151 // Set resumed flag.
152 actRec()->setResumed();
154 // Suspend VarEnv if needed
155 assertx(mayUseVV || !(func->attrs() & AttrMayUseVV));
156 if (mayUseVV &&
157 UNLIKELY(func->attrs() & AttrMayUseVV) &&
158 UNLIKELY(fp->hasVarEnv())) {
159 fp->getVarEnv()->suspend(fp, actRec());
161 } else {
162 // If we are cloning a Resumable, only copy the ActRec. The
163 // caller will take care of copying locals, setting the VarEnv, etc.
164 // When called from AFWH::Create or Generator::Create we know we are
165 // going to overwrite m_sfp and m_savedRip, so don't copy them here.
166 auto src = reinterpret_cast<const char*>(fp);
167 auto dst = reinterpret_cast<char*>(actRec());
168 const size_t offset = offsetof(ActRec, m_func);
169 wordcpy(dst + offset, src + offset, sizeof(ActRec) - offset);
172 // Populate Resumable.
173 m_resumeAddr = resumeAddr;
174 m_offsetAndSize = (totalSize << 32 | resumeOffset);
177 template<class T> static void Destroy(size_t size, T* obj) {
178 auto const base = reinterpret_cast<char*>(obj + 1) - size;
179 obj->~T();
180 tl_heap->objFree(base, size);
183 ActRec* actRec() { return &m_actRec; }
184 const ActRec* actRec() const { return &m_actRec; }
185 jit::TCA resumeAddr() const { return m_resumeAddr; }
186 Offset resumeOffset() const {
187 assertx(m_actRec.func()->contains(m_resumeOffset));
188 return m_resumeOffset;
190 size_t size() const { return m_size; }
192 void setResumeAddr(jit::TCA resumeAddr, Offset resumeOffset) {
193 assertx(m_actRec.func()->contains(resumeOffset));
194 m_resumeAddr = resumeAddr;
195 m_resumeOffset = resumeOffset;
198 private:
199 // ActRec of the resumed frame.
200 ActRec m_actRec;
202 // Resume address.
203 jit::TCA m_resumeAddr;
205 // Resume offset: bytecode offset from start of Unit's bytecode.
206 union {
207 struct {
208 Offset m_resumeOffset;
210 // Size of the memory block that includes this resumable.
211 int32_t m_size;
213 uint64_t m_offsetAndSize;
217 static_assert(Resumable::arOff() == 0,
218 "ActRec must be in the beginning of Resumable");
220 //////////////////////////////////////////////////////////////////////
224 #endif