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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/native-data.h"
19 #include "hphp/runtime/base/exceptions.h"
20 #include "hphp/runtime/base/memory-manager.h"
21 #include "hphp/runtime/base/tv-refcount.h"
22 #include "hphp/runtime/base/type-variant.h"
23 #include "hphp/runtime/vm/class.h"
24 #include "hphp/runtime/vm/memo-cache.h"
25 #include "hphp/runtime/ext/generator/ext_generator.h"
26 #include "hphp/runtime/ext/asio/ext_async-generator.h"
28 namespace HPHP::Native
{
29 //////////////////////////////////////////////////////////////////////////////
31 using NativeDataInfoMap
= std::unordered_map
<const StringData
*,NativeDataInfo
>;
32 static NativeDataInfoMap s_nativedatainfo
;
36 // return the full native header size, which is also the distance from
37 // the allocated pointer to the ObjectData*.
38 size_t ndsize(size_t dataSize
, size_t nMemoSlots
) {
39 if (UNLIKELY(nMemoSlots
> 0)) {
40 return alignTypedValue(
41 alignTypedValue(sizeof(NativeNode
)) +
42 nMemoSlots
* sizeof(MemoSlot
) +
46 return alignTypedValue(dataSize
+ sizeof(NativeNode
));
52 size_t ndsize(const ObjectData
* obj
, const NativeDataInfo
* ndi
) {
53 auto cls
= obj
->getVMClass();
54 if (cls
== Generator::classof()) {
55 assertx(!cls
->hasMemoSlots());
56 return Native::data
<Generator
>(obj
)->resumable()->size() -
59 if (cls
== AsyncGenerator::classof()) {
60 assertx(!cls
->hasMemoSlots());
61 return Native::data
<AsyncGenerator
>(obj
)->resumable()->size() -
64 return ndsize(ndi
->sz
, cls
->numMemoSlots());
67 void registerNativeDataInfo(const StringData
* name
,
69 NativeDataInfo::InitFunc init
,
70 NativeDataInfo::CopyFunc copy
,
71 NativeDataInfo::DestroyFunc destroy
,
72 NativeDataInfo::SweepFunc sweep
,
73 NativeDataInfo::SleepFunc sleep
,
74 NativeDataInfo::WakeupFunc wakeup
,
75 type_scan::Index tyindex
,
78 assertx(s_nativedatainfo
.find(name
) == s_nativedatainfo
.end());
79 assertx((sleep
== nullptr && wakeup
== nullptr) ||
80 (sleep
!= nullptr && wakeup
!= nullptr));
83 info
.rt_attrs
= rt_attrs
;
84 info
.tyindex
= tyindex
;
87 info
.destroy
= destroy
;
91 info
.ctor_throws
= ctor_throws
;
92 s_nativedatainfo
[name
] = info
;
95 NativeDataInfo
* getNativeDataInfo(const StringData
* name
) {
96 auto it
= s_nativedatainfo
.find(name
);
97 if (it
== s_nativedatainfo
.end()) {
103 /* Classes with NativeData structs allocate extra memory prior
106 * [NativeNode][padding][memo slots][NativeData][ObjectData](prop0)...(propN)
108 * ObjectData* points here
110 * padding is added by alignTypedValue(sizeof(NativeData)) to ensure
111 * that ObjectData* falls on a 16-aligned boundary. NativeData is
112 * sizeof(NativeData) (NativeDataInfo.sz) bytes for the custom struct.
113 * NativeNode is a link in the NativeData sweep list for this ND block
115 template <bool Unlocked
>
116 ObjectData
* nativeDataInstanceCtor(Class
* cls
) {
117 auto const ndi
= cls
->getNativeDataInfo();
119 auto const nativeDataSize
= ndsize(ndi
->sz
, cls
->numMemoSlots());
120 auto const nProps
= cls
->numDeclProperties();
121 auto const size
= ObjectData::sizeForNProps(nProps
) + nativeDataSize
;
123 auto node
= reinterpret_cast<NativeNode
*>(
124 tl_heap
->objMalloc(size
)
126 node
->obj_offset
= nativeDataSize
;
127 assertx(type_scan::isKnownType(ndi
->tyindex
));
128 node
->initHeader_32_16(HeaderKind::NativeData
, 0, ndi
->tyindex
);
129 auto const flags
= Unlocked
130 ? ObjectData::IsBeingConstructed
131 : ObjectData::NoAttrs
;
132 auto obj
= new (reinterpret_cast<char*>(node
) + nativeDataSize
)
133 ObjectData(cls
, flags
, HeaderKind::NativeObject
);
134 assertx(obj
->hasExactlyOneRef());
136 if (UNLIKELY(cls
->hasMemoSlots())) {
137 auto cur
= reinterpret_cast<MemoSlot
*>(
138 reinterpret_cast<char*>(node
) + sizeof(NativeNode
));
139 auto end
= reinterpret_cast<MemoSlot
*>(
140 reinterpret_cast<char*>(node
) + nativeDataSize
);
150 tl_heap
->addNativeObject(node
);
155 template ObjectData
* nativeDataInstanceCtor
<false>(Class
*);
156 template ObjectData
* nativeDataInstanceCtor
<true>(Class
*);
158 ObjectData
* nativeDataInstanceCopyCtor(ObjectData
* src
, Class
* cls
,
160 auto const ndi
= cls
->getNativeDataInfo();
163 throw_not_implemented("NativeDataInfoCopy");
165 auto const nativeDataSize
= ndsize(src
, ndi
);
166 auto node
= reinterpret_cast<NativeNode
*>(
167 tl_heap
->objMalloc(ObjectData::sizeForNProps(nProps
) + nativeDataSize
)
169 node
->obj_offset
= nativeDataSize
;
170 assertx(type_scan::isKnownType(ndi
->tyindex
));
171 node
->initHeader_32_16(HeaderKind::NativeData
, 0, ndi
->tyindex
);
172 auto obj
= new (reinterpret_cast<char*>(node
) + nativeDataSize
)
173 ObjectData(cls
, ObjectData::InitRaw
{}, ObjectData::NoAttrs
,
174 HeaderKind::NativeObject
);
175 assertx(obj
->hasExactlyOneRef());
177 obj
->props()->init(cls
->numDeclProperties());
179 if (UNLIKELY(cls
->hasMemoSlots())) {
180 auto cur
= reinterpret_cast<MemoSlot
*>(
181 reinterpret_cast<char*>(node
) + sizeof(NativeNode
));
182 auto end
= reinterpret_cast<MemoSlot
*>(
183 reinterpret_cast<char*>(node
) + nativeDataSize
);
194 tl_heap
->addNativeObject(node
);
199 void nativeDataInstanceDtor(ObjectData
* obj
, const Class
* cls
) {
202 auto const nProps
= size_t{cls
->numDeclProperties()};
203 obj
->props()->foreach(nProps
, [&](tv_lval lval
) {
207 auto ndi
= cls
->getNativeDataInfo();
209 if (UNLIKELY(obj
->getAttribute(ObjectData::UsedMemoCache
))) {
210 assertx(cls
->hasMemoSlots());
211 auto const nSlots
= cls
->numMemoSlots();
212 for (Slot i
= 0; i
< nSlots
; ++i
) {
213 auto slot
= obj
->memoSlotNativeData(i
, ndi
->sz
);
214 if (slot
->isCache()) {
215 if (auto cache
= slot
->getCache()) req::destroy_raw(cache
);
217 tvDecRefGen(*slot
->getValue());
225 auto node
= getNativeNode(obj
, ndi
);
227 tl_heap
->removeNativeObject(node
);
230 tl_heap
->objFree(node
, ObjectData::sizeForNProps(nProps
) + ndsize(obj
, ndi
));
233 Variant
nativeDataSleep(const ObjectData
* obj
) {
234 auto ndi
= obj
->getVMClass()->getNativeDataInfo();
237 return ndi
->sleep(obj
);
240 void nativeDataWakeup(ObjectData
* obj
, const Variant
& data
) {
241 auto ndi
= obj
->getVMClass()->getNativeDataInfo();
243 assertx(ndi
->wakeup
);
244 ndi
->wakeup(obj
, data
);
247 //////////////////////////////////////////////////////////////////////////////
248 } // namespace HPHP::Native