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_JIT_TYPE_INL_H_
18 #error "type-inl.h should only be included by type.h"
21 #include "hphp/runtime/base/bespoke-array.h"
22 #include "hphp/runtime/base/string-data.h"
23 #include "hphp/runtime/vm/class.h"
24 #include "hphp/runtime/vm/class-meth-data-ref.h"
26 #include "hphp/util/hash.h"
31 ///////////////////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////////////////
36 constexpr inline Type::Type(bits_t bits
, PtrLocation ptr
)
39 , m_hasConstVal(false)
43 #define IRT(name, ...) \
44 constexpr Type T##name{Type::k##name, PtrLocation::Bottom};
45 #define IRTP(name, ptr) \
46 constexpr Type T##name{Type::kPtr, PtrLocation::ptr};
47 #define IRTL(name, ptr) \
48 constexpr Type T##name{Type::kLval, PtrLocation::ptr};
49 #define IRTM(name, ptr) \
50 constexpr Type T##name{Type::kMem, PtrLocation::ptr};
51 #define IRTX(name, x, bits) \
52 constexpr Type T##name{Type::bits, PtrLocation::x};
63 #define IRT(name, ...) \
64 constexpr Type T##name{Type::k##name, PtrLocation::Bottom};
68 // Vanilla types that appear in irgen.
69 static auto const TVanillaVec
= TVec
.narrowToVanilla();
70 static auto const TVanillaDict
= TDict
.narrowToVanilla();
71 static auto const TVanillaKeyset
= TKeyset
.narrowToVanilla();
72 static auto const TVanillaArrLike
= TArrLike
.narrowToVanilla();
75 * Abbreviated namespace for predefined types.
77 * Used for macro codegen for types declared in ir.specification.
80 #define IRT(name, ...) UNUSED constexpr Type name = T##name;
81 #define IRTP(name, ...) IRT(name)
82 #define IRTL(name, ...) IRT(name)
83 #define IRTM(name, ...) IRT(name)
84 #define IRTX(name, ...) IRT(name)
93 namespace type_detail
{
94 ///////////////////////////////////////////////////////////////////////////////
97 * Widen a constant value if needed.
100 using needs_promotion
= std::integral_constant
<
102 (std::is_integral
<T
>::value
||
103 std::is_same
<T
,bool>::value
||
104 std::is_enum
<T
>::value
)
108 typename
std::enable_if
<needs_promotion
<T
>::value
,uint64_t>::type
109 promote_cns_if_needed(T t
) { return static_cast<uint64_t>(t
); }
112 typename
std::enable_if
<!needs_promotion
<T
>::value
,T
>::type
113 promote_cns_if_needed(T t
) { return t
; }
116 * Return the Type to use for a given C++ value.
118 * The only interesting case is int/bool disambiguation. Enums are treated as
122 typename
std::enable_if
<
123 std::is_integral
<T
>::value
|| std::is_enum
<T
>::value
,
125 >::type
for_const(T
) {
126 return std::is_same
<T
,bool>::value
? TBool
: TInt
;
128 inline Type
for_const(const StringData
* sd
) {
129 assertx(sd
->isStatic());
132 inline Type
for_const(const ArrayData
* ad
) {
133 assertx(ad
->isStatic());
134 if (ad
->isVecType()) return TStaticVec
;
135 if (ad
->isDictType()) return TStaticDict
;
136 if (ad
->isKeysetType()) return TStaticKeyset
;
139 inline Type
for_const(double) { return TDbl
; }
140 inline Type
for_const(const Func
*) { return TFunc
; }
141 inline Type
for_const(const Class
*) { return TCls
; }
142 inline Type
for_const(LazyClassData
) { return TLazyCls
; }
143 inline Type
for_const(ClsMethDataRef
) { return TClsMeth
; }
144 inline Type
for_const(TCA
) { return TTCA
; }
145 inline Type
for_const(void*) { return TVoidPtr
; }
146 ///////////////////////////////////////////////////////////////////////////////
149 ///////////////////////////////////////////////////////////////////////////////
154 , m_ptr(PtrLocation::Bottom
)
155 , m_hasConstVal(false)
159 inline Type::Type(DataType outer
)
160 : m_bits(bitsFromDataType(outer
))
161 , m_ptr(PtrLocation::Bottom
)
162 , m_hasConstVal(false)
166 inline size_t Type::hash() const {
167 return hash_int64_pair(
170 static_cast<uint64_t>(m_ptr
) ^ m_hasConstVal
176 ///////////////////////////////////////////////////////////////////////////////
179 inline bool Type::operator==(Type rhs
) const {
180 return m_bits
== rhs
.m_bits
&&
181 m_ptr
== rhs
.m_ptr
&&
182 m_hasConstVal
== rhs
.m_hasConstVal
&&
183 m_extra
== rhs
.m_extra
;
186 inline bool Type::operator!=(Type rhs
) const {
187 return !operator==(rhs
);
190 inline bool Type::operator>=(Type rhs
) const {
194 inline bool Type::operator<(Type rhs
) const {
195 return *this != rhs
&& *this <= rhs
;
198 inline bool Type::operator>(Type rhs
) const {
202 template<typename
... Types
>
203 bool Type::subtypeOfAny(Type t2
, Types
... ts
) const {
204 return *this <= t2
|| subtypeOfAny(ts
...);
206 inline bool Type::subtypeOfAny() const {
210 inline bool Type::nonTrivialSubtypeOf(Type t2
) const {
211 return !(*this <= TBottom
) && (*this <= t2
);
214 inline bool Type::maybe(Type t2
) const {
215 return (*this & t2
) != TBottom
;
218 ///////////////////////////////////////////////////////////////////////////////
221 inline Type
Type::unionAll() {
225 template<typename
... Types
>
226 inline Type
Type::unionAll(Type t
, Types
... ts
) {
227 return t
| unionAll(ts
...);
230 ///////////////////////////////////////////////////////////////////////////////
233 inline bool Type::isUnion() const {
234 // This will return true iff more than 1 bit is set in m_bits.
235 return m_bits
.count() > 1;
238 inline bool Type::isKnownDataType() const {
239 assertx(*this <= TCell
);
241 // Some unions correspond to single KindOfs.
242 if (!isUnion()) return true;
243 return subtypeOfAny(TStr
, TVec
, TDict
, TKeyset
);
246 inline bool Type::needsReg() const {
247 return *this <= TCell
&& !isKnownDataType();
250 inline bool Type::isSimpleType() const {
251 return subtypeOfAny(TBool
, TInt
, TDbl
, TNull
);
254 inline bool Type::isReferenceType() const {
255 return subtypeOfAny(TStr
, TArrLike
, TObj
, TRes
);
258 ///////////////////////////////////////////////////////////////////////////////
259 // Constant type creation.
262 Type
Type::cns(T val
, Type ret
) {
263 assertx(!ret
.m_hasConstVal
);
264 ret
.m_hasConstVal
= true;
266 static_assert(sizeof(T
) <= sizeof(ret
),
267 "Constant data was larger than supported");
268 static_assert(std::is_pod
<T
>::value
,
269 "Constant data wasn't a pod");
271 const auto toCopy
= type_detail::promote_cns_if_needed(val
);
272 static_assert(sizeof(toCopy
) == 8,
273 "Unexpected size for toCopy");
275 std::memcpy(&ret
.m_extra
, &toCopy
, sizeof(toCopy
));
276 assertx(ret
.checkValid());
281 Type
Type::cns(T val
) {
282 return cns(val
, type_detail::for_const(val
));
285 inline Type
Type::cns(std::nullptr_t
) {
289 inline Type
Type::cns(TypedValue tv
) {
290 if (auto const t
= tryCns(tv
)) return *t
;
291 always_assert(false && "Invalid KindOf for constant TypedValue");
294 inline Optional
<Type
> Type::tryCns(TypedValue tv
) {
295 assertx(tvIsPlausible(tv
));
297 if (tv
.m_type
== KindOfUninit
) return TUninit
;
298 if (tv
.m_type
== KindOfNull
) return TInitNull
;
300 auto ret
= [&] () -> Optional
<Type
> {
309 return Type(tv
.m_type
);
311 case KindOfPersistentString
:
313 return type_detail::for_const(tv
.m_data
.pstr
);
315 case KindOfPersistentVec
:
317 case KindOfPersistentDict
:
319 case KindOfPersistentKeyset
:
321 return type_detail::for_const(tv
.m_data
.parr
);
322 case KindOfLazyClass
:
323 return type_detail::for_const(tv
.m_data
.plazyclass
);
326 return type_detail::for_const(tv
.m_data
.pfunc
);
328 return type_detail::for_const(tv
.m_data
.pclass
);
330 return type_detail::for_const(tv
.m_data
.pclsmeth
);
341 ret
->m_hasConstVal
= true;
342 ret
->m_extra
= tv
.m_data
.num
;
347 inline Type
Type::dropConstVal() const {
348 if (!m_hasConstVal
) return *this;
351 auto const result
= Type(m_bits
, ptrLocation());
353 if (*this <= TArrLike
) {
354 return Type(result
, ArraySpec(ArrayLayout::FromArray(m_arrVal
)));
359 ///////////////////////////////////////////////////////////////////////////////
360 // Constant introspection.
362 inline bool Type::hasConstVal() const {
363 return m_hasConstVal
;
366 inline bool Type::hasConstVal(Type t
) const {
367 return hasConstVal() && *this <= t
;
371 bool Type::hasConstVal(T val
) const {
372 return hasConstVal(cns(val
));
375 inline bool Type::admitsSingleVal() const {
376 return hasConstVal() || subtypeOfAny(TNullptr
, TInitNull
, TUninit
);
379 inline uint64_t Type::rawVal() const {
380 assertx(hasConstVal());
384 #define IMPLEMENT_CNS_VAL(TypeName, name, valtype) \
385 inline valtype Type::name##Val() const { \
386 assertx(hasConstVal(TypeName)); \
387 return m_##name##Val; \
390 IMPLEMENT_CNS_VAL(TBool
, bool, bool)
391 IMPLEMENT_CNS_VAL(TInt
, int, int64_t)
392 IMPLEMENT_CNS_VAL(TDbl
, dbl
, double)
393 IMPLEMENT_CNS_VAL(TStaticStr
, str
, const StringData
*)
394 IMPLEMENT_CNS_VAL(TStaticVec
, vec
, const ArrayData
*)
395 IMPLEMENT_CNS_VAL(TStaticDict
, dict
, const ArrayData
*)
396 IMPLEMENT_CNS_VAL(TStaticKeyset
, keyset
, const ArrayData
*)
397 IMPLEMENT_CNS_VAL(TFunc
, func
, const HPHP::Func
*)
398 IMPLEMENT_CNS_VAL(TCls
, cls
, const Class
*)
399 IMPLEMENT_CNS_VAL(TLazyCls
, lcls
, LazyClassData
)
400 IMPLEMENT_CNS_VAL(TClsMeth
, clsmeth
, ClsMethDataRef
)
401 IMPLEMENT_CNS_VAL(TTCA
, tca
, jit::TCA
)
402 IMPLEMENT_CNS_VAL(TVoidPtr
, voidPtr
, void*)
403 IMPLEMENT_CNS_VAL(TRDSHandle
, rdsHandle
, rds::Handle
)
404 IMPLEMENT_CNS_VAL(TMem
, ptr
, const TypedValue
*)
406 #undef IMPLEMENT_CNS_VAL
408 ///////////////////////////////////////////////////////////////////////////////
409 // Specialized type creation.
411 inline Type
Type::Vec(const RepoAuthType::Array
* rat
) {
412 return Type(TVec
, ArraySpec(rat
));
415 inline Type
Type::Dict(const RepoAuthType::Array
* rat
) {
416 return Type(TDict
, ArraySpec(rat
));
419 inline Type
Type::Keyset(const RepoAuthType::Array
* rat
) {
420 return Type(TKeyset
, ArraySpec(rat
));
423 inline Type
Type::StaticVec(const RepoAuthType::Array
* rat
) {
424 return Type(TStaticVec
, ArraySpec(rat
));
427 inline Type
Type::StaticDict(const RepoAuthType::Array
* rat
) {
428 return Type(TStaticDict
, ArraySpec(rat
));
431 inline Type
Type::StaticKeyset(const RepoAuthType::Array
* rat
) {
432 return Type(TStaticKeyset
, ArraySpec(rat
));
435 inline Type
Type::CountedVec(const RepoAuthType::Array
* rat
) {
436 return Type(TCountedVec
, ArraySpec(rat
));
439 inline Type
Type::CountedDict(const RepoAuthType::Array
* rat
) {
440 return Type(TCountedDict
, ArraySpec(rat
));
443 inline Type
Type::CountedKeyset(const RepoAuthType::Array
* rat
) {
444 return Type(TCountedKeyset
, ArraySpec(rat
));
447 inline Type
Type::SubObj(const Class
* cls
) {
448 if (cls
->attrs() & AttrNoOverride
) return ExactObj(cls
);
449 return Type(TObj
, ClassSpec(cls
, ClassSpec::SubTag
{}));
452 inline Type
Type::ExactObj(const Class
* cls
) {
453 return Type(TObj
, ClassSpec(cls
, ClassSpec::ExactTag
{}));
456 inline Type
Type::SubCls(const Class
* cls
) {
457 if (cls
->attrs() & AttrNoOverride
) return ExactCls(cls
);
458 return Type(TCls
, ClassSpec(cls
, ClassSpec::SubTag
{}));
461 inline Type
Type::ExactCls(const Class
* cls
) {
462 return Type::cns(cls
);
465 inline Type
Type::unspecialize() const {
466 return Type(m_bits
, ptrLocation());
469 ///////////////////////////////////////////////////////////////////////////////
470 // Specialization introspection.
472 inline bool Type::isSpecialized() const {
473 return clsSpec() || arrSpec();
476 inline bool Type::supports(bits_t bits
, SpecKind kind
) {
480 case SpecKind::Array
:
481 return (bits
& kArrSpecBits
) != kBottom
;
482 case SpecKind::Class
:
483 return (bits
& kClsSpecBits
) != kBottom
;
488 inline bool Type::supports(SpecKind kind
) const {
489 return supports(m_bits
, kind
);
492 inline ArraySpec
Type::arrSpec() const {
493 if (!supports(SpecKind::Array
)) return ArraySpec::Bottom();
495 // Currently, a Type which supports multiple specializations is trivial
496 // along all of them.
497 if (supports(SpecKind::Class
)) return ArraySpec::Top();
499 // For constant pointers, we don't have an array-like val, so return Top.
500 // Else, use the layout of the array val. (We pun array-like types here.)
502 if (m_bits
& kMem
) return ArraySpec::Top();
503 return ArraySpec(ArrayLayout::FromArray(m_arrVal
));
506 assertx(m_arrSpec
!= ArraySpec::Bottom());
510 inline ClassSpec
Type::clsSpec() const {
511 if (!supports(SpecKind::Class
)) return ClassSpec::Bottom();
513 // Currently, a Type which supports multiple specializations is trivial
514 // along all of them.
515 if (supports(SpecKind::Array
)) return ClassSpec::Top();
518 if (m_bits
& kMem
) return ClassSpec::Top();
519 return ClassSpec(clsVal(), ClassSpec::ExactTag
{});
522 assertx(m_clsSpec
!= ClassSpec::Bottom());
526 inline TypeSpec
Type::spec() const {
527 return TypeSpec(arrSpec(), clsSpec());
530 ///////////////////////////////////////////////////////////////////////////////
533 inline PtrLocation
Type::ptrLocation() const {
537 inline Type
Type::ptrToLval() const {
539 if (temp
.m_bits
& kPtr
) {
540 temp
.m_bits
&= ~kPtr
;
541 temp
.m_bits
|= kLval
;
546 inline Type
Type::lvalToPtr() const {
548 if (temp
.m_bits
& kLval
) {
549 temp
.m_bits
&= ~kLval
;
555 ///////////////////////////////////////////////////////////////////////////////
556 // Private constructors.
558 inline Type::Type(bits_t bits
, PtrLocation ptr
, bool hasConstVal
,
562 , m_hasConstVal(hasConstVal
)
565 assertx(checkValid());
568 inline Type::Type(Type t
, ArraySpec arraySpec
)
571 , m_hasConstVal(false)
572 , m_arrSpec(arraySpec
)
574 assertx(checkValid());
575 assertx(m_arrSpec
!= ArraySpec::Bottom());
578 inline Type::Type(Type t
, ClassSpec classSpec
)
581 , m_hasConstVal(false)
582 , m_clsSpec(classSpec
)
584 assertx(checkValid());
585 assertx(m_clsSpec
!= ClassSpec::Bottom());
588 ///////////////////////////////////////////////////////////////////////////////