2 +----------------------------------------------------------------------+
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.
25 #include "hphp/runtime/base/types.h"
28 ///////////////////////////////////////////////////////////////////////////////
33 * Assertions on Cells and TypedValues. Should usually only happen
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);
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
)) {
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
;
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
)) {
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
));
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
;
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
) {
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
;
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
;
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
;
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
;
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
;
337 tvRefcountedDecRefHelper(oldType
, oldDatum
);
340 // Assumes 'to' is live
341 inline void tvUnset(TypedValue
* to
) {
342 tvRefcountedDecRef(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
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
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
)) {
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();
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_