2 +----------------------------------------------------------------------+
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/base/array-data.h"
18 #include "hphp/runtime/base/array-init.h"
19 #include "hphp/runtime/base/array-iterator.h"
20 #include "hphp/runtime/base/collections.h"
21 #include "hphp/runtime/base/datatype.h"
22 #include "hphp/runtime/base/double-to-int64.h"
23 #include "hphp/runtime/base/dummy-resource.h"
24 #include "hphp/runtime/base/mixed-array.h"
25 #include "hphp/runtime/base/object-data.h"
26 #include "hphp/runtime/base/packed-array.h"
27 #include "hphp/runtime/base/resource-data.h"
28 #include "hphp/runtime/base/runtime-error.h"
29 #include "hphp/runtime/base/runtime-option.h"
30 #include "hphp/runtime/base/set-array.h"
31 #include "hphp/runtime/base/string-data.h"
32 #include "hphp/runtime/base/tv-mutate.h"
33 #include "hphp/runtime/base/tv-refcount.h"
34 #include "hphp/runtime/base/tv-variant.h"
35 #include "hphp/runtime/base/tv-val.h"
36 #include "hphp/runtime/base/type-array.h"
37 #include "hphp/runtime/base/type-object.h"
38 #include "hphp/runtime/base/type-string.h"
39 #include "hphp/runtime/base/type-variant.h"
40 #include "hphp/runtime/base/typed-value.h"
42 #include "hphp/runtime/vm/class-meth-data-ref.h"
43 #include "hphp/runtime/vm/func.h"
44 #include "hphp/runtime/vm/vm-regs.h"
46 #include "hphp/system/systemlib.h"
48 #include "hphp/util/assertions.h"
52 ///////////////////////////////////////////////////////////////////////////////
55 enable_if_lval_t
<T
, void> tvCastToBooleanInPlace(T tv
) {
56 assertx(tvIsPlausible(*tv
));
70 b
= (val(tv
).num
!= 0LL);
74 b
= (val(tv
).dbl
!= 0);
77 case KindOfPersistentString
:
78 b
= val(tv
).pstr
->toBoolean();
82 b
= val(tv
).pstr
->toBoolean();
86 case KindOfPersistentDArray
:
87 case KindOfPersistentVArray
:
88 case KindOfPersistentVec
:
89 case KindOfPersistentDict
:
90 case KindOfPersistentKeyset
:
91 case KindOfPersistentArray
:
92 b
= !val(tv
).parr
->empty();
101 b
= !val(tv
).parr
->empty();
106 b
= val(tv
).pobj
->toBoolean();
111 b
= val(tv
).pres
->data()->o_toBoolean();
123 raise_convert_record_to_type("bool");
129 type(tv
) = KindOfBoolean
;
132 bool tvCastToBoolean(TypedValue tv
) {
133 assertx(tvIsPlausible(tv
));
138 enable_if_lval_t
<T
, void> tvCastToDoubleInPlace(T tv
) {
139 assertx(tvIsPlausible(*tv
));
150 assertx(val(tv
).num
== 0LL || val(tv
).num
== 1LL);
153 d
= (double)(val(tv
).num
);
159 case KindOfPersistentString
:
160 d
= val(tv
).pstr
->toDouble();
164 d
= val(tv
).pstr
->toDouble();
168 case KindOfPersistentDArray
:
169 case KindOfPersistentVArray
:
170 case KindOfPersistentVec
:
171 case KindOfPersistentDict
:
172 case KindOfPersistentKeyset
:
173 case KindOfPersistentArray
:
174 d
= val(tv
).parr
->empty() ? 0 : 1;
183 d
= val(tv
).parr
->empty() ? 0 : 1;
188 d
= val(tv
).pobj
->toDouble();
193 d
= val(tv
).pres
->data()->o_toDouble();
198 if (RuntimeOption::EvalRaiseFuncConversionWarning
) {
199 raise_warning("Func to double conversion");
201 d
= val(tv
).pfunc
->name()->toDouble();
205 d
= classToStringHelper(val(tv
).pclass
)->toDouble();
209 raiseClsMethConvertWarningHelper("double");
215 raise_convert_record_to_type("double");
221 type(tv
) = KindOfDouble
;
225 enable_if_lval_t
<T
, void> tvCastToInt64InPlace(T tv
) {
226 assertx(tvIsPlausible(*tv
));
227 assertx(tvIsPlausible(*tv
));
237 assertx(val(tv
).num
== 0LL || val(tv
).num
== 1LL);
238 type(tv
) = KindOfInt64
;
244 i
= double_to_int64(val(tv
).dbl
);
247 case KindOfPersistentString
:
248 i
= val(tv
).pstr
->toInt64();
252 i
= val(tv
).pstr
->toInt64();
256 case KindOfPersistentDArray
:
257 case KindOfPersistentVArray
:
258 case KindOfPersistentVec
:
259 case KindOfPersistentDict
:
260 case KindOfPersistentKeyset
:
261 case KindOfPersistentArray
:
262 i
= val(tv
).parr
->empty() ? 0 : 1;
271 i
= val(tv
).parr
->empty() ? 0 : 1;
276 i
= val(tv
).pobj
->toInt64();
281 i
= val(tv
).pres
->data()->o_toInt64();
286 i
= funcToInt64Helper(val(tv
).pfunc
);
290 i
= classToStringHelper(val(tv
).pclass
)->toInt64();
294 raiseClsMethConvertWarningHelper("int");
300 raise_convert_record_to_type("int");
306 type(tv
) = KindOfInt64
;
309 int64_t tvCastToInt64(TypedValue tv
) {
310 assertx(tvIsPlausible(tv
));
314 double tvCastToDouble(TypedValue tv
) {
315 assertx(tvIsPlausible(tv
));
322 assertx(tv
.m_data
.num
== 0LL || tv
.m_data
.num
== 1LL);
325 return (double)(tv
.m_data
.num
);
328 return tv
.m_data
.dbl
;
330 case KindOfPersistentString
:
332 return tv
.m_data
.pstr
->toDouble();
334 case KindOfPersistentDArray
:
336 case KindOfPersistentVArray
:
338 case KindOfPersistentVec
:
340 case KindOfPersistentDict
:
342 case KindOfPersistentKeyset
:
344 case KindOfPersistentArray
:
346 return tv
.m_data
.parr
->empty() ? 0.0 : 1.0;
349 return tv
.m_data
.pobj
->toDouble();
352 return tv
.m_data
.pres
->data()->o_toDouble();
355 if (RuntimeOption::EvalRaiseFuncConversionWarning
) {
356 raise_warning("Func to double conversion");
358 return tv
.m_data
.pfunc
->name()->toDouble();
361 return classToStringHelper(tv
.m_data
.pclass
)->toDouble();
364 raiseClsMethConvertWarningHelper("double");
368 raise_convert_record_to_type("double");
378 enable_if_lval_t
<T
, void> tvCastToStringInPlace(T tv
) {
379 assertx(tvIsPlausible(*tv
));
381 auto string
= [&](StringData
* s
) {
382 type(tv
) = KindOfString
;
385 auto persistentString
= [&](StringData
* s
) {
386 assertx(!s
->isRefCounted());
387 type(tv
) = KindOfPersistentString
;
394 return persistentString(staticEmptyString());
397 return persistentString(val(tv
).num
? s_1
.get() : staticEmptyString());
400 return string(buildStringData(val(tv
).num
));
403 return string(buildStringData(val(tv
).dbl
));
405 case KindOfPersistentString
:
410 case KindOfPersistentVec
:
411 raise_notice("Vec to string conversion");
412 if (type(tv
) == KindOfVec
) tvDecRefArr(*tv
);
413 return persistentString(vec_string
.get());
416 case KindOfPersistentDict
:
417 raise_notice("Dict to string conversion");
418 if (type(tv
) == KindOfDict
) tvDecRefArr(*tv
);
419 return persistentString(dict_string
.get());
422 case KindOfPersistentKeyset
:
423 raise_notice("Keyset to string conversion");
424 if (type(tv
) == KindOfKeyset
) tvDecRefArr(*tv
);
425 return persistentString(keyset_string
.get());
427 case KindOfPersistentDArray
:
429 case KindOfPersistentVArray
:
432 case KindOfPersistentArray
:
433 raise_notice("Array to string conversion");
434 if (isRefcountedType(type(tv
))) {
437 return persistentString(array_string
.get());
441 make_tv
<KindOfString
>(val(tv
).pobj
->invokeToString().detach()),
448 make_tv
<KindOfString
>(val(tv
).pres
->data()->o_toString().detach()),
454 auto const s
= funcToStringHelper(val(tv
).pfunc
);
455 return persistentString(const_cast<StringData
*>(s
));
459 auto const s
= classToStringHelper(val(tv
).pclass
);
460 return persistentString(const_cast<StringData
*>(s
));
464 if (RuntimeOption::EvalRaiseClsMethConversionWarning
) {
465 raise_notice("Implicit clsmeth to string conversion");
468 if (RuntimeOption::EvalHackArrDVArrs
) {
469 return persistentString(vec_string
.get());
471 return persistentString(array_string
.get());
475 raise_convert_record_to_type("string");
480 StringData
* tvCastToStringData(TypedValue tv
) {
481 assertx(tvIsPlausible(tv
));
486 return staticEmptyString();
489 return tv
.m_data
.num
? s_1
.get() : staticEmptyString();
492 return buildStringData(tv
.m_data
.num
);
495 return buildStringData(tv
.m_data
.dbl
);
497 case KindOfPersistentString
:
498 return tv
.m_data
.pstr
;
501 auto s
= tv
.m_data
.pstr
;
506 case KindOfPersistentVec
:
508 raise_notice("Vec to string conversion");
509 return vec_string
.get();
511 case KindOfPersistentDict
:
513 raise_notice("Dict to string conversion");
514 return dict_string
.get();
516 case KindOfPersistentKeyset
:
518 raise_notice("Keyset to string conversion");
519 return keyset_string
.get();
521 case KindOfPersistentDArray
:
523 case KindOfPersistentVArray
:
525 case KindOfPersistentArray
:
527 raise_notice("Array to string conversion");
528 return array_string
.get();
531 return tv
.m_data
.pobj
->invokeToString().detach();
534 return tv
.m_data
.pres
->data()->o_toString().detach();
537 auto const s
= funcToStringHelper(tv
.m_data
.pfunc
);
538 return const_cast<StringData
*>(s
);
542 auto const s
= classToStringHelper(tv
.m_data
.pclass
);
543 return const_cast<StringData
*>(s
);
547 if (RuntimeOption::EvalRaiseClsMethConversionWarning
) {
548 raise_notice("Implicit clsmeth to string conversion");
550 if (RuntimeOption::EvalHackArrDVArrs
) {
551 return vec_string
.get();
553 return array_string
.get();
557 raise_convert_record_to_type("string");
562 String
tvCastToString(TypedValue tv
) {
563 return String::attach(tvCastToStringData(tv
));
566 template <IntishCast IC
>
567 ArrayData
* tvCastToArrayLikeData(TypedValue tv
) {
568 assertx(tvIsPlausible(tv
));
572 return ArrayData::Create();
577 case KindOfPersistentString
:
582 return ArrayData::Create(tv
);
584 case KindOfPersistentDArray
:
586 case KindOfPersistentVArray
:
588 case KindOfPersistentVec
:
590 case KindOfPersistentDict
:
592 case KindOfPersistentKeyset
:
594 case KindOfPersistentArray
:
596 auto const ad
= tv
.m_data
.parr
;
602 raiseClsMethToVecWarningHelper();
603 return clsMethToVecHelper(tv
.m_data
.pclsmeth
).detach();
606 auto ad
= tv
.m_data
.pobj
->toArray
<IC
>();
607 assertx(ad
->isPHPArrayType());
612 raise_convert_record_to_type("array");
618 ArrayData
* tvCastToArrayLikeData
<IntishCast::None
>(TypedValue
);
620 ArrayData
* tvCastToArrayLikeData
<IntishCast::Cast
>(TypedValue
);
622 template <IntishCast IC
/* = IntishCast::None */>
623 Array
tvCastToArrayLike(TypedValue tv
) {
624 return Array::attach(tvCastToArrayLikeData
<IC
>(tv
));
627 template Array tvCastToArrayLike
<IntishCast::Cast
>(TypedValue
);
628 template Array tvCastToArrayLike
<IntishCast::None
>(TypedValue
);
630 template <typename LHS
, typename T
>
631 static enable_if_lval_t
<
633 typename
std::enable_if
<std::is_rvalue_reference
<T
&&>::value
, void>::type
>
634 assign(LHS lhs
, T
&& rhs
) {
635 variant_ref
{lhs
} = std::forward
<T
>(rhs
);
638 template<typename T
, IntishCast IC
/* = IntishCast::None */>
639 enable_if_lval_t
<T
, void> tvCastToArrayInPlace(T tv
) {
640 assertx(tvIsPlausible(*tv
));
647 a
= ArrayData::Create();
653 case KindOfPersistentString
:
654 a
= ArrayData::Create(*tv
);
658 a
= ArrayData::Create(*tv
);
662 case KindOfPersistentVec
: {
663 auto* adIn
= val(tv
).parr
;
664 assertx(adIn
->isVecArrayKind());
665 a
= PackedArray::ToPHPArrayVec(adIn
, true);
671 auto* adIn
= val(tv
).parr
;
672 assertx(adIn
->isVecArrayKind());
673 a
= PackedArray::ToPHPArrayVec(adIn
, adIn
->cowCheck());
674 if (a
!= adIn
) tvDecRefArr(tv
);
678 case KindOfPersistentDict
: {
679 auto* adIn
= val(tv
).parr
;
680 assertx(adIn
->isDictKind());
682 if (IC
== IntishCast::Cast
) {
683 a
= MixedArray::ToPHPArrayIntishCastDict(adIn
, true);
685 assertx(IC
== IntishCast::None
);
686 a
= MixedArray::ToPHPArrayDict(adIn
, true);
694 auto* adIn
= val(tv
).parr
;
695 assertx(adIn
->isDictKind());
697 if (IC
== IntishCast::Cast
) {
698 a
= MixedArray::ToPHPArrayIntishCastDict(adIn
, adIn
->cowCheck());
700 assertx(IC
== IntishCast::None
);
701 a
= MixedArray::ToPHPArrayDict(adIn
, adIn
->cowCheck());
704 if (a
!= adIn
) tvDecRefArr(tv
);
708 case KindOfPersistentKeyset
: {
709 auto* adIn
= val(tv
).parr
;
710 assertx(adIn
->isKeysetKind());
712 if (IC
== IntishCast::Cast
) {
713 a
= SetArray::ToPHPArrayIntishCast(adIn
, true);
715 assertx(IC
== IntishCast::None
);
716 a
= SetArray::ToPHPArray(adIn
, true);
724 auto* adIn
= val(tv
).parr
;
725 assertx(adIn
->isKeysetKind());
727 if (IC
== IntishCast::Cast
) {
728 a
= SetArray::ToPHPArrayIntishCast(adIn
, adIn
->cowCheck());
730 assertx(IC
== IntishCast::None
);
731 a
= SetArray::ToPHPArray(adIn
, adIn
->cowCheck());
734 if (a
!= adIn
) tvDecRefArr(tv
);
738 case KindOfPersistentDArray
:
739 case KindOfPersistentVArray
:
740 case KindOfPersistentArray
: {
741 auto* adIn
= val(tv
).parr
;
742 assertx(adIn
->isPHPArrayType());
743 if (IC
== IntishCast::Cast
) {
744 a
= adIn
->toPHPArrayIntishCast(true);
746 assertx(IC
== IntishCast::None
);
747 a
= adIn
->toPHPArray(true);
755 auto* adIn
= val(tv
).parr
;
756 assertx(adIn
->isPHPArrayType());
757 if (IC
== IntishCast::Cast
) {
758 a
= adIn
->toPHPArrayIntishCast(adIn
->cowCheck());
760 assertx(IC
== IntishCast::None
);
761 a
= adIn
->toPHPArray(adIn
->cowCheck());
763 if (a
!= adIn
) tvDecRefArr(tv
);
768 assign(tv
, ((ObjectData
*)val(tv
).pobj
)->toArray
<IC
>());
773 a
= ArrayData::Create(*tv
);
779 a
= ArrayData::Create(*tv
);
782 case KindOfClsMeth
: {
783 raiseClsMethConvertWarningHelper("array");
784 a
= make_packed_array(
785 val(tv
).pclsmeth
->getClsStr(), val(tv
).pclsmeth
->getFuncStr()
792 raise_convert_record_to_type("array");
797 assertx(a
->isPHPArrayType());
798 assertx(a
->isNotDVArray());
801 type(tv
) = KindOfArray
;
802 assertx(tvIsPlausible(*tv
));
806 enable_if_lval_t
<T
, void> tvCastToVecInPlace(T tv
) {
807 assertx(tvIsPlausible(*tv
));
814 SystemLib::throwInvalidOperationExceptionObject(
815 "Null to vec conversion"
819 SystemLib::throwInvalidOperationExceptionObject(
820 "Bool to vec conversion"
824 SystemLib::throwInvalidOperationExceptionObject(
825 "Int to vec conversion"
829 SystemLib::throwInvalidOperationExceptionObject(
830 "Double to vec conversion"
833 case KindOfPersistentString
:
835 SystemLib::throwInvalidOperationExceptionObject(
836 "String to vec conversion"
840 SystemLib::throwInvalidOperationExceptionObject(
841 "Resource to vec conversion"
844 case KindOfPersistentDict
:
846 auto* adIn
= val(tv
).parr
;
847 assertx(adIn
->isDictKind());
848 a
= MixedArray::ToVecDict(adIn
, adIn
->cowCheck());
854 case KindOfPersistentKeyset
:
856 auto* adIn
= val(tv
).parr
;
857 assertx(adIn
->isKeysetKind());
858 a
= SetArray::ToVec(adIn
, adIn
->cowCheck());
864 case KindOfPersistentDArray
:
866 case KindOfPersistentVArray
:
868 case KindOfPersistentArray
:
870 auto* adIn
= val(tv
).parr
;
871 assertx(adIn
->isPHPArrayType());
872 a
= adIn
->toVec(adIn
->cowCheck());
873 if (a
!= adIn
) decRefArr(adIn
);
877 case KindOfPersistentVec
:
879 assertx(val(tv
).parr
->isVecArrayType());
883 a
= castObjToVec(val(tv
).pobj
);
884 // We might have re-entered, so tv may not contain the object anymore.
889 SystemLib::throwInvalidOperationExceptionObject(
890 "Func to vec conversion"
894 SystemLib::throwInvalidOperationExceptionObject(
895 "Class to vec conversion"
898 case KindOfClsMeth
: {
899 raiseClsMethConvertWarningHelper("vec");
901 val(tv
).pclsmeth
->getClsStr(), val(tv
).pclsmeth
->getFuncStr()
908 raise_convert_record_to_type("vec");
914 type(tv
) = KindOfVec
;
915 assertx(tvIsPlausible(*tv
));
919 enable_if_lval_t
<T
, void> tvCastToDictInPlace(T tv
) {
920 assertx(tvIsPlausible(*tv
));
927 SystemLib::throwInvalidOperationExceptionObject(
928 "Null to dict conversion"
932 SystemLib::throwInvalidOperationExceptionObject(
933 "Bool to dict conversion"
937 SystemLib::throwInvalidOperationExceptionObject(
938 "Int to dict conversion"
942 SystemLib::throwInvalidOperationExceptionObject(
943 "Double to dict conversion"
946 case KindOfPersistentString
:
948 SystemLib::throwInvalidOperationExceptionObject(
949 "String to dict conversion"
953 SystemLib::throwInvalidOperationExceptionObject(
954 "Resource to dict conversion"
957 case KindOfPersistentVec
:
959 auto* adIn
= val(tv
).parr
;
960 assertx(adIn
->isVecArrayKind());
961 a
= PackedArray::ToDictVec(adIn
, adIn
->cowCheck());
967 case KindOfPersistentKeyset
:
969 auto* adIn
= val(tv
).parr
;
970 assertx(adIn
->isKeysetKind());
971 a
= SetArray::ToDict(adIn
, adIn
->cowCheck());
972 if (a
!= adIn
) decRefArr(adIn
);
976 case KindOfPersistentDArray
:
978 case KindOfPersistentVArray
:
980 case KindOfPersistentArray
:
982 auto* adIn
= val(tv
).parr
;
983 assertx(adIn
->isPHPArrayType());
984 a
= adIn
->toDict(adIn
->cowCheck());
985 if (a
!= adIn
) decRefArr(adIn
);
989 case KindOfPersistentDict
:
991 assertx(val(tv
).parr
->isDictType());
995 a
= castObjToDict(val(tv
).pobj
);
996 // We might have re-entered, so tv may not contain the object anymore.
1001 SystemLib::throwInvalidOperationExceptionObject(
1002 "Func to dict conversion"
1006 SystemLib::throwInvalidArgumentExceptionObject(
1007 "Class to dict conversion"
1010 case KindOfClsMeth
: {
1011 raiseClsMethConvertWarningHelper("dict");
1012 a
= make_dict_array(
1013 0, val(tv
).pclsmeth
->getClsStr(),
1014 1, val(tv
).pclsmeth
->getFuncStr()).detach();
1015 tvDecRefClsMeth(tv
);
1020 raise_convert_record_to_type("dict");
1026 type(tv
) = KindOfDict
;
1027 assertx(tvIsPlausible(*tv
));
1030 template<typename T
>
1031 enable_if_lval_t
<T
, void> tvCastToKeysetInPlace(T tv
) {
1032 assertx(tvIsPlausible(*tv
));
1039 SystemLib::throwInvalidOperationExceptionObject(
1040 "Null to keyset conversion"
1044 SystemLib::throwInvalidOperationExceptionObject(
1045 "Bool to keyset conversion"
1049 SystemLib::throwInvalidOperationExceptionObject(
1050 "Int to keyset conversion"
1054 SystemLib::throwInvalidOperationExceptionObject(
1055 "Double to keyset conversion"
1058 case KindOfPersistentString
:
1060 SystemLib::throwInvalidOperationExceptionObject(
1061 "String to keyset conversion"
1064 case KindOfResource
:
1065 SystemLib::throwInvalidOperationExceptionObject(
1066 "Resource to keyset conversion"
1069 case KindOfPersistentVec
:
1071 auto* adIn
= val(tv
).parr
;
1072 assertx(adIn
->isVecArrayKind());
1073 a
= PackedArray::ToKeysetVec(adIn
, adIn
->cowCheck());
1079 case KindOfPersistentDict
:
1081 auto* adIn
= val(tv
).parr
;
1082 assertx(adIn
->isDictKind());
1083 a
= MixedArray::ToKeysetDict(adIn
, adIn
->cowCheck());
1084 if (a
!= adIn
) decRefArr(adIn
);
1088 case KindOfPersistentDArray
:
1090 case KindOfPersistentVArray
:
1092 case KindOfPersistentArray
:
1094 auto* adIn
= val(tv
).parr
;
1095 assertx(adIn
->isPHPArrayType());
1096 a
= adIn
->toKeyset(adIn
->cowCheck());
1097 if (a
!= adIn
) decRefArr(adIn
);
1101 case KindOfPersistentKeyset
:
1103 assertx(val(tv
).parr
->isKeysetType());
1107 a
= castObjToKeyset(val(tv
).pobj
);
1108 // We might have re-entered, so tv may not contain the object anymore.
1113 SystemLib::throwInvalidOperationExceptionObject(
1114 "Func to keyset conversion"
1118 SystemLib::throwInvalidOperationExceptionObject(
1119 "Class to keyset conversion"
1122 case KindOfClsMeth
: {
1123 raiseClsMethConvertWarningHelper("keyset");
1124 a
= make_keyset_array(
1125 const_cast<StringData
*>(val(tv
).pclsmeth
->getCls()->name()),
1126 const_cast<StringData
*>(val(tv
).pclsmeth
->getFunc()->name())
1128 tvDecRefClsMeth(tv
);
1133 raise_convert_record_to_type("keyset");
1139 type(tv
) = KindOfKeyset
;
1140 assertx(tvIsPlausible(*tv
));
1143 template<typename T
>
1144 enable_if_lval_t
<T
, void> tvCastToVArrayInPlace(T tv
) {
1145 assertx(!RuntimeOption::EvalHackArrDVArrs
);
1146 assertx(tvIsPlausible(*tv
));
1153 SystemLib::throwInvalidOperationExceptionObject(
1154 "Null to varray conversion"
1158 SystemLib::throwInvalidOperationExceptionObject(
1159 "Bool to varray conversion"
1163 SystemLib::throwInvalidOperationExceptionObject(
1164 "Int to varray conversion"
1168 SystemLib::throwInvalidOperationExceptionObject(
1169 "Double to varray conversion"
1172 case KindOfPersistentString
:
1174 SystemLib::throwInvalidOperationExceptionObject(
1175 "String to varray conversion"
1178 case KindOfResource
:
1179 SystemLib::throwInvalidOperationExceptionObject(
1180 "Resource to varray conversion"
1183 case KindOfPersistentVec
:
1185 auto* adIn
= val(tv
).parr
;
1186 assertx(adIn
->isVecArrayKind());
1187 a
= PackedArray::ToVArrayVec(adIn
, adIn
->cowCheck());
1188 if (a
!= adIn
) decRefArr(adIn
);
1192 case KindOfPersistentDict
:
1194 auto* adIn
= val(tv
).parr
;
1195 assertx(adIn
->isDictKind());
1196 a
= MixedArray::ToVArrayDict(adIn
, adIn
->cowCheck());
1202 case KindOfPersistentKeyset
:
1203 case KindOfKeyset
: {
1204 auto* adIn
= val(tv
).parr
;
1205 assertx(adIn
->isKeysetKind());
1206 a
= SetArray::ToVArray(adIn
, adIn
->cowCheck());
1212 case KindOfPersistentDArray
:
1214 case KindOfPersistentVArray
:
1216 case KindOfPersistentArray
:
1218 auto* adIn
= val(tv
).parr
;
1219 assertx(adIn
->isPHPArrayType());
1220 if (adIn
->isVArray()) return;
1221 a
= adIn
->toVArray(adIn
->cowCheck());
1222 assertx(a
->isPackedKind());
1223 assertx(a
->isVArray());
1224 if (a
== adIn
) return;
1230 a
= castObjToVArray(val(tv
).pobj
);
1231 // We might have re-entered, so tv may not contain the object anymore.
1236 SystemLib::throwInvalidOperationExceptionObject(
1237 "Func to varray conversion"
1241 SystemLib::throwInvalidOperationExceptionObject(
1242 "Class to varray conversion"
1245 case KindOfClsMeth
: {
1246 raiseClsMethConvertWarningHelper("varray");
1248 val(tv
).pclsmeth
->getClsStr(), val(tv
).pclsmeth
->getFuncStr()
1250 tvDecRefClsMeth(tv
);
1255 raise_convert_record_to_type("varray");
1260 assertx(a
->isPackedKind());
1261 assertx(a
->isVArray());
1262 assertx(a
->dvArraySanityCheck());
1265 type(tv
) = KindOfArray
;
1266 assertx(tvIsPlausible(*tv
));
1269 template<typename T
>
1270 enable_if_lval_t
<T
, void> tvCastToDArrayInPlace(T tv
) {
1271 assertx(!RuntimeOption::EvalHackArrDVArrs
);
1272 assertx(tvIsPlausible(*tv
));
1279 SystemLib::throwInvalidOperationExceptionObject(
1280 "Null to darray conversion"
1284 SystemLib::throwInvalidOperationExceptionObject(
1285 "Bool to darray conversion"
1289 SystemLib::throwInvalidOperationExceptionObject(
1290 "Int to darray conversion"
1294 SystemLib::throwInvalidOperationExceptionObject(
1295 "Double to darray conversion"
1298 case KindOfPersistentString
:
1300 SystemLib::throwInvalidOperationExceptionObject(
1301 "String to darray conversion"
1304 case KindOfResource
:
1305 SystemLib::throwInvalidOperationExceptionObject(
1306 "Resource to darray conversion"
1309 case KindOfPersistentVec
:
1311 auto* adIn
= val(tv
).parr
;
1312 assertx(adIn
->isVecArrayKind());
1313 a
= PackedArray::ToDArrayVec(adIn
, adIn
->cowCheck());
1319 case KindOfPersistentDict
:
1321 auto* adIn
= val(tv
).parr
;
1322 assertx(adIn
->isDictKind());
1323 a
= MixedArray::ToDArrayDict(adIn
, adIn
->cowCheck());
1324 if (a
!= adIn
) decRefArr(adIn
);
1328 case KindOfPersistentKeyset
:
1329 case KindOfKeyset
: {
1330 auto* adIn
= val(tv
).parr
;
1331 assertx(adIn
->isKeysetKind());
1332 a
= SetArray::ToDArray(adIn
, adIn
->cowCheck());
1338 case KindOfPersistentDArray
:
1340 case KindOfPersistentVArray
:
1342 case KindOfPersistentArray
:
1344 auto* adIn
= val(tv
).parr
;
1345 assertx(adIn
->isPHPArrayType());
1346 if (adIn
->isDArray()) return;
1347 a
= adIn
->toDArray(adIn
->cowCheck());
1348 assertx(a
->isMixedKind());
1349 assertx(a
->isDArray());
1350 if (a
== adIn
) return;
1356 a
= castObjToDArray(val(tv
).pobj
);
1357 // We might have re-entered, so tv may not contain the object anymore.
1362 SystemLib::throwInvalidOperationExceptionObject(
1363 "Func to darray conversion"
1367 SystemLib::throwInvalidOperationExceptionObject(
1368 "Class to darray conversion"
1371 case KindOfClsMeth
: {
1372 raiseClsMethConvertWarningHelper("darray");
1374 0, val(tv
).pclsmeth
->getClsStr(),
1375 1, val(tv
).pclsmeth
->getFuncStr()
1377 tvDecRefClsMeth(tv
);
1382 raise_convert_record_to_type("darray");
1387 assertx(a
->isMixedKind());
1388 assertx(a
->isDArray());
1389 assertx(a
->dvArraySanityCheck());
1392 type(tv
) = KindOfArray
;
1393 assertx(tvIsPlausible(*tv
));
1396 ObjectData
* tvCastToObjectData(TypedValue tv
) {
1397 assertx(tvIsPlausible(tv
));
1398 switch (tv
.m_type
) {
1401 return SystemLib::AllocStdClassObject().detach();
1406 case KindOfPersistentString
:
1410 case KindOfResource
: {
1411 ArrayInit
props(1, ArrayInit::Map
{});
1412 props
.set(s_scalar
, tv
);
1413 return ObjectData::FromArray(props
.create()).detach();
1416 case KindOfPersistentVec
:
1418 case KindOfPersistentDict
:
1420 case KindOfPersistentKeyset
:
1421 case KindOfKeyset
: {
1422 auto const arr
= Array::attach(tv
.m_data
.parr
->toPHPArray(true));
1423 return ObjectData::FromArray(arr
.get()).detach();
1426 case KindOfPersistentDArray
:
1428 case KindOfPersistentVArray
:
1430 case KindOfPersistentArray
:
1432 return ObjectData::FromArray(tv
.m_data
.parr
).detach();
1435 tv
.m_data
.pobj
->incRefCount();
1436 return tv
.m_data
.pobj
;
1438 case KindOfClsMeth
: {
1439 raiseClsMethConvertWarningHelper("array");
1440 auto arr
= make_varray(
1441 val(tv
).pclsmeth
->getClsStr(), val(tv
).pclsmeth
->getFuncStr());
1442 return ObjectData::FromArray(arr
.get()).detach();
1446 raise_convert_record_to_type("object");
1451 template<typename T
>
1452 enable_if_lval_t
<T
, void> tvCastToResourceInPlace(T tv
) {
1453 assertx(tvIsPlausible(*tv
));
1468 tvDecRefCountable(tv
);
1471 tvDecRefClsMeth(tv
);
1473 case KindOfResource
:
1480 type(tv
) = KindOfResource
;
1481 val(tv
).pres
= req::make
<DummyResource
>().detach()->hdr();
1482 assertx(tvIsPlausible(*tv
));
1485 ///////////////////////////////////////////////////////////////////////////////
1487 template void tvCastTo##kind##InPlace<TypedValue*>(TypedValue*); \
1488 template void tvCastTo##kind##InPlace<tv_lval>(tv_lval); \
1489 template void tvCastTo##kind##InPlace<arr_lval>(arr_lval);
1502 #define X(kind, IC) \
1503 template void tvCastTo##kind##InPlace<TypedValue*, IC>(TypedValue*); \
1504 template void tvCastTo##kind##InPlace<tv_lval, IC>(tv_lval); \
1505 template void tvCastTo##kind##InPlace<arr_lval, IC>(arr_lval);
1506 X(Array
, IntishCast::Cast
)
1507 X(Array
, IntishCast::None
)