Give `NowTask` some teeth
[hiphop-php.git] / hphp / runtime / vm / native-data.cpp
blobc154d66bb72b4a5e42a8abc1c7f2d128912c5fba
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 #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;
34 namespace {
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) +
43 dataSize
45 } else {
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() -
57 sizeof(ObjectData);
59 if (cls == AsyncGenerator::classof()) {
60 assertx(!cls->hasMemoSlots());
61 return Native::data<AsyncGenerator>(obj)->resumable()->size() -
62 sizeof(ObjectData);
64 return ndsize(ndi->sz, cls->numMemoSlots());
67 void registerNativeDataInfo(const StringData* name,
68 size_t sz,
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,
76 uint8_t rt_attrs,
77 bool ctor_throws) {
78 assertx(s_nativedatainfo.find(name) == s_nativedatainfo.end());
79 assertx((sleep == nullptr && wakeup == nullptr) ||
80 (sleep != nullptr && wakeup != nullptr));
81 NativeDataInfo info;
82 info.sz = sz;
83 info.rt_attrs = rt_attrs;
84 info.tyindex = tyindex;
85 info.init = init;
86 info.copy = copy;
87 info.destroy = destroy;
88 info.sweep = sweep;
89 info.sleep = sleep;
90 info.wakeup = wakeup;
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()) {
98 return nullptr;
100 return &it->second;
103 /* Classes with NativeData structs allocate extra memory prior
104 * to the ObjectData.
106 * [NativeNode][padding][memo slots][NativeData][ObjectData](prop0)...(propN)
107 * /\
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();
118 assertx(ndi);
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);
141 while (cur < end) {
142 (cur++)->init();
146 if (ndi->init) {
147 ndi->init(obj);
149 if (ndi->sweep) {
150 tl_heap->addNativeObject(node);
152 return obj;
155 template ObjectData* nativeDataInstanceCtor<false>(Class*);
156 template ObjectData* nativeDataInstanceCtor<true>(Class*);
158 ObjectData* nativeDataInstanceCopyCtor(ObjectData* src, Class* cls,
159 size_t nProps) {
160 auto const ndi = cls->getNativeDataInfo();
161 assertx(ndi);
162 if (!ndi->copy) {
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);
184 while (cur < end) {
185 (cur++)->init();
189 if (ndi->init) {
190 ndi->init(obj);
192 ndi->copy(obj, src);
193 if (ndi->sweep) {
194 tl_heap->addNativeObject(node);
196 return obj;
199 void nativeDataInstanceDtor(ObjectData* obj, const Class* cls) {
200 obj->~ObjectData();
202 auto const nProps = size_t{cls->numDeclProperties()};
203 obj->props()->foreach(nProps, [&](tv_lval lval) {
204 tvDecRefGen(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);
216 } else {
217 tvDecRefGen(*slot->getValue());
222 if (ndi->destroy) {
223 ndi->destroy(obj);
225 auto node = getNativeNode(obj, ndi);
226 if (ndi->sweep) {
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();
235 assertx(ndi);
236 assertx(ndi->sleep);
237 return ndi->sleep(obj);
240 void nativeDataWakeup(ObjectData* obj, const Variant& data) {
241 auto ndi = obj->getVMClass()->getNativeDataInfo();
242 assertx(ndi);
243 assertx(ndi->wakeup);
244 ndi->wakeup(obj, data);
247 //////////////////////////////////////////////////////////////////////////////
248 } // namespace HPHP::Native