Fix relaxation of specialized boxed types
[hiphop-php.git] / hphp / runtime / vm / jit / type.h
blob9d7aa0ef9668029e27c5faf2444e2f16ba08951a
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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_JIT_TYPE_H_
18 #define incl_HPHP_JIT_TYPE_H_
20 #include "hphp/runtime/base/repo-auth-type.h"
21 #include "hphp/runtime/base/repo-auth-type-array.h"
22 #include "hphp/runtime/base/string-data.h"
23 #include "hphp/runtime/base/type-array.h"
25 #include "hphp/runtime/vm/class.h"
26 #include "hphp/runtime/vm/jit/types.h"
28 #include "hphp/util/data-block.h"
30 #include "folly/Optional.h"
32 #include <cstdint>
33 #include <cstring>
35 namespace HPHP {
36 struct Func;
38 namespace JIT {
39 struct DynLocation;
40 struct RuntimeType;
42 namespace JIT {
44 namespace constToBits_detail {
45 template<class T>
46 struct needs_promotion
47 : std::integral_constant<
48 bool,
49 std::is_integral<T>::value ||
50 std::is_same<T,bool>::value ||
51 std::is_enum<T>::value
53 {};
55 template<class T>
56 typename std::enable_if<needs_promotion<T>::value,uint64_t>::type
57 promoteIfNeeded(T t) { return static_cast<uint64_t>(t); }
59 template<class T>
60 typename std::enable_if<!needs_promotion<T>::value,T>::type
61 promoteIfNeeded(T t) { return t; }
64 #define IRT_BOXES(name, bits) \
65 IRT(name, (bits)) \
66 IRT(Boxed##name, (bits) << kBoxShift) \
67 IRT(PtrTo##name, (bits) << kPtrShift) \
68 IRT(PtrToBoxed##name, (bits) << kPtrBoxShift)
70 #define IRT_BOXES_WITH_ANY(name, bits) \
71 IRT_BOXES(name, bits) \
72 IRT(Any##name, k##name | kBoxed##name | kPtrTo##name | \
73 kPtrToBoxed##name)
76 #define IRT_PHP(c) \
77 c(Uninit, 1ULL << 0) \
78 c(InitNull, 1ULL << 1) \
79 c(Bool, 1ULL << 2) \
80 c(Int, 1ULL << 3) \
81 c(Dbl, 1ULL << 4) \
82 c(StaticStr, 1ULL << 5) \
83 c(CountedStr, 1ULL << 6) \
84 c(StaticArr, 1ULL << 7) \
85 c(CountedArr, 1ULL << 8) \
86 c(Obj, 1ULL << 9) \
87 c(Res, 1ULL << 10)
88 // Boxed*: 11-21
89 // PtrTo*: 22-32
90 // PtrToBoxed*: 33-43
92 // This list should be in non-decreasing order of specificity
93 #define IRT_PHP_UNIONS(c) \
94 c(Null, kUninit|kInitNull) \
95 c(Str, kStaticStr|kCountedStr) \
96 c(Arr, kStaticArr|kCountedArr) \
97 c(NullableObj, kObj|kInitNull|kUninit) \
98 c(UncountedInit, kInitNull|kBool|kInt|kDbl|kStaticStr|kStaticArr) \
99 c(Uncounted, kUncountedInit|kUninit) \
100 c(InitCell, kUncountedInit|kStr|kArr|kObj|kRes) \
101 c(Cell, kInitCell|kUninit)
103 #define IRT_RUNTIME \
104 IRT(Cls, 1ULL << 44) \
105 IRT(Func, 1ULL << 45) \
106 IRT(VarEnv, 1ULL << 46) \
107 IRT(NamedEntity, 1ULL << 47) \
108 IRT(Cctx, 1ULL << 48) /* Class* with the lowest bit set, */ \
109 /* as stored in ActRec.m_cls field */ \
110 IRT(RetAddr, 1ULL << 49) /* Return address */ \
111 IRT(StkPtr, 1ULL << 50) /* stack pointer */ \
112 IRT(FramePtr, 1ULL << 51) /* frame pointer */ \
113 IRT(TCA, 1ULL << 52) \
114 IRT(ActRec, 1ULL << 53) \
115 IRT(RDSHandle, 1ULL << 54) /* RDS::Handle */ \
116 IRT(Nullptr, 1ULL << 55)
118 // The definitions for these are in ir.cpp
119 #define IRT_UNIONS \
120 IRT(Ctx, kObj|kCctx) \
122 // Gen, Counted, PtrToGen, and PtrToCounted are here instead of
123 // IRT_PHP_UNIONS because boxing them (e.g., BoxedGen, PtrToBoxedGen)
124 // would yield nonsense types.
125 #define IRT_SPECIAL \
126 IRT(Bottom, 0) \
127 IRT(Top, 0xffffffffffffffffULL) \
128 IRT(Counted, kCountedStr|kCountedArr|kObj|kRes|kBoxedCell) \
129 IRT(PtrToCounted, kCounted << kPtrShift) \
130 IRT(Gen, kCell|kBoxedCell) \
131 IRT(StackElem, kGen|kCls) \
132 IRT(Init, kGen & ~kUninit) \
133 IRT(PtrToGen, kGen << kPtrShift) \
134 IRT(PtrToInit, kInit << kPtrShift)
136 // All types (including union types) that represent program values,
137 // except Gen (which is special). Boxed*, PtrTo*, and PtrToBoxed* only
138 // exist for these types.
139 #define IRT_USERLAND(c) IRT_PHP(c) IRT_PHP_UNIONS(c)
141 // All types with just a single bit set
142 #define IRT_PRIMITIVE IRT_PHP(IRT_BOXES) IRT_RUNTIME
144 // All types
145 #define IR_TYPES IRT_USERLAND(IRT_BOXES_WITH_ANY) IRT_RUNTIME IRT_UNIONS \
146 IRT_SPECIAL
149 * Type is used to represent the types of values in the jit. Every Type
150 * represents a set of types, with Type::Top being a superset of all Types and
151 * Type::Bottom being a subset of all Types. The elements forming these sets of
152 * types come from the types of PHP-visible values (Str, Obj, Int, ...) and
153 * runtime-internal types (Func, TCA, ActRec, ...).
155 * Types can be constructed from the predefined constants or by composing
156 * existing Types in various ways. Unions, intersections, and subtractions are
157 * all supported, though for implementation-specific reasons certain
158 * combinations of specialized types cannot be represented. A type is
159 * considered specialized if it refers to a specific Class or a
160 * ArrayData::ArrayKind. As an example, if A and B are unrelated Classes,
161 * Obj<A> | Obj<B> is impossible to represent. However, if B is a subclass of
162 * A, Obj<A> | Obj<B> == Obj<B>, which can be represented as a Type.
164 class Type {
165 typedef uint64_t bits_t;
167 static const size_t kBoxShift = 11;
168 static const size_t kPtrShift = kBoxShift * 2;
169 static const size_t kPtrBoxShift = kBoxShift + kPtrShift;
171 enum TypedBits {
172 #define IRT(name, bits) k##name = (bits),
173 IR_TYPES
174 #undef IRT
177 // An ArrayKind in the top 16 bits, optional RepoAuthType::Array* in
178 // the lower 48 bits, and the low bit that says whether the kind is
179 // valid.
180 enum class ArrayInfo : uintptr_t {};
182 bits_t m_bits:63;
183 bool m_hasConstVal:1;
185 union {
186 uintptr_t m_extra;
188 // Constant values. Validity determined by m_hasConstVal and m_bits.
189 bool m_boolVal;
190 int64_t m_intVal;
191 double m_dblVal;
192 const StringData* m_strVal;
193 const ArrayData* m_arrVal;
194 const HPHP::Func* m_funcVal;
195 const Class* m_clsVal;
196 JIT::TCA m_tcaVal;
197 RDS::Handle m_rdsHandleVal;
198 TypedValue* m_ptrVal;
200 // Specialization for object classes and arrays.
201 const Class* m_class;
202 ArrayInfo m_arrayInfo;
205 static ArrayInfo makeArrayInfo(folly::Optional<ArrayData::ArrayKind> kind,
206 const RepoAuthType::Array* arrTy) {
207 auto ret = reinterpret_cast<uintptr_t>(arrTy);
208 if (kind.hasValue()) {
209 ret |= 0x1;
210 ret |= uintptr_t{*kind} << 48;
212 return static_cast<ArrayInfo>(ret);
215 static bool arrayKindValid(ArrayInfo info) {
216 return static_cast<uintptr_t>(info) & 0x1;
219 static ArrayData::ArrayKind kind(ArrayInfo info) {
220 assert(arrayKindValid(info));
221 return static_cast<ArrayData::ArrayKind>(
222 static_cast<uintptr_t>(info) >> 48
226 // May return nullptr if we have no specialized array type
227 // information.
228 static const RepoAuthType::Array* arrayType(ArrayInfo info) {
229 return reinterpret_cast<const RepoAuthType::Array*>(
230 static_cast<uintptr_t>(info) & (-1ull >> 16) & ~0x1
234 bool checkValid() const;
236 explicit Type(bits_t bits, uintptr_t extra = 0)
237 : m_bits(bits)
238 , m_hasConstVal(false)
239 , m_extra(extra)
241 assert(checkValid());
244 explicit Type(bits_t bits, const Class* klass)
245 : m_bits(bits)
246 , m_hasConstVal(false)
247 , m_class(klass)
249 assert(checkValid());
252 explicit Type(bits_t bits, ArrayInfo arrayInfo)
253 : m_bits(bits)
254 , m_hasConstVal(false)
255 , m_arrayInfo(arrayInfo)
257 assert(checkValid());
260 explicit Type(bits_t bits, ArrayData::ArrayKind) = delete;
262 static bits_t bitsFromDataType(DataType outer, DataType inner);
264 // combine, Union, and Intersect are used for operator| and operator&. See
265 // .cpp for details.
266 template<typename Oper>
267 static Type combine(bits_t newBits, Type a, Type b);
269 struct Union;
270 struct Intersect;
271 struct ArrayOps;
273 public:
274 # define IRT(name, ...) static const Type name;
275 IR_TYPES
276 # undef IRT
278 Type()
279 : m_bits(kBottom)
280 , m_hasConstVal(false)
281 , m_extra(0)
284 explicit Type(DataType outerType, DataType innerType = KindOfInvalid)
285 : m_bits(bitsFromDataType(outerType, innerType))
286 , m_hasConstVal(false)
287 , m_extra(0)
290 explicit Type(const RuntimeType& rtt);
291 explicit Type(const DynLocation* dl);
293 size_t hash() const {
294 return hash_int64_pair(m_bits | (bits_t(m_hasConstVal) << 63), m_extra);
297 Type& operator=(Type b) {
298 m_bits = b.m_bits;
299 m_hasConstVal = b.m_hasConstVal;
300 m_extra = b.m_extra;
301 return *this;
304 std::string constValString() const;
305 std::string toString() const;
306 static std::string debugString(Type t);
307 static Type fromString(const std::string& str);
309 ////////// Support for constants //////////
311 private:
312 // forConst returns the Type to use for a given C++ value. The only
313 // interesting case is int/bool disambiguation. Enums are treated as ints.
314 template<class T>
315 static typename std::enable_if<
316 std::is_integral<T>::value || std::is_enum<T>::value,
317 Type
318 >::type forConst(T) {
319 return std::is_same<T,bool>::value ? Type::Bool : Type::Int;
321 static Type forConst(const HPHP::Func*) { return Func; }
322 static Type forConst(const Class*) { return Cls; }
323 static Type forConst(JIT::TCA) { return TCA; }
324 static Type forConst(double) { return Dbl; }
325 static Type forConst(const StringData* sd) {
326 assert(sd->isStatic());
327 return StaticStr;
329 static Type forConst(const ArrayData* ad) {
330 assert(ad->isStatic());
331 return StaticArr.specialize(ad->kind());
334 public:
335 // Returns true iff this Type represents a known value.
336 bool isConst() const {
337 return m_hasConstVal || subtypeOfAny(Uninit, InitNull, Nullptr);
340 // Returns true iff this Type is a constant value of type t.
341 bool isConst(Type t) const {
342 return subtypeOf(t) && isConst();
345 // Returns true iff this Type represents the constant val, using the same C++
346 // type -> Type mapping as Type::cns().
347 template<typename T>
348 bool isConst(T val) const {
349 return subtypeOf(cns(val));
352 template<typename T>
353 static Type cns(T val, Type ret) {
354 assert(!ret.m_hasConstVal);
355 ret.m_hasConstVal = true;
357 static_assert(sizeof(T) <= sizeof ret,
358 "Constant data was larger than supported");
359 static_assert(std::is_pod<T>::value,
360 "Constant data wasn't a pod");
361 const auto toCopy = constToBits_detail::promoteIfNeeded(val);
362 static_assert(sizeof toCopy == 8,
363 "Unexpected size for toCopy");
364 std::memcpy(&ret.m_extra, &toCopy, sizeof toCopy);
365 return ret;
368 template<typename T>
369 static Type cns(T val) {
370 return cns(val, forConst(val));
373 static Type cns(std::nullptr_t) {
374 return Type::Nullptr;
377 static Type cns(const TypedValue tv) {
378 if (tv.m_type == KindOfUninit) return Type::Uninit;
379 if (tv.m_type == KindOfNull) return Type::InitNull;
381 auto ret = [&] {
382 switch (tv.m_type) {
383 case KindOfClass:
384 case KindOfBoolean:
385 case KindOfInt64:
386 case KindOfDouble:
387 case KindOfStaticString:
388 return Type(tv.m_type);
390 case KindOfString:
391 return forConst(tv.m_data.pstr);
393 case KindOfArray:
394 return forConst(tv.m_data.parr);
396 default:
397 always_assert(false && "Invalid KindOf for constant TypedValue");
399 }();
400 ret.m_hasConstVal = true;
401 ret.m_extra = tv.m_data.num;
402 return ret;
405 // If this represents a constant value, return the most specific strict
406 // supertype of this we can represent. In most cases this just erases the
407 // constant value: Int<4> -> Int, Dbl<2.5> -> Dbl. Arrays are special since
408 // they can be both constant and specialized, so keep the array's kind in the
409 // resulting type.
410 Type dropConstVal() const {
411 if (!m_hasConstVal) return *this;
412 assert(!isUnion());
414 if (subtypeOf(StaticArr)) {
415 return Type::StaticArr.specialize(arrVal()->kind());
417 return Type(m_bits);
420 // Relaxes the type to one that we can check in codegen
421 Type relaxToGuardable() const;
423 bool hasRawVal() const {
424 return m_hasConstVal;
427 uint64_t rawVal() const {
428 assert(m_hasConstVal);
429 return m_intVal;
432 bool boolVal() const {
433 assert(subtypeOf(Bool) && m_hasConstVal);
434 assert(m_boolVal <= 1);
435 return m_boolVal;
438 int64_t intVal() const {
439 assert(subtypeOf(Int) && m_hasConstVal);
440 return m_intVal;
443 double dblVal() const {
444 assert(subtypeOf(Dbl) && m_hasConstVal);
445 return m_dblVal;
448 const StringData* strVal() const {
449 assert(subtypeOf(StaticStr) && m_hasConstVal);
450 return m_strVal;
453 const ArrayData* arrVal() const {
454 assert(subtypeOf(StaticArr) && m_hasConstVal);
455 return m_arrVal;
458 const HPHP::Func* funcVal() const {
459 assert(subtypeOf(Func) && m_hasConstVal);
460 return m_funcVal;
463 const Class* clsVal() const {
464 assert(subtypeOf(Cls) && m_hasConstVal);
465 return m_clsVal;
468 RDS::Handle rdsHandleVal() const {
469 assert(subtypeOf(RDSHandle) && m_hasConstVal);
470 return m_rdsHandleVal;
473 JIT::TCA tcaVal() const {
474 assert(subtypeOf(TCA) && m_hasConstVal);
475 return m_tcaVal;
478 ////////// Methods to query properties of the type //////////
480 bool isBoxed() const {
481 return subtypeOf(BoxedCell);
484 bool notBoxed() const {
485 assert(subtypeOf(Gen));
486 return subtypeOf(Cell);
489 bool maybeBoxed() const {
490 return maybe(BoxedCell);
493 bool isPtr() const {
494 return subtypeOf(PtrToGen);
497 bool notPtr() const {
498 return not(PtrToGen);
501 bool isCounted() const {
502 return subtypeOf(Counted);
505 bool maybeCounted() const {
506 return maybe(Counted);
509 bool notCounted() const {
510 return not(Counted);
514 * Returns true iff this is a union type. Note that this is the plain old set
515 * definition of union, so Type::Str, Type::Arr, and Type::Null will all
516 * return true.
518 bool isUnion() const {
519 // This will return true iff more than 1 bit is set in m_bits.
520 return (m_bits & (m_bits - 1)) != 0;
524 * Returns true if this value has a known constant DataType enum value. If
525 * the type is exactly Type::Str or Type::Null it returns true anyway, even
526 * though it could be either KindOfStaticString or KindOfString, or
527 * KindOfUninit or KindOfNull, respectively.
529 * TODO(#3390819): this function should return false for Str and Null.
531 * Pre: subtypeOf(StackElem)
533 bool isKnownDataType() const {
534 assert(subtypeOf(StackElem));
536 // Some unions that correspond to single KindOfs. And Type::Str
537 // and Type::Null for now for historical reasons.
538 if (subtypeOfAny(Str, Arr, Null, BoxedCell)) {
539 return true;
542 return !isUnion();
546 * Similar to isKnownDataType, with the added restriction that the type not
547 * be Boxed.
549 bool isKnownUnboxedDataType() const {
550 return isKnownDataType() && notBoxed();
554 * Returns true if this requires a register to hold a DataType at runtime.
556 bool needsReg() const {
557 return subtypeOf(StackElem) && !isKnownDataType();
560 bool needsValueReg() const {
561 return !subtypeOfAny(Uninit, InitNull, Nullptr);
564 bool needsStaticBitCheck() const {
565 return maybe(StaticStr | StaticArr);
568 bool canRunDtor() const {
569 return maybe(CountedArr | BoxedCountedArr | Obj | BoxedObj |
570 Res | BoxedRes);
573 // return true if this corresponds to a type that is passed by value in C++
574 bool isSimpleType() const {
575 return subtypeOfAny(Bool, Int, Dbl, Null);
578 // return true if this corresponds to a type that is passed by reference in
579 // C++
580 bool isReferenceType() const {
581 return subtypeOfAny(Str, Arr, Obj, Res);
584 int nativeSize() const {
585 if (subtypeOf(Type::Int | Type::Func)) return sz::qword;
586 if (subtypeOf(Type::Bool)) return sz::byte;
587 not_implemented();
590 ////////// Support for specialized types: Obj classes and Arr kinds //////////
593 * True if type can have a specialized class.
595 bool canSpecializeClass() const {
596 return (m_bits & kAnyObj) && !(m_bits & kAnyArr);
600 * True if type can have specialized array information.
602 bool canSpecializeArray() const {
603 return (m_bits & kAnyArr) && !(m_bits & kAnyObj);
606 bool canSpecializeAny() const {
607 return canSpecializeClass() || canSpecializeArray();
610 Type specialize(const Class* klass) const {
611 assert(canSpecializeClass() && m_class == nullptr);
612 return Type(m_bits, klass);
615 Type specialize(ArrayData::ArrayKind arrayKind) const {
616 assert(canSpecializeArray());
617 return Type(m_bits, makeArrayInfo(arrayKind, nullptr));
620 Type specialize(const RepoAuthType::Array* array) const {
621 assert(canSpecializeArray());
622 return Type(m_bits, makeArrayInfo(folly::none, array));
625 bool isSpecialized() const {
626 return (canSpecializeClass() && getClass()) ||
627 (canSpecializeArray() && (hasArrayKind() || getArrayType()));
630 Type unspecialize() const {
631 return Type(m_bits);
634 const Class* getClass() const {
635 assert(canSpecializeClass());
636 return m_class;
639 bool hasArrayKind() const {
640 assert(canSpecializeArray());
641 return m_hasConstVal || arrayKindValid(m_arrayInfo);
644 ArrayData::ArrayKind getArrayKind() const {
645 assert(hasArrayKind());
646 return m_hasConstVal ? m_arrVal->kind() : kind(m_arrayInfo);
649 folly::Optional<ArrayData::ArrayKind> getOptArrayKind() const {
650 if (hasArrayKind()) return getArrayKind();
651 return folly::none;
654 const RepoAuthType::Array* getArrayType() const {
655 assert(canSpecializeArray());
656 return m_hasConstVal ? nullptr : arrayType(m_arrayInfo);
659 // Returns a subset of *this containing only the members relating to its
660 // specialization.
662 // {Int|Str|Obj<C>|BoxedObj<C>}.specializedType() == {Obj<C>|BoxedObj<C>}
663 Type specializedType() const {
664 assert(isSpecialized());
665 if (canSpecializeClass()) return *this & AnyObj;
666 if (canSpecializeArray()) return *this & AnyArr;
667 not_reached();
670 ////////// Methods for comparing types //////////
673 * Returns true iff this represents a non-strict subset of t2.
675 bool subtypeOf(Type t2) const;
677 template<typename... Types>
678 bool subtypeOfAny(Type t2, Types... ts) const {
679 return subtypeOf(t2) || subtypeOfAny(ts...);
682 bool subtypeOfAny() const {
683 return false;
687 * Returns true if this is a strict subtype of t2.
689 bool strictSubtypeOf(Type t2) const {
690 return *this != t2 && subtypeOf(t2);
694 * Returns true if any subtype of this is a subtype of t2.
696 bool maybe(Type t2) const {
697 return (*this & t2) != Bottom;
701 * Returns true if no subtypes of this are subtypes of t2.
703 bool not(Type t2) const {
704 return !maybe(t2);
708 * Returns true if this is exactly equal to t2. Be careful: you
709 * probably mean subtypeOf.
711 bool equals(Type t2) const {
712 return m_bits == t2.m_bits && m_hasConstVal == t2.m_hasConstVal &&
713 m_extra == t2.m_extra;
716 bool operator==(Type t2) const { return equals(t2); }
717 bool operator!=(Type t2) const { return !operator==(t2); }
719 ////////// Methods for combining Types in various ways //////////
722 * Standard set operations: union, intersection, and difference.
724 Type operator|(Type other) const;
725 Type& operator|=(Type other) { return *this = *this | other; }
727 Type operator&(Type other) const;
728 Type& operator&=(Type other) { return *this = *this & other; }
730 Type operator-(Type other) const;
731 Type& operator-=(Type other) { return *this = *this - other; }
734 * unionOf: return the least common predefined supertype of t1 and t2,
735 * i.e.. the most refined type t3 such that t1 <= t3 and t2 <= t3. Note that
736 * arbitrary union types are possible using operator| but this function
737 * always returns one of the predefined types.
739 static Type unionOf(Type t1, Type t2);
741 ////////// Support for inner types of boxed and pointer types //////////
743 Type box() const {
744 assert(subtypeOf(Cell));
745 // Boxing Uninit returns InitNull but that logic doesn't belong
746 // here.
747 assert(not(Uninit) || equals(Cell));
748 return Type(m_bits << kBoxShift,
749 isSpecialized() && !m_hasConstVal ? m_extra : 0);
752 // This computes the type effects of the Unbox opcode.
753 Type unbox() const {
754 assert(subtypeOf(Gen));
755 return (*this & Cell) | (*this & BoxedCell).innerType();
758 Type innerType() const {
759 assert(isBoxed() || equals(Bottom));
760 return Type(m_bits >> kBoxShift, m_extra);
763 Type deref() const {
764 assert(isPtr());
765 return Type(m_bits >> kPtrShift, isSpecialized() ? m_extra : 0);
768 Type derefIfPtr() const {
769 assert(subtypeOf(Gen | PtrToGen));
770 return isPtr() ? deref() : *this;
773 // Returns the "stripped" version of this: dereferenced and unboxed,
774 // if applicable.
775 Type strip() const {
776 return derefIfPtr().unbox();
779 Type ptr() const {
780 assert(!isPtr());
781 assert(subtypeOf(Gen));
782 return Type(m_bits << kPtrShift,
783 isSpecialized() && !m_hasConstVal ? m_extra : 0);
786 ////////// Methods for talking to other type systems in the VM //////////
789 * TODO(#3390819): this function does not exactly convert this type into a
790 * DataType in cases where a type does not exactly map to a DataType. For
791 * example, Null.toDataType() returns KindOfNull, even though it could be
792 * KindOfUninit.
794 * Try not to use this function in new code.
796 DataType toDataType() const;
798 RuntimeType toRuntimeType() const;
801 typedef folly::Optional<Type> OptType;
803 inline bool operator<(Type a, Type b) { return a.strictSubtypeOf(b); }
804 inline bool operator>(Type a, Type b) { return b.strictSubtypeOf(a); }
805 inline bool operator<=(Type a, Type b) { return a.subtypeOf(b); }
806 inline bool operator>=(Type a, Type b) { return b.subtypeOf(a); }
809 * JIT::Type must be small enough for efficient pass-by-value.
811 static_assert(sizeof(Type) <= 2 * sizeof(uint64_t),
812 "JIT::Type should fit in (2 * sizeof(uint64_t))");
815 * Return the most refined type that can be used to represent the type
816 * in a live TypedValue.
818 Type liveTVType(const TypedValue* tv);
821 * Return the boxed version of the input type, taking into account php
822 * semantics and subtle implementation details.
824 Type boxType(Type);
827 * Create a Type from a RepoAuthType.
829 Type convertToType(RepoAuthType ty);
832 * Return the type resulting from refining oldType with the fact that it also
833 * belongs to newType. This essentially intersects the two types, except that
834 * it has special logic for boxed types.
836 Type refineType(Type oldType, Type newType);
838 //////////////////////////////////////////////////////////////////////
840 struct TypeConstraint {
841 /* implicit */ TypeConstraint(DataTypeCategory cat = DataTypeGeneric,
842 DataTypeCategory inner = DataTypeGeneric)
843 : category(cat)
844 , innerCat(inner)
845 , weak(false)
846 , m_specialized(0)
849 explicit TypeConstraint(const Class* cls)
850 : TypeConstraint(DataTypeSpecialized)
852 setDesiredClass(cls);
855 void applyConstraint(TypeConstraint newTc);
857 std::string toString() const;
859 TypeConstraint& setWeak(bool w = true) {
860 weak = w;
861 return *this;
864 bool operator==(TypeConstraint tc2) const {
865 return category == tc2.category && innerCat == tc2.innerCat &&
866 weak == tc2.weak && m_specialized == tc2.m_specialized;
868 bool operator!=(TypeConstraint tc2) const { return !(*this == tc2); }
870 bool empty() const {
871 return category == DataTypeGeneric && innerCat == DataTypeGeneric && !weak;
874 static constexpr uint8_t kWantArrayKind = 0x1;
876 TypeConstraint& setWantArrayKind() {
877 assert(!wantClass());
878 assert(category == DataTypeSpecialized);
879 m_specialized |= kWantArrayKind;
880 return *this;
883 bool wantArrayKind() const { return m_specialized & kWantArrayKind; }
885 TypeConstraint& setDesiredClass(const Class* cls) {
886 assert(m_specialized == 0 ||
887 desiredClass()->classof(cls) || cls->classof(desiredClass()));
888 assert(category == DataTypeSpecialized || innerCat == DataTypeSpecialized);
889 m_specialized = reinterpret_cast<uintptr_t>(cls);
890 assert(wantClass());
891 return *this;
894 bool wantClass() const {
895 return m_specialized != 0 && !wantArrayKind();
898 const Class* desiredClass() const {
899 assert(wantClass());
900 return reinterpret_cast<const Class*>(m_specialized);
903 // Get the inner constraint, preserving m_specialized if appropriate.
904 TypeConstraint inner() const {
905 auto tc = TypeConstraint{innerCat}.setWeak(weak);
906 if (tc.category == DataTypeSpecialized) tc.m_specialized = m_specialized;
907 return tc;
910 // category starts as DataTypeGeneric and is refined to more specific values
911 // by consumers of the type.
912 DataTypeCategory category;
914 // When a value is boxed, innerCat is used to determine how we can relax the
915 // inner type. innerCat is only meaningful when category is at least
916 // DataTypeCountness, since a category of DataTypeGeneric relaxes types all
917 // the way to Gen which has no meaningful inner type.
918 DataTypeCategory innerCat;
920 // If weak is true, the consumer of the value being constrained doesn't
921 // actually want to constrain the guard (if found). Most often used to figure
922 // out if a type can be used without further constraining guards.
923 bool weak;
925 private:
926 // m_specialized either holds a Class* or a 1 in its low bit, indicating that
927 // for a DataTypeSpecialized constraint, we require the specified class or an
928 // array kind, respectively.
929 uintptr_t m_specialized;
932 const int kTypeWordOffset = offsetof(TypedValue, m_type) % 8;
933 const int kTypeShiftBits = kTypeWordOffset * CHAR_BIT;
935 // left shift an immediate DataType, for type, to the correct position
936 // within one of the registers used to pass a TypedValue by value.
937 inline uint64_t toDataTypeForCall(Type type) {
938 return uint64_t(type.toDataType()) << kTypeShiftBits;
944 #endif