Promote AsyncGenerator use-after-completion check
[hiphop-php.git] / hphp / runtime / base / apc-handle.cpp
blob3cb6119646372f5ce78bfb362dc7904a1b3d764a
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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/apc-handle.h"
18 #include "hphp/runtime/base/apc-array.h"
19 #include "hphp/runtime/base/apc-bespoke.h"
20 #include "hphp/runtime/base/apc-clsmeth.h"
21 #include "hphp/runtime/base/apc-collection.h"
22 #include "hphp/runtime/base/apc-named-entity.h"
23 #include "hphp/runtime/base/apc-object.h"
24 #include "hphp/runtime/base/apc-rclass-meth.h"
25 #include "hphp/runtime/base/apc-rfunc.h"
26 #include "hphp/runtime/base/apc-string.h"
27 #include "hphp/runtime/base/apc-typed-value.h"
28 #include "hphp/runtime/base/vanilla-dict.h"
29 #include "hphp/runtime/ext/apc/ext_apc.h"
30 #include "hphp/runtime/vm/class-meth-data-ref.h"
32 namespace HPHP {
34 //////////////////////////////////////////////////////////////////////
36 const StaticString s_invalidMethCaller("Cannot store meth_caller in APC");
38 APCHandle::Pair APCHandle::Create(const_variant_ref source,
39 APCHandleLevel level,
40 bool unserializeObj,
41 bool pure) {
42 auto const cell = source.asTypedValue();
43 switch (cell.type()) {
44 case KindOfUninit: {
45 auto const value = APCTypedValue::tvUninit();
46 return {value->getHandle(), sizeof(APCTypedValue)};
48 case KindOfNull: {
49 auto const value = APCTypedValue::tvNull();
50 return {value->getHandle(), sizeof(APCTypedValue)};
52 case KindOfBoolean: {
53 auto const value = val(cell).num ? APCTypedValue::tvTrue()
54 : APCTypedValue::tvFalse();
55 return {value->getHandle(), sizeof(APCTypedValue)};
57 case KindOfInt64: {
58 auto const value = new APCTypedValue(val(cell).num);
59 return {value->getHandle(), sizeof(APCTypedValue)};
61 case KindOfDouble: {
62 auto const value = new APCTypedValue(val(cell).dbl);
63 return {value->getHandle(), sizeof(APCTypedValue)};
65 case KindOfRFunc:
66 return APCRFunc::Construct(val(cell).prfunc);
67 case KindOfFunc: {
68 auto const func = val(cell).pfunc;
69 if (func->isMethCaller()) {
70 SystemLib::throwInvalidOperationExceptionObject(
71 VarNR{s_invalidMethCaller.get()}
74 auto const serialize_func =
75 RuntimeOption::EvalAPCSerializeFuncs &&
76 // Right now cls_meth() can serialize as an array, and attempting to
77 // recursively serialize elements in the array will eventually attempt
78 // to serialize a method pointer.
79 !func->isMethod();
80 if (serialize_func) {
81 if (func->isPersistent()) {
82 auto const value = new APCTypedValue(func);
83 return {value->getHandle(), sizeof(APCTypedValue)};
85 auto const value = new APCNamedFunc(func);
86 return {value->getHandle(), sizeof(APCNamedFunc)};
88 invalidFuncConversion("string");
90 case KindOfClass: {
91 auto const cls = val(cell).pclass;
92 if (cls->isPersistent()) {
93 auto const value = new APCTypedValue(cls);
94 return {value->getHandle(), sizeof(APCTypedValue)};
96 auto const value = new APCNamedClass(cls);
97 return {value->getHandle(), sizeof(APCNamedClass)};
99 case KindOfLazyClass: {
100 auto const value = new APCTypedValue(val(cell).plazyclass);
101 return {value->getHandle(), sizeof(APCTypedValue)};
103 case KindOfPersistentString:
104 case KindOfString: {
105 auto const s = val(cell).pstr;
106 if (auto const value = APCTypedValue::HandlePersistent(s)) {
107 return value;
109 if (auto const st = lookupStaticString(s)) {
110 auto const value = new APCTypedValue(APCTypedValue::StaticStr{}, st);
111 return {value->getHandle(), sizeof(APCTypedValue)};
113 auto const st = StringData::MakeUncounted(s->slice());
114 auto const value = new APCTypedValue(APCTypedValue::UncountedStr{}, st);
115 return {value->getHandle(), st->size() + sizeof(APCTypedValue)};
118 case KindOfPersistentVec:
119 case KindOfVec: {
120 auto const ad = val(cell).parr;
121 assertx(ad->isVecType());
122 return APCArray::MakeSharedVec(ad, level, unserializeObj, pure);
125 case KindOfPersistentDict:
126 case KindOfDict: {
127 auto const ad = val(cell).parr;
128 assertx(ad->isDictType());
129 return APCArray::MakeSharedDict(ad, level, unserializeObj, pure);
132 case KindOfPersistentKeyset:
133 case KindOfKeyset: {
134 auto const ad = val(cell).parr;
135 assertx(ad->isKeysetType());
136 return APCArray::MakeSharedKeyset(ad, level, unserializeObj);
139 case KindOfObject:
140 if (val(cell).pobj->isCollection()) {
141 return APCCollection::Make(val(cell).pobj,
142 level,
143 unserializeObj,
144 pure);
146 return unserializeObj ? APCObject::Construct(val(cell).pobj, pure) :
147 APCString::MakeSerializedObject(apc_serialize(source, pure));
149 case KindOfResource:
150 case KindOfEnumClassLabel:
151 return APCArray::MakeSharedEmptyVec();
153 case KindOfClsMeth:
154 if (RO::EvalAPCSerializeClsMeth) {
155 auto const meth = val(cell).pclsmeth;
156 if (meth->getCls()->isPersistent()) {
157 auto const value = new APCTypedValue(meth);
158 return {value->getHandle(), sizeof(APCTypedValue)};
160 auto const value = new APCClsMeth(meth->getCls(), meth->getFunc());
161 return {value->getHandle(), sizeof(APCClsMeth)};
163 [[fallthrough]];
165 case KindOfRClsMeth:
166 return APCRClsMeth::Construct(val(cell).prclsmeth);
168 not_reached();
171 Variant APCHandle::toLocalHelper(bool pure) const {
172 assertx(!isTypedValue());
173 switch (m_kind) {
174 case APCKind::Uninit:
175 case APCKind::Null:
176 case APCKind::Bool:
177 case APCKind::Int:
178 case APCKind::Double:
179 case APCKind::PersistentFunc:
180 case APCKind::PersistentClass:
181 case APCKind::LazyClass:
182 case APCKind::PersistentClsMeth:
183 case APCKind::StaticArray:
184 case APCKind::StaticBespoke:
185 case APCKind::StaticString:
186 case APCKind::UncountedArray:
187 case APCKind::UncountedBespoke:
188 case APCKind::UncountedString:
189 not_reached();
191 case APCKind::FuncEntity:
192 return APCNamedFunc::fromHandle(this)->getEntityOrNull();
194 case APCKind::ClassEntity:
195 return APCNamedClass::fromHandle(this)->getEntityOrNull();
197 case APCKind::ClsMeth:
198 return APCClsMeth::fromHandle(this)->getEntityOrNull();
200 case APCKind::SerializedVec: {
201 auto const serVec = APCString::fromHandle(this)->getStringData();
202 auto const v = apc_unserialize(serVec->data(), serVec->size(), pure);
203 assertx(v.isVec());
204 return v;
206 case APCKind::SerializedDict: {
207 auto const serDict = APCString::fromHandle(this)->getStringData();
208 auto const v = apc_unserialize(serDict->data(), serDict->size(), pure);
209 assertx(v.isDict());
210 return v;
212 case APCKind::SerializedKeyset: {
213 auto const serKeyset = APCString::fromHandle(this)->getStringData();
214 auto const v = apc_unserialize(serKeyset->data(), serKeyset->size(), true /* irrelevant for arraykeys */);
215 assertx(v.isKeyset());
216 return v;
218 case APCKind::SharedVec:
219 return Variant::attach(
220 APCArray::fromHandle(this)->toLocalVec(pure)
222 case APCKind::SharedLegacyVec:
223 return Variant::attach(
224 APCArray::fromHandle(this)->toLocalLegacyVec(pure)
226 case APCKind::SharedDict:
227 return Variant::attach(
228 APCArray::fromHandle(this)->toLocalDict(pure)
230 case APCKind::SharedLegacyDict:
231 return Variant::attach(
232 APCArray::fromHandle(this)->toLocalLegacyDict(pure)
234 case APCKind::SharedKeyset:
235 return Variant::attach(
236 APCArray::fromHandle(this)->toLocalKeyset()
238 case APCKind::SerializedObject: {
239 auto const serObj = APCString::fromHandle(this)->getStringData();
240 return apc_unserialize(serObj->data(), serObj->size(), pure);
242 case APCKind::SharedCollection:
243 return APCCollection::fromHandle(this)->createObject(pure);
244 case APCKind::SharedObject:
245 return APCObject::MakeLocalObject(this, pure);
246 case APCKind::RFunc:
247 return APCRFunc::Make(this);
248 case APCKind::RClsMeth:
249 return APCRClsMeth::Make(this);
251 not_reached();
254 bool APCHandle::toLocalMayRaise() const {
255 switch (m_kind) {
256 case APCKind::Uninit:
257 case APCKind::Null:
258 case APCKind::Bool:
259 case APCKind::Int:
260 case APCKind::Double:
261 case APCKind::PersistentFunc:
262 case APCKind::PersistentClass:
263 case APCKind::LazyClass:
264 case APCKind::PersistentClsMeth:
265 case APCKind::StaticArray:
266 case APCKind::StaticBespoke:
267 case APCKind::StaticString:
268 case APCKind::UncountedArray:
269 case APCKind::UncountedBespoke:
270 case APCKind::UncountedString:
271 return false;
273 case APCKind::FuncEntity:
274 case APCKind::ClassEntity:
275 case APCKind::ClsMeth:
276 case APCKind::SerializedVec:
277 case APCKind::SerializedDict:
278 case APCKind::SerializedKeyset:
279 case APCKind::SerializedObject:
280 case APCKind::RFunc:
281 case APCKind::RClsMeth:
282 return true;
284 case APCKind::SharedVec:
285 case APCKind::SharedLegacyVec:
286 case APCKind::SharedDict:
287 case APCKind::SharedLegacyDict:
288 case APCKind::SharedKeyset:
289 return APCArray::fromHandle(this)->toLocalMayRaise();
291 case APCKind::SharedCollection:
292 return APCCollection::fromHandle(this)->toLocalMayRaise();
294 case APCKind::SharedObject:
295 return APCObject::fromHandle(this)->toLocalMayRaise();
297 not_reached();
300 void APCHandle::deleteShared() {
301 assertx(checkInvariants());
302 switch (m_kind) {
303 case APCKind::Uninit:
304 case APCKind::Null:
305 case APCKind::Bool:
306 return;
307 case APCKind::Int:
308 case APCKind::Double:
309 case APCKind::StaticArray:
310 case APCKind::StaticString:
311 case APCKind::PersistentFunc:
312 case APCKind::PersistentClass:
313 case APCKind::LazyClass:
314 case APCKind::PersistentClsMeth:
315 delete APCTypedValue::fromHandle(this);
316 return;
318 case APCKind::ClsMeth:
319 delete APCClsMeth::fromHandle(this);
320 return;
322 case APCKind::FuncEntity:
323 delete APCNamedFunc::fromHandle(this);
324 return;
326 case APCKind::ClassEntity:
327 delete APCNamedClass::fromHandle(this);
328 return;
330 case APCKind::SerializedVec:
331 case APCKind::SerializedDict:
332 case APCKind::SerializedKeyset:
333 case APCKind::SerializedObject:
334 APCString::Delete(APCString::fromHandle(this));
335 return;
337 case APCKind::SharedVec:
338 case APCKind::SharedLegacyVec:
339 case APCKind::SharedDict:
340 case APCKind::SharedLegacyDict:
341 case APCKind::SharedKeyset:
342 APCArray::Delete(this);
343 return;
345 case APCKind::SharedObject:
346 APCObject::Delete(this);
347 return;
349 case APCKind::SharedCollection:
350 APCCollection::Delete(this);
351 return;
353 case APCKind::RFunc:
354 APCRFunc::Delete(this);
355 return;
357 case APCKind::RClsMeth:
358 APCRClsMeth::Delete(this);
359 return;
361 case APCKind::StaticBespoke:
362 freeAPCBespoke(APCTypedValue::fromHandle(this));
363 return;
365 case APCKind::UncountedArray:
366 case APCKind::UncountedBespoke:
367 case APCKind::UncountedString:
368 assertx(false);
369 return;
371 not_reached();
374 bool APCHandle::checkInvariants() const {
375 switch (m_kind) {
376 case APCKind::Uninit:
377 assertx(m_type == KindOfUninit);
378 return true;
379 case APCKind::Null:
380 assertx(m_type == KindOfNull);
381 return true;
382 case APCKind::Bool:
383 assertx(m_type == KindOfBoolean);
384 return true;
385 case APCKind::Int:
386 assertx(m_type == KindOfInt64);
387 return true;
388 case APCKind::Double:
389 assertx(m_type == KindOfDouble);
390 return true;
391 case APCKind::PersistentFunc:
392 assertx(m_type == KindOfFunc);
393 return true;
394 case APCKind::PersistentClass:
395 assertx(m_type == KindOfClass);
396 return true;
397 case APCKind::LazyClass:
398 assertx(m_type == KindOfLazyClass);
399 return true;
400 case APCKind::PersistentClsMeth:
401 assertx(m_type == KindOfClsMeth);
402 return true;
403 case APCKind::StaticString:
404 case APCKind::UncountedString:
405 assertx(m_type == KindOfPersistentString);
406 return true;
407 case APCKind::StaticArray:
408 case APCKind::StaticBespoke:
409 case APCKind::UncountedArray:
410 case APCKind::UncountedBespoke:
411 assertx(m_type == KindOfPersistentVec ||
412 m_type == KindOfPersistentDict ||
413 m_type == KindOfPersistentKeyset);
414 return true;
415 case APCKind::FuncEntity:
416 case APCKind::ClassEntity:
417 case APCKind::ClsMeth:
418 case APCKind::RFunc:
419 case APCKind::RClsMeth:
420 case APCKind::SharedVec:
421 case APCKind::SharedLegacyVec:
422 case APCKind::SharedDict:
423 case APCKind::SharedLegacyDict:
424 case APCKind::SharedKeyset:
425 case APCKind::SharedObject:
426 case APCKind::SharedCollection:
427 case APCKind::SerializedVec:
428 case APCKind::SerializedDict:
429 case APCKind::SerializedKeyset:
430 case APCKind::SerializedObject:
431 assertx(m_type == kInvalidDataType);
432 return true;
434 not_reached();
435 return false;
438 void APCHandle::unreferenceRoot(size_t size) {
439 assertx(isSingletonKind() || m_unref_root_count++ == 0);
440 if (!isUncounted()) {
441 atomicDecRef();
442 } else if (APCTypedValue::UseStringHazardPointers()) {
443 APCTypedValue::fromHandle(this)->deleteUncounted();
444 } else {
445 g_context->enqueueAPCHandle(this, size);
449 //////////////////////////////////////////////////////////////////////