Eliminate ArrayData::LvalForceNew
[hiphop-php.git] / hphp / runtime / base / datatype.h
blob30c1befdf513e2936a6bdf412960f3c455b82968
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 #ifndef incl_HPHP_DATATYPE_H_
18 #define incl_HPHP_DATATYPE_H_
20 #include <cstdint>
21 #include <cstdio>
22 #include <string>
24 #include <folly/Format.h>
25 #include <folly/Optional.h>
27 #include "hphp/util/assertions.h"
28 #include "hphp/util/low-ptr.h"
29 #include "hphp/util/portability.h"
31 namespace HPHP {
33 ///////////////////////////////////////////////////////////////////////////////
36 * DataType is the type tag for a TypedValue (see typed-value.h).
38 * If you want to add a new type, beware of the following restrictions:
39 * - KindOfUninit must be 0. Many places rely on zero-initialized memory
40 * being a valid, KindOfUninit TypedValue.
41 * - KindOfNull must be 2, and 1 must not be a valid type. This allows for
42 * a fast implementation of isNullType().
43 * - The Array and String types are positioned to allow for fast array/string
44 * checks, ignoring persistence (see isArrayType and isStringType).
45 * - Refcounted types are odd, and uncounted types are even, to allow fast
46 * countness checks.
47 * - Types with persistent and non-persistent versions must be negative, for
48 * equivDataTypes(). Other types may be negative, as long as dropping the low
49 * bit does not give another valid type.
50 * - -128 and -127 are used as invalid types and can't be real DataTypes.
52 * If you think you need to change any of these restrictions, be prepared to
53 * deal with subtle bugs and/or performance regressions while you sort out the
54 * consequences. At a minimum, you must:
55 * - Audit every helper function in this file.
56 * - Audit jit::emitTypeTest().
58 #define DATATYPES \
59 DT(PersistentDArray, -16) \
60 DT(DArray, -15) \
61 DT(PersistentVArray, -14) \
62 DT(VArray, -13) \
63 DT(PersistentArray, -12) \
64 DT(Array, -11) \
65 DT(PersistentKeyset, -10) \
66 DT(Keyset, -9) \
67 DT(PersistentDict, -8) \
68 DT(Dict, -7) \
69 DT(PersistentVec, -6) \
70 DT(Vec, -5) \
71 DT(Record, -3) \
72 DT(PersistentString, -2) \
73 DT(String, -1) \
74 DT(Uninit, 0) \
75 /* isNullType relies on a hole here */ \
76 DT(Null, 2) \
77 DT(Object, 3) \
78 DT(Boolean, 4) \
79 DT(Resource, 5) \
80 DT(Int64, 6) \
81 DT(Double, 8) \
82 DT(Func, 10) \
83 DT(Class, 12) \
84 DT(ClsMeth, use_lowptr ? 14 : 7)
86 enum class DataType : int8_t {
87 #define DT(name, value) name = value,
88 DATATYPES
89 #undef DT
92 using data_type_t = typename std::underlying_type<DataType>::type;
94 // Macro so we can limit its scope to this file. Anyone else doing this cast
95 // should have to write out the whole thing and think about their life choices.
96 #define dt_t(t) static_cast<data_type_t>(t)
99 * Also define KindOf<Foo> for each type, to avoid having to change thousands
100 * of existing usage sites.
102 #define DT(name, ...) auto constexpr KindOf##name = DataType::name;
103 DATATYPES
104 #undef DT
107 * Sentinel invalid DataTypes.
109 * These values must differ from that of any real DataType. A live TypedValue
110 * should never have these as its type tag, so we keep them out of the enum to
111 * keep switches cleaner.
113 * These should only be used where MaybeDataType cannot be (e.g., in
114 * TypedValues, such as for MixedArray tombstones).
116 constexpr DataType kInvalidDataType = static_cast<DataType>(-128);
117 constexpr DataType kExtraInvalidDataType = static_cast<DataType>(-127);
120 * DataType limits.
122 auto constexpr kMinDataType = dt_t(KindOfPersistentDArray);
123 auto constexpr kMaxDataType = dt_t(use_lowptr ? KindOfClsMeth : KindOfClass);
124 auto constexpr kMinRefCountedDataType = dt_t(KindOfDArray);
125 auto constexpr kMaxRefCountedDataType =
126 dt_t(use_lowptr ? KindOfResource : KindOfClsMeth);
129 * A DataType is a refcounted type if and only if it has this bit set.
131 constexpr int kRefCountedBit = 0x1;
134 * Return `dt` with or without the refcount bit set.
136 constexpr DataType dt_with_rc(DataType dt) {
137 return static_cast<DataType>(dt_t(dt) | kRefCountedBit);
139 constexpr DataType dt_with_persistence(DataType dt) {
140 return static_cast<DataType>(dt_t(dt) & ~kRefCountedBit);
144 * Return the ref-counted flavor of `dt` if it has both a KindOf$x and a
145 * KindOfPersistent$x flavor
147 constexpr DataType dt_modulo_persistence(DataType dt) {
148 auto const rep = dt_t(dt);
149 return static_cast<DataType>(rep < 0 ? rep | kRefCountedBit : rep);
152 ///////////////////////////////////////////////////////////////////////////////
154 * Optional DataType.
156 * Used for (DataType|KindOfNoneType) or (DataType|KindOfAnyType), depending on
157 * context. Users who wish to use (DataType|KindOfNoneType|KindOfAnyType)
158 * should consider dying in a fire.
160 using MaybeDataType = folly::Optional<DataType>;
163 * Extracts the DataType from the given type
165 MaybeDataType get_datatype(
166 const std::string& name,
167 bool can_be_collection,
168 bool is_nullable,
169 bool is_soft
172 ///////////////////////////////////////////////////////////////////////////////
173 // DataTypeCategory
175 // These must be kept in order from least to most specific.
177 // Note that Countness can be relaxed to Generic in optimizeProfiledGuards(), so
178 // it should only be used to constrain values used by instructions that work
179 // even in the absence of type information.
180 #define DT_CATEGORIES(func) \
181 func(Generic) \
182 func(Countness) \
183 func(CountnessInit) \
184 func(Specific) \
185 func(Specialized)
187 enum class DataTypeCategory : uint8_t {
188 #define DT(name) name,
189 DT_CATEGORIES(DT)
190 #undef DT
193 #define DT(name) auto constexpr DataType##name = DataTypeCategory::name;
194 DT_CATEGORIES(DT)
195 #undef DT
197 ///////////////////////////////////////////////////////////////////////////////
198 // Names.
200 inline std::string tname(DataType t) {
201 switch (t) {
202 #define DT(name, ...) case KindOf##name: return #name;
203 DATATYPES
204 #undef DT
205 default: {
206 if (t == kInvalidDataType) return "Invalid";
207 return folly::sformat("Unknown:{}", static_cast<int>(t));
212 inline std::string typeCategoryName(DataTypeCategory c) {
213 switch (c) {
214 # define CASE(name) case DataType##name: return "DataType" #name;
215 DT_CATEGORIES(CASE)
216 #undef CASE
218 not_reached();
222 * These are used in type-variant.cpp.
224 constexpr int kDestrTableSize =
225 (kMaxRefCountedDataType - kMinRefCountedDataType) / 2 + 1;
227 constexpr unsigned typeToDestrIdx(DataType t) {
228 // t must be a refcounted type, but we can't actually assert that and still
229 // be constexpr.
230 return (static_cast<int64_t>(t) - kMinRefCountedDataType) / 2;
233 ///////////////////////////////////////////////////////////////////////////////
234 // Is-a macros.
237 * Whether a type is valid.
239 constexpr bool isRealType(DataType t) {
240 return t >= static_cast<DataType>(kMinDataType) &&
241 t <= static_cast<DataType>(kMaxDataType);
245 * Whether a type is refcounted.
247 constexpr bool isRefcountedType(DataType t) {
248 return dt_t(t) & kRefCountedBit;
252 * Whether a builtin return or param type is not a simple type.
254 * This is different from isRefcountedType because builtins can accept and
255 * return Variants, and we use folly::none to denote these cases.
257 inline bool isBuiltinByRef(MaybeDataType t) {
258 return t != KindOfNull &&
259 t != KindOfBoolean &&
260 t != KindOfInt64 &&
261 t != KindOfDouble;
265 * Whether a type's value is an integral value in m_data.num.
267 constexpr bool hasNumData(DataType t) {
268 return t == KindOfBoolean || t == KindOfInt64;
272 * Whether a type is KindOfUninit or KindOfNull.
274 constexpr bool isNullType(DataType t) {
275 static_assert(KindOfUninit == static_cast<DataType>(0) &&
276 KindOfNull == static_cast<DataType>(2),
277 "isNullType requires Uninit and Null to be 0 and 2");
278 return static_cast<uint8_t>(t) <= static_cast<uint8_t>(KindOfNull);
282 * Whether a type is any kind of string or array.
284 constexpr bool isStringType(DataType t) {
285 return
286 static_cast<uint8_t>(t) >= static_cast<uint8_t>(KindOfPersistentString);
288 inline bool isStringType(MaybeDataType t) {
289 return t && isStringType(*t);
292 constexpr bool isArrayLikeType(DataType t) {
293 return t <= KindOfVec;
295 inline bool isArrayLikeType(MaybeDataType t) {
296 return t && isArrayLikeType(*t);
300 * When any PHP (d|v|)array will do.
302 constexpr bool isPHPArrayType(DataType t) {
303 return t <= KindOfArray;
305 inline bool isPHPArrayType(MaybeDataType t) {
306 return t && isPHPArrayType(*t);
310 * Currently matches any PHP (d|v|)array.
311 * Eventually will only match arrays without dvarray-ness.
313 constexpr bool isArrayType(DataType t) {
314 return t <= KindOfArray;
316 inline bool isArrayType(MaybeDataType t) {
317 return t && isArrayType(*t);
320 constexpr bool isHackArrayType(DataType t) {
321 return t >= KindOfPersistentKeyset && t <= KindOfVec;
323 inline bool isHackArrayType(MaybeDataType t) {
324 return t && isHackArrayType(*t);
327 constexpr bool isVArrayType(DataType t) {
328 return
329 static_cast<DataType>(dt_t(t) & ~kRefCountedBit) == KindOfPersistentVArray;
332 inline bool isVArrayType(MaybeDataType t) {
333 return t && isVArrayType(*t);
336 constexpr bool isDArrayType(DataType t) {
337 return
338 static_cast<DataType>(dt_t(t) & ~kRefCountedBit) == KindOfPersistentDArray;
340 inline bool isDArrayType(MaybeDataType t) {
341 return t && isDArrayType(*t);
344 constexpr bool isVecType(DataType t) {
345 return
346 static_cast<DataType>(dt_t(t) & ~kRefCountedBit) == KindOfPersistentVec;
348 inline bool isVecType(MaybeDataType t) {
349 return t && isVecType(*t);
352 constexpr bool isDictType(DataType t) {
353 return
354 static_cast<DataType>(dt_t(t) & ~kRefCountedBit) == KindOfPersistentDict;
356 inline bool isDictType(MaybeDataType t) {
357 return t && isDictType(*t);
361 * Based on EvalHackArrDVArrs checks whether t is vec/dict or array
363 bool isVecOrArrayType(DataType t);
364 bool isDictOrArrayType(DataType t);
366 constexpr bool isKeysetType(DataType t) {
367 return
368 static_cast<DataType>(dt_t(t) & ~kRefCountedBit) == KindOfPersistentKeyset;
370 inline bool isKeysetType(MaybeDataType t) {
371 return t && isKeysetType(*t);
375 * Other type-check functions.
377 constexpr bool isIntType(DataType t) { return t == KindOfInt64; }
378 constexpr bool isBoolType(DataType t) { return t == KindOfBoolean; }
379 constexpr bool isDoubleType(DataType t) { return t == KindOfDouble; }
380 constexpr bool isObjectType(DataType t) { return t == KindOfObject; }
381 constexpr bool isRecordType(DataType t) { return t == KindOfRecord; }
382 constexpr bool isResourceType(DataType t) { return t == KindOfResource; }
383 constexpr bool isFuncType(DataType t) { return t == KindOfFunc; }
384 constexpr bool isClassType(DataType t) { return t == KindOfClass; }
385 constexpr bool isClsMethType(DataType t) { return t == KindOfClsMeth; }
387 constexpr int kHasPersistentMask = -128;
390 * Return whether two DataTypes for primitive types are "equivalent" as far as
391 * user-visible PHP types are concerned (i.e. ignoring different types of
392 * strings, PHP arrays, and Hack arrays). Note that KindOfUninit and KindOfNull are
393 * not considered equivalent.
395 constexpr bool equivDataTypes(DataType t1, DataType t2) {
396 return t1 == t2 ||
397 (isArrayType(t1) && isArrayType(t2)) ||
398 ((dt_t(t1) & dt_t(t2) & kHasPersistentMask) &&
399 (dt_t(t1) & ~kRefCountedBit) == (dt_t(t2) & ~kRefCountedBit));
403 * If you think you need to do any of these operations, you should instead add
404 * a helper function up above and call that, to keep any knowledge about the
405 * relative values of DataTypes in this file.
407 bool operator<(DataType, DataType) = delete;
408 bool operator>(DataType, DataType) = delete;
409 bool operator<=(DataType, DataType) = delete;
410 bool operator>=(DataType, DataType) = delete;
412 #undef dt_t
414 ///////////////////////////////////////////////////////////////////////////////
415 // Switch case macros.
418 * Covers all DataTypes `dt' such that !isRefcountedType(dt) holds.
420 #define DT_UNCOUNTED_CASE \
421 case KindOfUninit: \
422 case KindOfNull: \
423 case KindOfBoolean: \
424 case KindOfInt64: \
425 case KindOfDouble: \
426 case KindOfPersistentString: \
427 case KindOfPersistentVArray: \
428 case KindOfPersistentDArray: \
429 case KindOfPersistentArray: \
430 case KindOfPersistentVec: \
431 case KindOfPersistentDict: \
432 case KindOfPersistentKeyset: \
433 case KindOfFunc: \
434 case KindOfClass
437 ///////////////////////////////////////////////////////////////////////////////
439 namespace folly {
440 template<> class FormatValue<HPHP::DataTypeCategory> {
441 public:
442 explicit FormatValue(HPHP::DataTypeCategory val) noexcept : m_val(val) {}
444 template<typename Callback>
445 void format(FormatArg& arg, Callback& cb) const {
446 format_value::formatString(typeCategoryName(m_val), arg, cb);
449 private:
450 HPHP::DataTypeCategory m_val;
453 template<> class FormatValue<HPHP::DataType> {
454 public:
455 explicit FormatValue(HPHP::DataType dt) noexcept : m_dt(dt) {}
457 template<typename C>
458 void format(FormatArg& arg, C& cb) const {
459 format_value::formatString(tname(m_dt), arg, cb);
462 private:
463 HPHP::DataType m_dt;
467 ///////////////////////////////////////////////////////////////////////////////
469 #endif