-
Notifications
You must be signed in to change notification settings - Fork 3k
/
ext_std_closure.h
174 lines (147 loc) · 5.53 KB
/
ext_std_closure.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_EXT_CLOSURE_H_
#define incl_HPHP_EXT_CLOSURE_H_
#include "hphp/runtime/ext/extension.h"
#include "hphp/runtime/vm/func.h"
#include "hphp/runtime/vm/native-data.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
struct StandardExtension;
extern const StaticString s_Closure;
// native data for closures. Memory layout looks like this:
// [ClosureHdr][ObjectData, kind=Closure][captured vars]
struct ClosureHdr : HeapObject {
explicit ClosureHdr(uint32_t size) {
initHeader_32(HeaderKind::ClosureHdr, size);
// we need to set this here, because the next thing 'new Closure'
// will do is call the constructor, which will throw, and the
// destructor will examine this field.
ctx_bits = 0;
}
uint32_t& size() { return m_aux32; }
uint32_t size() const { return m_aux32; }
static constexpr uintptr_t kClassBit = 0x1;
bool ctxIsClass() const {
return ctx_bits & kClassBit;
}
TYPE_SCAN_CUSTOM_FIELD(ctx) {
if (!ctxIsClass()) scanner.scan(ctx_this);
}
public:
union {
void* ctx;
uintptr_t ctx_bits;
ObjectData* ctx_this;
};
};
struct c_Closure final : ObjectData {
static Class* classof() { assertx(cls_Closure); return cls_Closure; }
static c_Closure* fromObject(ObjectData* obj) {
assertx(obj->instanceof(classof()));
return reinterpret_cast<c_Closure*>(obj);
}
/* closureInstanceCtor() skips this constructor call in debug mode.
* Update that method if this assumption changes.
*/
explicit c_Closure(Class* cls)
: ObjectData(cls, 0, HeaderKind::Closure) {
// hdr()->ctx must be initialized by init() or the TC.
if (debug) setThis(reinterpret_cast<ObjectData*>(-uintptr_t(1)));
}
ClosureHdr* hdr() {
return reinterpret_cast<ClosureHdr*>(this) - 1;
}
const ClosureHdr* hdr() const {
return reinterpret_cast<const ClosureHdr*>(this) - 1;
}
/*
* Initialization function used by the interpreter. The JIT inlines these
* operations in the TC.
*
* `sp' points to the last used variable on the evaluation stack.
*/
void init(int numArgs, ActRec* ar, TypedValue* sp);
/////////////////////////////////////////////////////////////////////////////
/*
* The closure's underlying function.
*/
const Func* getInvokeFunc() const { return getVMClass()->getCachedInvoke(); }
/*
* The Class scope the closure was defined in.
*/
Class* getScope() { return getInvokeFunc()->cls(); }
/*
* Use and static local variables.
*
* Returns obj->propVecForWrite()
* but with runtime generalized checks replaced with assertions
*/
TypedValue* getUseVars() { return propVecForWrite(); }
TypedValue* getStaticVar(Slot s) {
assertx(getVMClass()->numDeclProperties() > s);
return getUseVars() + s;
}
int32_t getNumUseVars() const {
return getVMClass()->numDeclProperties() -
getInvokeFunc()->numStaticLocals();
}
/*
* The bound context of the Closure---either a $this or a late bound class,
* just like in the ActRec.
*/
void* getThisOrClass() const { return hdr()->ctx; }
void setThisOrClass(void* p) { hdr()->ctx = p; }
ObjectData* getThisUnchecked() const {
assertx(!hdr()->ctxIsClass());
return hdr()->ctx_this;
}
ObjectData* getThis() const {
return UNLIKELY(hdr()->ctxIsClass()) ? nullptr : getThisUnchecked();
}
void setThis(ObjectData* od) { hdr()->ctx_this = od; }
bool hasThis() const { return hdr()->ctx && !hdr()->ctxIsClass(); }
Class* getClass() const {
return LIKELY(hdr()->ctxIsClass()) ?
reinterpret_cast<Class*>(hdr()->ctx_bits & ~ClosureHdr::kClassBit) :
nullptr;
}
void setClass(Class* cls) {
assertx(cls);
hdr()->ctx_bits = reinterpret_cast<uintptr_t>(cls) | ClosureHdr::kClassBit;
}
bool hasClass() const { return hdr()->ctxIsClass(); }
ObjectData* clone();
/////////////////////////////////////////////////////////////////////////////
/*
* Offsets for the JIT.
*/
static constexpr ssize_t ctxOffset() {
return offsetof(ClosureHdr, ctx) - sizeof(ClosureHdr);
}
private:
friend struct Class;
friend struct StandardExtension;
static Class* cls_Closure;
static void setAllocators(Class* cls);
};
TypedValue* lookupStaticTvFromClosure(ObjectData* closure,
const StringData* name);
Slot lookupStaticSlotFromClosure(const Class* cls, const StringData* name);
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_EXT_CLOSURE_H_