Use conditionals in sync_functions instead of section blocks
[hiphop-php.git] / hphp / runtime / vm / reified-generics.cpp
blob07725486357fb1c4da72f0f5475cc03059522e4c
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* addToTypeReifiedGenericsTable(
31 const StringData* name,
32 ArrayData* tsList
33 ) {
34 auto const ne = NamedType::getOrCreate(name);
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 assert_flog(tsList->same(generics),
52 "reified ts mismatch\nname: {}\ntsList: {}\ngenerics: {}\n",
53 name,
54 staticArrayStreamer(tsList),
55 staticArrayStreamer(generics));
56 decRefArr(tsList);
57 return generics;
60 ArrayData* getClsReifiedGenericsProp(Class* cls, ObjectData* obj) {
61 if (!cls->hasReifiedGenerics()) {
62 raise_error("Cannot get reified generics property of a non reified class");
64 auto const slot = cls->lookupReifiedInitProp();
65 assertx(slot != kInvalidSlot);
66 auto index = cls->propSlotToIndex(slot);
67 auto tv = obj->props()->at(index).tv();
68 assertx(tvIsVec(tv));
69 return tv.m_data.parr;
72 ReifiedGenericsInfo
73 extractSizeAndPosFromReifiedAttribute(const ArrayData* arr) {
74 size_t len = 0, cur = 0, numReified = 0;
75 bool isReified = false, isSoft = false, hasAnySoft = false;
76 uint32_t bitmap = 0;
77 std::vector<TypeParamInfo> tpList;
78 IterateKV(
79 arr,
80 [&](TypedValue k, TypedValue v) {
81 assertx(isIntType(k.m_type));
82 assertx(isIntType(v.m_type));
83 if (k.m_data.num == 0) {
84 len = (size_t) v.m_data.num;
85 } else {
86 if (k.m_data.num % 3 == 1) {
87 // This is the reified generic index
88 // Insert the non reified ones
89 auto const numErased = v.m_data.num - cur;
90 tpList.insert(tpList.end(), numErased, {});
91 bitmap = (bitmap << (numErased + 1)) | 1;
92 cur = v.m_data.num;
93 isReified = true;
94 } else if (k.m_data.num % 3 == 2) {
95 isSoft = (bool) v.m_data.num;
96 hasAnySoft |= isSoft;
97 } else {
98 // k.m_data.num % 3 == 0
99 numReified++;
100 cur++;
101 tpList.push_back({isReified, isSoft, (bool) v.m_data.num});
106 // Insert the non reified ones at the end
107 tpList.insert(tpList.end(), len - cur, {});
108 bitmap = bitmap << (len - cur);
109 return {numReified, hasAnySoft, bitmap, tpList};
112 // Raises a runtime error if the location of reified generics of f does not
113 // match the location of reified_generics
114 template <bool fun>
115 void checkReifiedGenericMismatchHelper(
116 const ReifiedGenericsInfo& info,
117 const StringData* name,
118 const ArrayData* reified_generics
120 auto const& generics = info.m_typeParamInfo;
121 auto const len = generics.size();
122 if (len != reified_generics->size()) {
123 if (reified_generics->size() == 0) {
124 if (areAllGenericsSoft(info)) {
125 raise_warning_for_soft_reified(0, fun, name);
126 return;
129 SystemLib::throwBadMethodCallExceptionObject(
130 folly::sformat("{} {} requires {} generics but {} given",
131 fun ? "Function" : "Class",
132 name->data(),
133 len,
134 reified_generics->size()));
136 auto it = generics.begin();
137 IterateKV(
138 reified_generics,
139 [&](TypedValue k, TypedValue v) {
140 assertx(isIntType(k.m_type));
141 assertx(isArrayLikeType(v.m_type));
142 auto const i = k.m_data.num;
143 if (isWildCard(v.m_data.parr) && it->m_isReified) {
144 if (!it->m_isSoft) {
145 SystemLib::throwBadMethodCallExceptionObject(
146 folly::sformat("{} {} expects a reified generic at index {}",
147 fun ? "Function" : "Class",
148 name->data(),
149 i));
151 raise_warning_for_soft_reified(i, fun, name);
153 ++it;
158 void checkFunReifiedGenericMismatch(
159 const Func* f,
160 const ArrayData* reified_generics
162 checkReifiedGenericMismatchHelper<true>(
163 f->getReifiedGenericsInfo(),
164 f->fullName(),
165 reified_generics
169 void checkClassReifiedGenericMismatch(
170 const Class* c,
171 const ArrayData* reified_generics
173 checkReifiedGenericMismatchHelper<false>(
174 c->getReifiedGenericsInfo(),
175 c->name(),
176 reified_generics
180 uint16_t getGenericsBitmap(const ArrayData* generics) {
181 assertx(generics);
182 if (generics->size() > 15) return 0;
183 uint16_t bitmap = 1;
184 IterateV(
185 generics,
186 [&](TypedValue v) {
187 assertx(isArrayLikeType(v.m_type));
188 bitmap = (bitmap << 1) | !isWildCard(v.m_data.parr);
191 return bitmap;
194 uint16_t getGenericsBitmap(const Func* f) {
195 assertx(f);
196 if (!f->hasReifiedGenerics()) return 0;
197 auto const& info = f->getReifiedGenericsInfo();
198 if (info.m_typeParamInfo.size() > 15) return 0;
199 uint16_t bitmap = 1;
200 for (auto const& tinfo : info.m_typeParamInfo) {
201 bitmap = (bitmap << 1) | (tinfo.m_isReified && !tinfo.m_isSoft);
203 return bitmap;
206 bool areAllGenericsSoft(const ReifiedGenericsInfo& info) {
207 for (auto const& tp : info.m_typeParamInfo) {
208 if (!tp.m_isSoft) return false;
210 return true;
213 void raise_warning_for_soft_reified(size_t i, bool fun,
214 const StringData *name) {
215 raise_warning("Generic at index %zu to %s %s must be reified,"
216 " erased given",
218 fun ? "Function" : "Class",
219 name->data());
222 void checkClassReifiedGenericsSoft(const Class* cls) {
223 assertx(cls->hasReifiedGenerics());
224 if (areAllGenericsSoft(cls->getReifiedGenericsInfo())) {
225 raise_warning_for_soft_reified(0, false, cls->name());
226 } else {
227 raise_error("Cannot create a new instance of a reified class without "
228 "the reified generics");
232 ///////////////////////////////////////////////////////////////////////////////