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 #ifndef incl_HPHP_DATATYPE_H_
18 #define incl_HPHP_DATATYPE_H_
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"
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
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().
59 DT(PersistentDArray, -16) \
61 DT(PersistentVArray, -14) \
63 DT(PersistentArray, -12) \
65 DT(PersistentKeyset, -10) \
67 DT(PersistentDict, -8) \
69 DT(PersistentVec, -6) \
72 DT(PersistentString, -2) \
75 /* isNullType relies on a hole here */ \
84 DT(ClsMeth, use_lowptr ? 14 : 7)
86 enum class DataType
: int8_t {
87 #define DT(name, value) name = value,
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;
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);
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 ///////////////////////////////////////////////////////////////////////////////
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
,
172 ///////////////////////////////////////////////////////////////////////////////
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) \
183 func(CountnessInit) \
187 enum class DataTypeCategory
: uint8_t {
188 #define DT(name) name,
193 #define DT(name) auto constexpr DataType##name = DataTypeCategory::name;
197 ///////////////////////////////////////////////////////////////////////////////
200 inline std::string
tname(DataType t
) {
202 #define DT(name, ...) case KindOf##name: return #name;
206 if (t
== kInvalidDataType
) return "Invalid";
207 return folly::sformat("Unknown:{}", static_cast<int>(t
));
212 inline std::string
typeCategoryName(DataTypeCategory c
) {
214 # define CASE(name) case DataType##name: return "DataType" #name;
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
230 return (static_cast<int64_t>(t
) - kMinRefCountedDataType
) / 2;
233 ///////////////////////////////////////////////////////////////////////////////
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
&&
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
) {
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
) {
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
) {
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
) {
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
) {
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
) {
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
) {
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;
414 ///////////////////////////////////////////////////////////////////////////////
415 // Switch case macros.
418 * Covers all DataTypes `dt' such that !isRefcountedType(dt) holds.
420 #define DT_UNCOUNTED_CASE \
423 case KindOfBoolean: \
426 case KindOfPersistentString: \
427 case KindOfPersistentVArray: \
428 case KindOfPersistentDArray: \
429 case KindOfPersistentArray: \
430 case KindOfPersistentVec: \
431 case KindOfPersistentDict: \
432 case KindOfPersistentKeyset: \
437 ///////////////////////////////////////////////////////////////////////////////
440 template<> class FormatValue
<HPHP::DataTypeCategory
> {
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
);
450 HPHP::DataTypeCategory m_val
;
453 template<> class FormatValue
<HPHP::DataType
> {
455 explicit FormatValue(HPHP::DataType dt
) noexcept
: m_dt(dt
) {}
458 void format(FormatArg
& arg
, C
& cb
) const {
459 format_value::formatString(tname(m_dt
), arg
, cb
);
467 ///////////////////////////////////////////////////////////////////////////////