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/vm/reified-generics.h"
19 #include "hphp/runtime/base/array-iterator.h"
20 #include "hphp/runtime/base/type-structure-helpers-defs.h"
22 #include "hphp/runtime/vm/act-rec.h"
23 #include "hphp/runtime/vm/named-entity.h"
24 #include "hphp/runtime/vm/reified-generics-info.h"
28 ///////////////////////////////////////////////////////////////////////////////
30 ArrayData
* addToReifiedGenericsTable(
31 const StringData
* name
,
34 auto const ne
= NamedEntity::get(name
, true);
35 auto const generics
= ne
->getCachedReifiedGenerics();
37 // We have created a new entry on the named entity table
38 // TODO(T31677864): If the type structures only contain persistent data,
39 // mark it as persistent
40 ne
->m_cachedReifiedGenerics
.bind(
42 rds::LinkName
{"ReifiedGenerics", name
}
44 ArrayData::GetScalarArray(&tsList
);
45 ne
->setCachedReifiedGenerics(tsList
);
48 // Same key should never result in different values.
49 // If this assertion fires, there's a high chance that two different type
50 // structure mangle to the same name and they should not.
51 assertx(tsList
->same(generics
));
56 ArrayData
* getClsReifiedGenericsProp(Class
* cls
, ObjectData
* obj
) {
57 if (!cls
->hasReifiedGenerics()) {
58 raise_error("Cannot get reified generics property of a non reified class");
60 auto const slot
= cls
->lookupReifiedInitProp();
61 assertx(slot
!= kInvalidSlot
);
62 auto index
= cls
->propSlotToIndex(slot
);
63 auto tv
= obj
->props()->at(index
).tv();
64 assertx(tvIsHAMSafeVArray(tv
));
65 return tv
.m_data
.parr
;
68 ArrayData
* getClsReifiedGenericsProp(Class
* cls
, ActRec
* ar
) {
69 auto const this_
= ar
->getThis();
70 return getClsReifiedGenericsProp(cls
, this_
);
74 extractSizeAndPosFromReifiedAttribute(const ArrayData
* arr
) {
75 size_t len
= 0, cur
= 0, numReified
= 0;
76 bool isReified
= false, isSoft
= false, hasAnySoft
= false;
78 std::vector
<TypeParamInfo
> tpList
;
81 [&](TypedValue k
, TypedValue v
) {
82 assertx(isIntType(k
.m_type
));
83 assertx(isIntType(v
.m_type
));
84 if (k
.m_data
.num
== 0) {
85 len
= (size_t) v
.m_data
.num
;
87 if (k
.m_data
.num
% 3 == 1) {
88 // This is the reified generic index
89 // Insert the non reified ones
90 auto const numErased
= v
.m_data
.num
- cur
;
91 tpList
.insert(tpList
.end(), numErased
, {});
92 bitmap
= (bitmap
<< (numErased
+ 1)) | 1;
95 } else if (k
.m_data
.num
% 3 == 2) {
96 isSoft
= (bool) v
.m_data
.num
;
99 // k.m_data.num % 3 == 0
102 tpList
.push_back({isReified
, isSoft
, (bool) v
.m_data
.num
});
107 // Insert the non reified ones at the end
108 tpList
.insert(tpList
.end(), len
- cur
, {});
109 bitmap
= bitmap
<< (len
- cur
);
110 return {numReified
, hasAnySoft
, bitmap
, tpList
};
113 // Raises a runtime error if the location of reified generics of f does not
114 // match the location of reified_generics
116 void checkReifiedGenericMismatchHelper(
117 const ReifiedGenericsInfo
& info
,
118 const StringData
* name
,
119 const ArrayData
* reified_generics
121 auto const generics
= info
.m_typeParamInfo
;
122 auto const len
= generics
.size();
123 if (len
!= reified_generics
->size()) {
124 if (reified_generics
->size() == 0) {
125 if (areAllGenericsSoft(info
)) {
126 raise_warning_for_soft_reified(0, fun
, name
);
130 SystemLib::throwBadMethodCallExceptionObject(
131 folly::sformat("{} {} requires {} generics but {} given",
132 fun
? "Function" : "Class",
135 reified_generics
->size()));
137 auto it
= generics
.begin();
140 [&](TypedValue k
, TypedValue v
) {
141 assertx(isIntType(k
.m_type
));
142 assertx(isArrayLikeType(v
.m_type
));
143 auto const i
= k
.m_data
.num
;
144 if (isWildCard(v
.m_data
.parr
) && it
->m_isReified
) {
146 SystemLib::throwBadMethodCallExceptionObject(
147 folly::sformat("{} {} expects a reified generic at index {}",
148 fun
? "Function" : "Class",
152 raise_warning_for_soft_reified(i
, fun
, name
);
159 void checkFunReifiedGenericMismatch(
161 const ArrayData
* reified_generics
163 checkReifiedGenericMismatchHelper
<true>(
164 f
->getReifiedGenericsInfo(),
170 void checkClassReifiedGenericMismatch(
172 const ArrayData
* reified_generics
174 checkReifiedGenericMismatchHelper
<false>(
175 c
->getReifiedGenericsInfo(),
181 uint32_t getGenericsBitmap(const ArrayData
* generics
) {
183 if (generics
->size() > 15) return 0;
188 assertx(isArrayLikeType(v
.m_type
));
189 bitmap
= (bitmap
<< 1) | !isWildCard(v
.m_data
.parr
);
195 bool areAllGenericsSoft(const ReifiedGenericsInfo
& info
) {
196 for (auto const& tp
: info
.m_typeParamInfo
) {
197 if (!tp
.m_isSoft
) return false;
202 void raise_warning_for_soft_reified(size_t i
, bool fun
,
203 const StringData
*name
) {
204 raise_warning("Generic at index %zu to %s %s must be reified,"
207 fun
? "Function" : "Class",
213 ///////////////////////////////////////////////////////////////////////////////