2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 2.00 of the Zend license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.zend.com/license/2_00.txt. |
12 | If you did not receive a copy of the Zend license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@zend.com so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/base/complex_types.h"
19 #include "hphp/runtime/base/dummy_resource.h"
20 #include "hphp/runtime/base/type_conversions.h"
21 #include "hphp/runtime/base/zend-functions.h"
23 #include "hphp/system/systemlib.h"
27 //////////////////////////////////////////////////////////////////////
29 bool cellIsPlausible(const Cell cell
) {
30 assert(cell
.m_type
!= KindOfRef
);
32 auto assertPtr
= [](void* ptr
) {
33 assert(ptr
&& (uintptr_t(ptr
) % sizeof(ptr
) == 0));
36 switch (cell
.m_type
) {
41 assert(cell
.m_data
.num
== 0 || cell
.m_data
.num
== 1);
46 case KindOfStaticString
:
47 assertPtr(cell
.m_data
.pstr
);
48 assert(cell
.m_data
.pstr
->isStatic());
51 assertPtr(cell
.m_data
.pstr
);
52 assert(is_refcount_realistic(cell
.m_data
.pstr
->getCount()));
55 assertPtr(cell
.m_data
.parr
);
56 assert(is_refcount_realistic(cell
.m_data
.parr
->getCount()));
59 assertPtr(cell
.m_data
.pobj
);
60 assert(!cell
.m_data
.pobj
->isStatic());
63 assertPtr(cell
.m_data
.pres
);
64 assert(!cell
.m_data
.pres
->isStatic());
67 assert(!"KindOfRef found in a Cell");
75 bool tvIsPlausible(TypedValue tv
) {
76 if (tv
.m_type
== KindOfRef
) {
77 assert(tv
.m_data
.pref
);
78 assert(uintptr_t(tv
.m_data
.pref
) % sizeof(void*) == 0);
79 assert(is_refcount_realistic(tv
.m_data
.pref
->getCount()));
80 tv
= *tv
.m_data
.pref
->tv();
82 return cellIsPlausible(tv
);
85 bool refIsPlausible(const Ref ref
) {
86 assert(ref
.m_type
== KindOfRef
);
87 return tvIsPlausible(ref
);
90 inline void tvUnboxIfNeeded(TypedValue
*tv
) {
91 if (tv
->m_type
== KindOfRef
) {
96 void tvCastToBooleanInPlace(TypedValue
* tv
) {
97 assert(tvIsPlausible(*tv
));
100 switch (tv
->m_type
) {
102 case KindOfNull
: b
= false; break;
103 case KindOfBoolean
: return;
104 case KindOfInt64
: b
= (tv
->m_data
.num
!= 0LL); break;
105 case KindOfDouble
: b
= (tv
->m_data
.dbl
!= 0); break;
106 case KindOfStaticString
: b
= tv
->m_data
.pstr
->toBoolean(); break;
107 case KindOfString
: b
= tv
->m_data
.pstr
->toBoolean(); tvDecRefStr(tv
); break;
108 case KindOfArray
: b
= (!tv
->m_data
.parr
->empty()); tvDecRefArr(tv
); break;
109 case KindOfObject
: b
= tv
->m_data
.pobj
->o_toBoolean();
112 case KindOfResource
: b
= tv
->m_data
.pres
->o_toBoolean();
115 default: assert(false); b
= false; break;
118 tv
->m_type
= KindOfBoolean
;
121 void tvCastToDoubleInPlace(TypedValue
* tv
) {
122 assert(tvIsPlausible(*tv
));
126 switch (tv
->m_type
) {
128 case KindOfNull
: d
= 0.0; break;
129 case KindOfBoolean
: assert(tv
->m_data
.num
== 0LL || tv
->m_data
.num
== 1LL);
130 case KindOfInt64
: d
= (double)(tv
->m_data
.num
); break;
131 case KindOfDouble
: return;
132 case KindOfStaticString
: d
= tv
->m_data
.pstr
->toDouble(); break;
133 case KindOfString
: d
= tv
->m_data
.pstr
->toDouble(); tvDecRefStr(tv
); break;
135 d
= (double)(tv
->m_data
.parr
->empty() ? 0LL : 1LL);
140 d
= tv
->m_data
.pobj
->o_toDouble();
144 case KindOfResource
: {
145 d
= tv
->m_data
.pres
->o_toDouble();
149 default: assert(false); d
= 0.0; break;
152 tv
->m_type
= KindOfDouble
;
155 void cellCastToInt64InPlace(Cell
* cell
) {
156 assert(cellIsPlausible(*cell
));
159 switch (cell
->m_type
) {
162 cell
->m_data
.num
= 0LL;
165 assert(cell
->m_data
.num
== 0LL || cell
->m_data
.num
== 1LL);
166 cell
->m_type
= KindOfInt64
;
171 i
= toInt64(cell
->m_data
.dbl
);
174 case KindOfStaticString
: i
= (cell
->m_data
.pstr
->toInt64()); break;
176 i
= cell
->m_data
.pstr
->toInt64();
181 i
= cell
->m_data
.parr
->empty() ? 0 : 1;
185 i
= cell
->m_data
.pobj
->o_toInt64();
189 i
= cell
->m_data
.pres
->o_toInt64();
195 cell
->m_data
.num
= i
;
196 cell
->m_type
= KindOfInt64
;
199 void tvCastToInt64InPlace(TypedValue
* tv
) {
200 assert(tvIsPlausible(*tv
));
202 cellCastToInt64InPlace(tv
);
205 double tvCastToDouble(TypedValue
* tv
) {
206 assert(tvIsPlausible(*tv
));
207 if (tv
->m_type
== KindOfRef
) {
208 tv
= tv
->m_data
.pref
->tv();
216 assert(tv
->m_data
.num
== 0LL || tv
->m_data
.num
== 1LL);
219 return (double)(tv
->m_data
.num
);
221 return tv
->m_data
.dbl
;
222 case KindOfStaticString
:
224 return tv
->m_data
.pstr
->toDouble();
226 return tv
->m_data
.parr
->empty() ? 0.0 : 1.0;
228 return tv
->m_data
.pobj
->o_toDouble();
230 return tv
->m_data
.pres
->o_toDouble();
241 void tvCastToStringInPlace(TypedValue
* tv
) {
242 assert(tvIsPlausible(*tv
));
245 switch (tv
->m_type
) {
247 case KindOfNull
: s
= empty_string
.get(); goto static_string
;
249 s
= tv
->m_data
.num
? s_1
.get() : empty_string
.get();
251 case KindOfInt64
: s
= buildStringData(tv
->m_data
.num
); break;
252 case KindOfDouble
: s
= buildStringData(tv
->m_data
.dbl
); break;
253 case KindOfStaticString
:
254 case KindOfString
: return;
260 // For objects, we fall back on the Variant machinery
261 tvAsVariant(tv
) = tv
->m_data
.pobj
->invokeToString();
264 // For resources, we fall back on the Variant machinery
265 tvAsVariant(tv
) = tv
->m_data
.pres
->o_toString();
273 tv
->m_type
= KindOfString
;
277 tv
->m_type
= KindOfStaticString
;
280 StringData
* tvCastToString(TypedValue
* tv
) {
281 assert(tvIsPlausible(*tv
));
282 if (tv
->m_type
== KindOfRef
) {
283 tv
= tv
->m_data
.pref
->tv();
287 switch (tv
->m_type
) {
289 case KindOfNull
: return empty_string
.get();
290 case KindOfBoolean
: return tv
->m_data
.num
? s_1
.get() : empty_string
.get();
291 case KindOfInt64
: s
= buildStringData(tv
->m_data
.num
); break;
292 case KindOfDouble
: s
= buildStringData(tv
->m_data
.dbl
); break;
293 case KindOfStaticString
: return tv
->m_data
.pstr
;
294 case KindOfString
: s
= tv
->m_data
.pstr
; break;
295 case KindOfArray
: return s_Array
.get();
296 case KindOfObject
: return tv
->m_data
.pobj
->invokeToString().detach();
297 case KindOfResource
: return tv
->m_data
.pres
->o_toString().detach();
298 default: not_reached();
305 void tvCastToArrayInPlace(TypedValue
* tv
) {
306 assert(tvIsPlausible(*tv
));
309 switch (tv
->m_type
) {
311 case KindOfNull
: a
= ArrayData::Create(); break;
315 case KindOfStaticString
: a
= ArrayData::Create(tvAsVariant(tv
)); break;
317 a
= ArrayData::Create(tvAsVariant(tv
));
321 case KindOfArray
: return;
323 // For objects, we fall back on the Variant machinery
324 tvAsVariant(tv
) = tv
->m_data
.pobj
->o_toArray();
327 case KindOfResource
: {
328 // For resources, we fall back on the Variant machinery
329 tvAsVariant(tv
) = tv
->m_data
.pres
->o_toArray();
332 default: assert(false); a
= ArrayData::Create(); break;
335 tv
->m_type
= KindOfArray
;
336 tv
->m_data
.parr
->incRefCount();
339 void tvCastToObjectInPlace(TypedValue
* tv
) {
340 assert(tvIsPlausible(*tv
));
343 switch (tv
->m_type
) {
345 case KindOfNull
: o
= SystemLib::AllocStdClassObject(); break;
349 case KindOfStaticString
: {
350 o
= SystemLib::AllocStdClassObject();
351 o
->o_set(s_scalar
, tvAsVariant(tv
));
355 o
= SystemLib::AllocStdClassObject();
356 o
->o_set(s_scalar
, tvAsVariant(tv
));
361 // For arrays, we fall back on the Variant machinery
362 tvAsVariant(tv
) = tv
->m_data
.parr
->toObject();
365 case KindOfObject
: return;
366 case KindOfResource
: return;
367 default: assert(false); o
= SystemLib::AllocStdClassObject(); break;
370 tv
->m_type
= KindOfObject
;
371 tv
->m_data
.pobj
->incRefCount();
374 void tvCastToResourceInPlace(TypedValue
* tv
) {
375 assert(tvIsPlausible(*tv
));
377 switch (tv
->m_type
) {
383 case KindOfStaticString
:
397 tv
->m_type
= KindOfResource
;
398 tv
->m_data
.pres
= NEWOBJ(DummyResource
);
399 tv
->m_data
.pres
->incRefCount();
403 bool tvCoerceParamToBooleanInPlace(TypedValue
* tv
) {
404 assert(tvIsPlausible(*tv
));
406 if (tv
->m_type
== KindOfArray
|| tv
->m_type
== KindOfObject
||
407 tv
->m_type
== KindOfResource
) {
410 tvCastToBooleanInPlace(tv
);
414 bool tvCanBeCoercedToNumber(TypedValue
* tv
) {
415 switch (tv
->m_type
) {
416 case KindOfStaticString
:
421 type
= is_numeric_string(s
->data(), s
->size(), nullptr, nullptr);
422 if (type
!= KindOfDouble
&& type
!= KindOfInt64
) {
436 bool tvCoerceParamToInt64InPlace(TypedValue
* tv
) {
437 assert(tvIsPlausible(*tv
));
439 if (!tvCanBeCoercedToNumber(tv
)) {
442 tvCastToInt64InPlace(tv
);
446 bool tvCoerceParamToDoubleInPlace(TypedValue
* tv
) {
447 assert(tvIsPlausible(*tv
));
449 if (!tvCanBeCoercedToNumber(tv
)) {
452 tvCastToDoubleInPlace(tv
);
456 bool tvCoerceParamToStringInPlace(TypedValue
* tv
) {
457 assert(tvIsPlausible(*tv
));
459 switch (tv
->m_type
) {
463 if (tv
->m_data
.pobj
->hasToString()) {
464 tvAsVariant(tv
) = tv
->m_data
.pobj
->invokeToString();
473 tvCastToStringInPlace(tv
);
477 bool tvCoerceParamToArrayInPlace(TypedValue
* tv
) {
478 assert(tvIsPlausible(*tv
));
480 if (tv
->m_type
== KindOfArray
) {
482 } else if (tv
->m_type
== KindOfObject
) {
483 tvAsVariant(tv
) = tv
->m_data
.pobj
->o_toArray();
485 } else if (tv
->m_type
== KindOfResource
) {
486 tvAsVariant(tv
) = tv
->m_data
.pres
->o_toArray();
492 bool tvCoerceParamToObjectInPlace(TypedValue
* tv
) {
493 assert(tvIsPlausible(*tv
));
495 return tv
->m_type
== KindOfObject
;
498 bool tvCoerceParamToResourceInPlace(TypedValue
* tv
) {
499 assert(tvIsPlausible(*tv
));
501 return tv
->m_type
== KindOfResource
;
504 ///////////////////////////////////////////////////////////////////////////////