Reland D23318594 and D23318592 add recordbasenativesp instr
[hiphop-php.git] / hphp / runtime / vm / reified-generics.cpp
blob1a94e120a109e25492e35f5d7d9803215ff497d4
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
26 namespace HPHP {
28 ///////////////////////////////////////////////////////////////////////////////
30 ArrayData* addToReifiedGenericsTable(
31 const StringData* name,
32 ArrayData* tsList
33 ) {
34 auto const ne = NamedEntity::get(name, true);
35 auto const generics = ne->getCachedReifiedGenerics();
36 if (!generics) {
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(
41 rds::Mode::Normal,
42 rds::LinkName{"ReifiedGenerics", name}
44 ArrayData::GetScalarArray(&tsList);
45 ne->setCachedReifiedGenerics(tsList);
46 return 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));
52 decRefArr(tsList);
53 return 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_);
73 ReifiedGenericsInfo
74 extractSizeAndPosFromReifiedAttribute(const ArrayData* arr) {
75 size_t len = 0, cur = 0, numReified = 0;
76 bool isReified = false, isSoft = false, hasAnySoft = false;
77 uint32_t bitmap = 0;
78 std::vector<TypeParamInfo> tpList;
79 IterateKV(
80 arr,
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;
86 } else {
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;
93 cur = v.m_data.num;
94 isReified = true;
95 } else if (k.m_data.num % 3 == 2) {
96 isSoft = (bool) v.m_data.num;
97 hasAnySoft |= isSoft;
98 } else {
99 // k.m_data.num % 3 == 0
100 numReified++;
101 cur++;
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
115 template <bool fun>
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);
127 return;
130 SystemLib::throwBadMethodCallExceptionObject(
131 folly::sformat("{} {} requires {} generics but {} given",
132 fun ? "Function" : "Class",
133 name->data(),
134 len,
135 reified_generics->size()));
137 auto it = generics.begin();
138 IterateKV(
139 reified_generics,
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) {
145 if (!it->m_isSoft) {
146 SystemLib::throwBadMethodCallExceptionObject(
147 folly::sformat("{} {} expects a reified generic at index {}",
148 fun ? "Function" : "Class",
149 name->data(),
150 i));
152 raise_warning_for_soft_reified(i, fun, name);
154 ++it;
159 void checkFunReifiedGenericMismatch(
160 const Func* f,
161 const ArrayData* reified_generics
163 checkReifiedGenericMismatchHelper<true>(
164 f->getReifiedGenericsInfo(),
165 f->fullName(),
166 reified_generics
170 void checkClassReifiedGenericMismatch(
171 const Class* c,
172 const ArrayData* reified_generics
174 checkReifiedGenericMismatchHelper<false>(
175 c->getReifiedGenericsInfo(),
176 c->name(),
177 reified_generics
181 uint32_t getGenericsBitmap(const ArrayData* generics) {
182 assertx(generics);
183 if (generics->size() > 15) return 0;
184 auto bitmap = 1;
185 IterateV(
186 generics,
187 [&](TypedValue v) {
188 assertx(isArrayLikeType(v.m_type));
189 bitmap = (bitmap << 1) | !isWildCard(v.m_data.parr);
192 return bitmap;
195 bool areAllGenericsSoft(const ReifiedGenericsInfo& info) {
196 for (auto const& tp : info.m_typeParamInfo) {
197 if (!tp.m_isSoft) return false;
199 return true;
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,"
205 " erased given",
207 fun ? "Function" : "Class",
208 name->data());
213 ///////////////////////////////////////////////////////////////////////////////