Add a cellIsPlausible assertion
[hiphop-php.git] / hphp / runtime / base / tv_helpers.h
blob116aefb812fd1fc1862c3f9c516b7842b546186e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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_TV_HELPERS_H_
18 #define incl_HPHP_TV_HELPERS_H_
20 #ifndef incl_HPHP_INSIDE_HPHP_COMPLEX_TYPES_H_
21 #error Directly including 'tv_helpers.h' is prohibited. \
22 Include 'complex_types.h' instead.
23 #endif
25 #include "hphp/runtime/base/types.h"
27 namespace HPHP {
28 ///////////////////////////////////////////////////////////////////////////////
30 class Variant;
33 * Assertions on Cells and TypedValues. Should usually only happen
34 * inside an assert().
36 bool tvIsPlausible(const TypedValue*);
37 bool cellIsPlausible(const Cell*);
39 // Assumes 'data' is live
40 // Assumes 'IS_REFCOUNTED_TYPE(type)'
41 void tvDecRefHelper(DataType type, uint64_t datum);
43 inline bool tvWillBeReleased(TypedValue* tv) {
44 return IS_REFCOUNTED_TYPE(tv->m_type) &&
45 tv->m_data.pstr->getCount() <= 1;
48 // Assumes 'tv' is live
49 inline void tvRefcountedDecRefCell(TypedValue* tv) {
50 assert(tvIsPlausible(tv));
51 if (IS_REFCOUNTED_TYPE(tv->m_type)) {
52 tvDecRefHelper(tv->m_type, tv->m_data.num);
56 inline void tvDecRefStr(TypedValue* tv) {
57 assert(tv->m_type == KindOfString);
58 decRefStr(tv->m_data.pstr);
61 inline void tvDecRefArr(TypedValue* tv) {
62 assert(tv->m_type == KindOfArray);
63 decRefArr(tv->m_data.parr);
66 inline void tvDecRefObj(TypedValue* tv) {
67 assert(tv->m_type == KindOfObject);
68 decRefObj(tv->m_data.pobj);
71 // Assumes 'r' is live and points to a RefData
72 inline void tvDecRefRefInternal(RefData* r) {
73 assert(tvIsPlausible(r->tv()));
74 assert(r->tv()->m_type != KindOfRef);
75 assert(r->_count > 0);
76 decRefRef(r);
79 // Assumes 'tv' is live
80 inline void tvDecRefRef(TypedValue* tv) {
81 assert(tv->m_type == KindOfRef);
82 tvDecRefRefInternal(tv->m_data.pref);
85 // Assumes 'tv' is live
86 inline void tvRefcountedDecRefHelper(DataType type, uint64_t datum) {
87 if (IS_REFCOUNTED_TYPE(type)) {
88 tvDecRefHelper(type, datum);
92 inline void tvRefcountedDecRef(TypedValue v) {
93 return tvRefcountedDecRefHelper(v.m_type, v.m_data.num);
96 // Assumes 'tv' is live
97 // Assumes 'IS_REFCOUNTED_TYPE(tv->m_type)'
98 inline void tvDecRef(TypedValue* tv) {
99 tvDecRefHelper(tv->m_type, tv->m_data.num);
102 // Assumes 'tv' is live
103 ALWAYS_INLINE inline void tvRefcountedDecRef(TypedValue* tv) {
104 if (IS_REFCOUNTED_TYPE(tv->m_type)) {
105 tvDecRef(tv);
109 // decref when the count is known not to reach zero
110 ALWAYS_INLINE inline void tvDecRefOnly(TypedValue* tv) {
111 assert(!tvWillBeReleased(tv));
112 if (IS_REFCOUNTED_TYPE(tv->m_type)) {
113 tv->m_data.pstr->decRefCount();
117 // tvBoxHelper sets the refcount of the newly allocated inner cell to 1
118 inline RefData* tvBoxHelper(DataType type, uint64_t datum) {
119 return NEW(RefData)(type, datum);
122 // Assumes 'tv' is live
123 inline TypedValue* tvBox(TypedValue* tv) {
124 assert(tvIsPlausible(tv));
125 assert(tv->m_type != KindOfRef);
126 tv->m_data.pref = tvBoxHelper(tv->m_type, tv->m_data.num);
127 tv->m_type = KindOfRef;
128 return tv;
131 // Assumes 'tv' is live
133 // Assumes 'IS_REFCOUNTED_TYPE(tv->m_type)'
134 inline void tvIncRef(TypedValue* tv) {
135 assert(tvIsPlausible(tv));
136 assert(IS_REFCOUNTED_TYPE(tv->m_type));
137 tv->m_data.pstr->incRefCount();
140 ALWAYS_INLINE inline void tvRefcountedIncRef(TypedValue* tv) {
141 assert(tvIsPlausible(tv));
142 if (IS_REFCOUNTED_TYPE(tv->m_type)) {
143 tvIncRef(tv);
147 // Assumes 'tv' is live
148 // Assumes 'IS_REFCOUNTED_TYPE(tv->m_type)'
149 // Assumes 'tv' is not shared (ie KindOfRef or KindOfObject)
150 inline void tvIncRefNotShared(TypedValue* tv) {
151 assert(tv->m_type == KindOfObject || tv->m_type == KindOfRef);
152 tv->m_data.pobj->incRefCount();
155 // Assumes 'tv' is live
156 // Assumes 'tv.m_type == KindOfRef'
157 inline void tvUnbox(TypedValue* tv) {
158 assert(tvIsPlausible(tv));
159 assert(tv->m_type == KindOfRef);
160 RefData* r = tv->m_data.pref;
161 TypedValue* innerCell = r->tv();
162 tv->m_data.num = innerCell->m_data.num;
163 tv->m_type = innerCell->m_type;
164 tvRefcountedIncRef(tv);
165 tvDecRefRefInternal(r);
166 assert(tvIsPlausible(tv));
169 // Assumes 'fr' is live and 'to' is dead. Store a reference to 'fr',
170 // as a Cell, into 'to'.
171 inline void tvReadCell(const TypedValue* fr, TypedValue* to) {
172 assert(tvIsPlausible(fr));
173 if (fr->m_type != KindOfRef) {
174 memcpy(to, fr, sizeof(TypedValue));
175 } else {
176 TypedValue* fr2 = fr->m_data.pref->tv();
177 to->m_data.num = fr2->m_data.num;
178 to->m_type = fr2->m_type;
180 tvRefcountedIncRef(to);
183 // Assumes 'fr' is live and 'to' is dead
184 // Assumes 'fr->m_type != KindOfRef'
185 // NOTE: this helper will not modify to->_count
186 inline void tvDupCell(const TypedValue* fr, TypedValue* to) {
187 assert(tvIsPlausible(fr));
188 assert(fr->m_type != KindOfRef);
189 to->m_data.num = fr->m_data.num;
190 to->m_type = fr->m_type;
191 tvRefcountedIncRef(to);
194 // Assumes 'fr' is live and 'to' is dead
195 // Assumes 'fr->m_type == KindOfRef'
196 // NOTE: this helper will not modify to->_count
197 inline void tvDupVar(const TypedValue* fr, TypedValue* to) {
198 assert(tvIsPlausible(fr));
199 assert(fr->m_type == KindOfRef);
200 to->m_data.num = fr->m_data.num;
201 to->m_type = KindOfRef;
202 tvIncRefNotShared(to);
205 // Assumes 'fr' is live and 'to' is dead
206 inline void tvDupRef(RefData* fr, TypedValue* to) {
207 assert(tvIsPlausible(fr->tv()));
208 to->m_data.pref = fr;
209 to->m_type = KindOfRef;
210 fr->incRefCount();
213 // Assumes 'fr' is live and 'to' is dead
214 // After this operation, 'fr' is dead and 'to' live.
215 inline void tvTeleport(const TypedValue* fr, TypedValue* to) {
216 assert(tvIsPlausible(fr));
217 to->m_data.num = fr->m_data.num;
218 to->m_type = fr->m_type;
221 // Assumes 'fr' is live and 'to' is dead
222 // NOTE: this helper does not modify to->_count
223 inline void tvDup(const TypedValue* fr, TypedValue* to) {
224 tvTeleport(fr, to);
225 tvRefcountedIncRef(to);
228 // Assumes 'tv' is dead
229 // NOTE: this helper does not modify tv->_count
230 inline void tvWriteNull(TypedValue* tv) {
231 tv->m_type = KindOfNull;
234 // Assumes 'tv' is dead
235 // NOTE: this helper does not modify tv->_count
236 inline void tvWriteUninit(TypedValue* tv) {
237 tv->m_type = KindOfUninit;
240 // Assumes 'tv' is dead
241 inline void tvWriteObject(ObjectData* pobj, TypedValue* tv) {
242 tv->m_type = KindOfObject;
243 tv->m_data.pobj = pobj;
244 tvIncRef(tv);
247 // conditionally unbox tv
248 inline Cell* tvToCell(TypedValue* tv) {
249 return LIKELY(tv->m_type != KindOfRef) ? tv : tv->m_data.pref->tv();
252 // conditionally unbox tv, preserve constness.
253 inline const Cell* tvToCell(const TypedValue* tv) {
254 return LIKELY(tv->m_type != KindOfRef) ? tv : tv->m_data.pref->tv();
257 template <bool respectRef>
258 inline void tvSetImpl(const TypedValue* fr, TypedValue* to) {
259 assert(fr->m_type != KindOfRef);
260 if (respectRef) to = tvToCell(to);
261 DataType oldType = to->m_type;
262 uint64_t oldDatum = to->m_data.num;
263 tvDupCell(fr, to);
264 tvRefcountedDecRefHelper(oldType, oldDatum);
267 // Assumes 'to' and 'fr' are live
268 // Assumes that 'fr->m_type != KindOfRef'
269 // If 'to->m_type == KindOfRef', this will perform the set
270 // operation on the inner cell (to->m_data.pref)
271 inline void tvSet(const TypedValue* fr, TypedValue* to) {
272 tvSetImpl<true>(fr, to);
275 // Same as tvSet, but does not dereference 'to' if it's KindOfRef.
276 inline void tvSetIgnoreRef(const TypedValue* fr, TypedValue* to) {
277 tvSetImpl<false>(fr, to);
280 template <bool respectRef>
281 inline void tvSetNullImpl(TypedValue* to) {
282 if (respectRef) to = tvToCell(to);
283 DataType oldType = to->m_type;
284 uint64_t oldDatum = to->m_data.num;
285 tvWriteNull(to);
286 tvRefcountedDecRefHelper(oldType, oldDatum);
289 // Assumes 'to' is live
290 // If 'to->m_type == KindOfRef', this will perform the set
291 // operation on the inner cell (to->m_data.pref)
292 inline void tvSetNull(TypedValue* to) {
293 tvSetNullImpl<true>(to);
296 // Same as tvSetNull, but does not dereference 'to' if it's KindOfRef.
297 inline void tvSetNullIgnoreRef(TypedValue* to) {
298 tvSetNullImpl<false>(to);
301 template <bool respectRef>
302 inline void tvSetObjectImpl(ObjectData* pobj, TypedValue* to) {
303 if (respectRef) to = tvToCell(to);
304 DataType oldType = to->m_type;
305 uint64_t oldDatum = to->m_data.num;
306 tvWriteObject(pobj, to);
307 tvRefcountedDecRefHelper(oldType, oldDatum);
310 // Assumes 'to' is live
311 // If 'to->m_type == KindOfRef', this will perform the set
312 // operation on the inner cell (to->m_data.pref)
313 inline void tvSetObject(ObjectData* pobj, TypedValue* to) {
314 tvSetObjectImpl<true>(pobj, to);
317 // Same as tvSetObject, but does not dereference 'to' if it's KindOfRef.
318 inline void tvSetObjectIgnoreRef(ObjectData* pobj, TypedValue* to) {
319 tvSetObjectImpl<false>(pobj, to);
322 // Assumes 'to' and 'fr' are live
323 // Assumes that 'fr->m_type == KindOfRef'
324 inline void tvBind(TypedValue * fr, TypedValue * to) {
325 assert(fr->m_type == KindOfRef);
326 DataType oldType = to->m_type;
327 uint64_t oldDatum = to->m_data.num;
328 tvDupVar(fr, to);
329 tvRefcountedDecRefHelper(oldType, oldDatum);
332 // Assumes 'to' and 'fr' are live
333 inline void tvBindRef(RefData* fr, TypedValue* to) {
334 DataType oldType = to->m_type;
335 uint64_t oldDatum = to->m_data.num;
336 tvDupRef(fr, to);
337 tvRefcountedDecRefHelper(oldType, oldDatum);
340 // Assumes 'to' is live
341 inline void tvUnset(TypedValue * to) {
342 tvRefcountedDecRef(to);
343 tvWriteUninit(to);
346 // Assumes `fr' is dead and binds it using KindOfIndirect to `to'.
347 inline void tvBindIndirect(TypedValue* fr, TypedValue* to) {
348 assert(tvIsPlausible(to));
349 fr->m_type = KindOfIndirect;
350 fr->m_data.pind = to;
353 // If a TypedValue is KindOfIndirect, dereference to the inner
354 // TypedValue.
355 inline TypedValue* tvDerefIndirect(TypedValue* tv) {
356 return tv->m_type == KindOfIndirect ? tv->m_data.pind : tv;
358 inline const TypedValue* tvDerefIndirect(const TypedValue* tv) {
359 return tvDerefIndirect(const_cast<TypedValue*>(tv));
363 * Returns true if this tv is not a ref-counted type, or if it is a
364 * ref-counted type and the object pointed to is static.
366 inline bool tvIsStatic(const TypedValue* tv) {
367 assert(tvIsPlausible(tv));
368 return !IS_REFCOUNTED_TYPE(tv->m_type) ||
369 tv->m_data.pref->_count == RefCountStaticValue;
373 * tvAsVariant and tvAsCVarRef serve as escape hatches that allow us to call
374 * into the Variant machinery. Ideally we will use these as little as possible
375 * in the long term.
378 // Assumes 'tv' is live
379 inline Variant& tvAsVariant(TypedValue* tv) {
380 // Avoid treating uninitialized TV's as variants. We have some slightly
381 // perverse, but defensible uses where we pass in NULL (and later check
382 // a Variant* against NULL) so tolerate it.
383 assert(nullptr == tv || tvIsPlausible(tv));
384 return *(Variant*)(tv);
387 inline Variant& tvAsUninitializedVariant(TypedValue* tv) {
388 // A special case, for use when constructing a variant and we don't
389 // assume initialization.
390 return *(Variant*)(tv);
393 // Assumes 'tv' is live
394 inline const Variant& tvAsCVarRef(const TypedValue* tv) {
395 return *(const Variant*)(tv);
398 // Assumes 'tv' is live
399 inline Variant& tvCellAsVariant(TypedValue* tv) {
400 assert(tv->m_type != KindOfRef);
401 return *(Variant*)(tv);
404 // Assumes 'tv' is live
405 inline const Variant& tvCellAsCVarRef(const TypedValue* tv) {
406 assert(tv->m_type != KindOfRef);
407 return *(const Variant*)(tv);
410 // Assumes 'tv' is live
411 inline Variant& tvVarAsVariant(TypedValue* tv) {
412 assert(tv->m_type == KindOfRef);
413 return *(Variant*)(tv);
416 // Assumes 'tv' is live
417 inline const Variant& tvVarAsCVarRef(const TypedValue* tv) {
418 assert(tv->m_type == KindOfRef);
419 return *(const Variant*)(tv);
422 inline bool tvIsStronglyBound(const TypedValue* tv) {
423 return (tv->m_type == KindOfRef && tv->m_data.pref->_count > 1);
426 // Assumes 'fr' is live and 'to' is dead, and does not mutate to->_count
427 inline void tvDupFlattenVars(const TypedValue* fr, TypedValue* to,
428 const ArrayData* container) {
429 if (LIKELY(fr->m_type != KindOfRef)) {
430 tvDupCell(fr, to);
431 } else if (fr->m_data.pref->_count <= 1 &&
432 (!container || fr->m_data.pref->tv()->m_data.parr != container)) {
433 fr = fr->m_data.pref->tv();
434 tvDupCell(fr, to);
435 } else {
436 tvDupVar(fr, to);
440 inline bool tvIsString(const TypedValue* tv) {
441 return (tv->m_type & KindOfStringBit) != 0;
444 void tvUnboxIfNeeded(TypedValue* tv);
447 * Convert a cell to a boolean, without changing the Cell.
449 bool cellToBool(const Cell*);
452 * TypedValue conversions that update the tv in place (decrefing and
453 * old value, if necessary).
455 void tvCastToBooleanInPlace(TypedValue* tv);
456 void tvCastToInt64InPlace(TypedValue* tv, int base = 10);
457 int64_t tvCastToInt64(TypedValue* tv, int base = 10);
458 void tvCastToDoubleInPlace(TypedValue* tv);
459 void tvCastToStringInPlace(TypedValue* tv);
460 StringData* tvCastToString(TypedValue* tv);
461 void tvCastToArrayInPlace(TypedValue* tv);
462 void tvCastToObjectInPlace(TypedValue* tv);
464 bool tvCanBeCoercedToNumber(TypedValue* tv);
465 bool tvCoerceParamToBooleanInPlace(TypedValue* tv);
466 bool tvCoerceParamToInt64InPlace(TypedValue* tv);
467 bool tvCoerceParamToDoubleInPlace(TypedValue* tv);
468 bool tvCoerceParamToStringInPlace(TypedValue* tv);
469 bool tvCoerceParamToArrayInPlace(TypedValue* tv);
470 bool tvCoerceParamToObjectInPlace(TypedValue* tv);
472 typedef void(*RawDestructor)(void*);
473 extern const RawDestructor g_destructors[kDestrTableSize];
475 ///////////////////////////////////////////////////////////////////////////////
478 #include "hphp/runtime/base/tv_helpers-inl.h"
480 #endif // incl_HPHP_TV_HELPERS_H_