2 +----------------------------------------------------------------------+
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_INL_H_
18 #error "type-inl.h should only be included by type.h"
21 #include "hphp/runtime/base/string-data.h"
22 #include "hphp/runtime/vm/class.h"
24 #include "hphp/util/hash.h"
28 namespace HPHP
{ namespace jit
{
29 ///////////////////////////////////////////////////////////////////////////////
31 ///////////////////////////////////////////////////////////////////////////////
34 constexpr inline Type::Type(bits_t bits
, Ptr kind
)
36 , m_ptrKind(static_cast<std::underlying_type
<Ptr
>::type
>(kind
))
37 , m_hasConstVal(false)
41 #define IRT(name, ...) constexpr Type T##name{Type::k##name, Ptr::Unk};
42 #define IRTP(name, ptr, ...) constexpr Type T##name{Type::k##name, Ptr::ptr};
48 * Abbreviated namespace for predefined types.
50 * Used for macro codegen for types declared in ir.specification.
53 #define IRT(name, ...) UNUSED constexpr Type name = T##name;
54 #define IRTP(name, ...) IRT(name)
60 namespace type_detail
{
61 ///////////////////////////////////////////////////////////////////////////////
64 * Widen a constant value if needed.
67 using needs_promotion
= std::integral_constant
<
69 (std::is_integral
<T
>::value
||
70 std::is_same
<T
,bool>::value
||
71 std::is_enum
<T
>::value
)
75 typename
std::enable_if
<needs_promotion
<T
>::value
,uint64_t>::type
76 promote_cns_if_needed(T t
) { return static_cast<uint64_t>(t
); }
79 typename
std::enable_if
<!needs_promotion
<T
>::value
,T
>::type
80 promote_cns_if_needed(T t
) { return t
; }
83 * Return the Type to use for a given C++ value.
85 * The only interesting case is int/bool disambiguation. Enums are treated as
89 typename
std::enable_if
<
90 std::is_integral
<T
>::value
|| std::is_enum
<T
>::value
,
92 >::type
for_const(T
) {
93 return std::is_same
<T
,bool>::value
? TBool
: TInt
;
95 inline Type
for_const(const StringData
* sd
) {
96 assertx(sd
->isStatic());
99 inline Type
for_const(const ArrayData
* ad
) {
100 assertx(ad
->isStatic());
101 return Type::StaticArray(ad
->kind());
103 inline Type
for_const(double) { return TDbl
; }
104 inline Type
for_const(const Func
*) { return TFunc
; }
105 inline Type
for_const(const Class
*) { return TCls
; }
106 inline Type
for_const(ConstCctx
) { return TCctx
; }
107 inline Type
for_const(TCA
) { return TTCA
; }
109 ///////////////////////////////////////////////////////////////////////////////
112 ///////////////////////////////////////////////////////////////////////////////
115 inline Ptr
add_ref(Ptr p
) {
116 if (p
== Ptr::Unk
|| p
== Ptr::ClsInit
|| p
== Ptr::ClsCns
) {
119 return static_cast<Ptr
>(static_cast<uint32_t>(p
) | kPtrRefBit
);
122 inline Ptr
remove_ref(Ptr p
) {
123 // If p is unknown or Ptr::Ref, we'll get back unknown. Note that this is not
124 // the same as subtracting Ptr::Ref from p.
125 return static_cast<Ptr
>(static_cast<uint32_t>(p
) & ~kPtrRefBit
);
129 * For use in this file.
131 bool ptr_subtype(Ptr
, Ptr
);
133 ///////////////////////////////////////////////////////////////////////////////
139 , m_hasConstVal(false)
143 inline Type::Type(DataType outer
, DataType inner
)
144 : m_bits(bitsFromDataType(outer
, inner
))
146 , m_hasConstVal(false)
150 inline Type::Type(DataType outer
, KindOfAny
)
151 : m_bits(outer
== KindOfRef
? kBoxedCell
152 : bitsFromDataType(outer
, KindOfUninit
))
154 , m_hasConstVal(false)
158 inline Type
& Type::operator=(Type b
) {
160 m_hasConstVal
= b
.m_hasConstVal
;
161 m_ptrKind
= b
.m_ptrKind
;
166 inline size_t Type::hash() const {
167 return hash_int64_pair(m_rawInt
, m_extra
);
170 ///////////////////////////////////////////////////////////////////////////////
173 inline bool Type::operator==(Type rhs
) const {
174 return m_rawInt
== rhs
.m_rawInt
&& m_extra
== rhs
.m_extra
;
177 inline bool Type::operator!=(Type rhs
) const {
178 return !operator==(rhs
);
181 inline bool Type::operator<=(Type rhs
) const {
184 // Check for any members in lhs.m_bits that aren't in rhs.m_bits.
185 if ((lhs
.m_bits
& rhs
.m_bits
) != lhs
.m_bits
) {
189 // Check for Bottom; all the remaining cases assume `lhs' is not Bottom.
190 if (lhs
.m_bits
== kBottom
) return true;
192 // If `rhs' is a constant, we must be the same constant.
193 if (rhs
.m_hasConstVal
) {
194 assertx(!rhs
.isUnion());
195 return lhs
.m_hasConstVal
&& lhs
.m_extra
== rhs
.m_extra
;
198 // If `rhs' could be a pointer, we must have a subtype relation in pointer
199 // kinds or we're not a subtype. (If `lhs' can't be a pointer, we found out
200 // above when we intersected the bits.) If neither can be a pointer, it's an
201 // invariant that `m_ptrKind' will be Ptr::Unk so this will pass.
202 if (lhs
.ptrKind() != rhs
.ptrKind() &&
203 !ptr_subtype(lhs
.ptrKind(), rhs
.ptrKind())) {
207 // Compare specializations only if `rhs' is specialized.
208 return !rhs
.isSpecialized() || lhs
.spec() <= rhs
.spec();
211 inline bool Type::operator>=(Type rhs
) const {
215 inline bool Type::operator<(Type rhs
) const {
216 return *this != rhs
&& *this <= rhs
;
219 inline bool Type::operator>(Type rhs
) const {
223 template<typename
... Types
>
224 bool Type::subtypeOfAny(Type t2
, Types
... ts
) const {
225 return *this <= t2
|| subtypeOfAny(ts
...);
227 inline bool Type::subtypeOfAny() const {
231 inline bool Type::maybe(Type t2
) const {
232 return (*this & t2
) != TBottom
;
235 ///////////////////////////////////////////////////////////////////////////////
238 inline bool Type::isUnion() const {
239 // This will return true iff more than 1 bit is set in m_bits.
240 return (m_bits
& (m_bits
- 1)) != 0;
243 inline bool Type::isKnownDataType() const {
244 assertx(*this <= TStkElem
);
246 // Some unions correspond to single KindOfs.
247 return subtypeOfAny(TStr
, TArr
, TBoxedCell
) || !isUnion();
250 inline bool Type::needsReg() const {
251 return *this <= TStkElem
&& !isKnownDataType();
254 inline bool Type::isSimpleType() const {
255 return subtypeOfAny(TBool
, TInt
, TDbl
, TNull
);
258 inline bool Type::isReferenceType() const {
259 return subtypeOfAny(TStr
, TArr
, TObj
, TRes
);
262 ///////////////////////////////////////////////////////////////////////////////
263 // Constant type creation.
266 Type
Type::cns(T val
, Type ret
) {
267 assertx(!ret
.m_hasConstVal
);
268 ret
.m_hasConstVal
= true;
270 static_assert(sizeof(T
) <= sizeof(ret
),
271 "Constant data was larger than supported");
272 static_assert(std::is_pod
<T
>::value
,
273 "Constant data wasn't a pod");
275 const auto toCopy
= type_detail::promote_cns_if_needed(val
);
276 static_assert(sizeof(toCopy
) == 8,
277 "Unexpected size for toCopy");
279 std::memcpy(&ret
.m_extra
, &toCopy
, sizeof(toCopy
));
284 Type
Type::cns(T val
) {
285 return cns(val
, type_detail::for_const(val
));
288 inline Type
Type::cns(std::nullptr_t
) {
292 inline Type
Type::cns(const TypedValue
& tv
) {
293 if (tv
.m_type
== KindOfUninit
) return TUninit
;
294 if (tv
.m_type
== KindOfNull
) return TInitNull
;
306 case KindOfStaticString
:
307 return Type(tv
.m_type
);
310 return type_detail::for_const(tv
.m_data
.pstr
);
313 return type_detail::for_const(tv
.m_data
.parr
);
318 always_assert(false && "Invalid KindOf for constant TypedValue");
322 ret
.m_hasConstVal
= true;
323 ret
.m_extra
= tv
.m_data
.num
;
327 inline Type
Type::dropConstVal() const {
328 if (!m_hasConstVal
) return *this;
331 if (*this <= TStaticArr
) {
332 return Type::StaticArray(arrVal()->kind());
334 return Type(m_bits
, ptrKind());
337 ///////////////////////////////////////////////////////////////////////////////
338 // Constant introspection.
340 inline bool Type::hasConstVal() const {
341 return m_hasConstVal
;
344 inline bool Type::hasConstVal(Type t
) const {
345 return hasConstVal() && *this <= t
;
349 bool Type::hasConstVal(T val
) const {
350 return hasConstVal(cns(val
));
353 inline uint64_t Type::rawVal() const {
354 assertx(hasConstVal());
358 #define IMPLEMENT_CNS_VAL(TypeName, name, valtype) \
359 inline valtype Type::name##Val() const { \
360 assertx(hasConstVal(TypeName)); \
361 return m_##name##Val; \
364 IMPLEMENT_CNS_VAL(TBool
, bool, bool)
365 IMPLEMENT_CNS_VAL(TInt
, int, int64_t)
366 IMPLEMENT_CNS_VAL(TDbl
, dbl
, double)
367 IMPLEMENT_CNS_VAL(TStaticStr
, str
, const StringData
*)
368 IMPLEMENT_CNS_VAL(TStaticArr
, arr
, const ArrayData
*)
369 IMPLEMENT_CNS_VAL(TFunc
, func
, const HPHP::Func
*)
370 IMPLEMENT_CNS_VAL(TCls
, cls
, const Class
*)
371 IMPLEMENT_CNS_VAL(TCctx
, cctx
, ConstCctx
)
372 IMPLEMENT_CNS_VAL(TTCA
, tca
, jit::TCA
)
373 IMPLEMENT_CNS_VAL(TRDSHandle
, rdsHandle
, rds::Handle
)
375 #undef IMPLEMENT_CNS_VAL
377 ///////////////////////////////////////////////////////////////////////////////
378 // Specialized type creation.
380 inline Type
Type::Array(ArrayData::ArrayKind kind
) {
381 return Type(TArr
, ArraySpec(kind
));
384 inline Type
Type::Array(const RepoAuthType::Array
* rat
) {
385 return Type(TArr
, ArraySpec(rat
));
388 inline Type
Type::Array(const Shape
* shape
) {
389 return Type(TArr
, ArraySpec(shape
));
392 inline Type
Type::StaticArray(ArrayData::ArrayKind kind
) {
393 return Type(TStaticArr
, ArraySpec(kind
));
396 inline Type
Type::StaticArray(const RepoAuthType::Array
* rat
) {
397 return Type(TStaticArr
, ArraySpec(rat
));
400 inline Type
Type::StaticArray(const Shape
* shape
) {
401 return Type(TStaticArr
, ArraySpec(shape
));
404 inline Type
Type::SubObj(const Class
* cls
) {
405 if (cls
->attrs() & AttrNoOverride
) return ExactObj(cls
);
406 return Type(TObj
, ClassSpec(cls
, ClassSpec::SubTag
{}));
409 inline Type
Type::ExactObj(const Class
* cls
) {
410 return Type(TObj
, ClassSpec(cls
, ClassSpec::ExactTag
{}));
413 inline Type
Type::unspecialize() const {
414 return Type(m_bits
, ptrKind());
417 ///////////////////////////////////////////////////////////////////////////////
418 // Specialization introspection.
420 inline bool Type::isSpecialized() const {
421 return clsSpec() || arrSpec();
424 inline bool Type::supports(SpecKind kind
) const {
428 case SpecKind::Array
:
429 return m_bits
& kAnyArr
;
430 case SpecKind::Class
:
431 return m_bits
& kAnyObj
;
436 inline ArraySpec
Type::arrSpec() const {
437 if (!supports(SpecKind::Array
)) return ArraySpec::Bottom
;
439 // Currently, a Type which supports multiple specializations is trivial along
441 if (supports(SpecKind::Class
)) return ArraySpec::Top
;
444 return ArraySpec(arrVal()->kind());
446 assertx(m_arrSpec
!= ArraySpec::Bottom
);
450 inline ClassSpec
Type::clsSpec() const {
451 if (!supports(SpecKind::Class
)) return ClassSpec::Bottom
;
453 // Currently, a Type which supports multiple specializations is trivial along
455 if (supports(SpecKind::Array
)) return ClassSpec::Top
;
458 return ClassSpec(clsVal(), ClassSpec::ExactTag
{});
460 assertx(m_clsSpec
!= ClassSpec::Bottom
);
464 inline TypeSpec
Type::spec() const {
465 return TypeSpec(arrSpec(), clsSpec());
468 ///////////////////////////////////////////////////////////////////////////////
471 inline Type
Type::box() const {
472 assertx(*this <= TCell
);
473 // Boxing Uninit returns InitNull but that logic doesn't belong here.
474 assertx(!maybe(TUninit
) || *this == TCell
);
475 return Type(m_bits
<< kBoxShift
,
477 isSpecialized() && !m_hasConstVal
? m_extra
: 0);
480 inline Type
Type::inner() const {
481 assertx(*this <= TBoxedCell
);
482 return Type(m_bits
>> kBoxShift
, Ptr::Unk
, m_extra
);
485 inline Type
Type::unbox() const {
486 assertx(*this <= TGen
);
487 return (*this & TCell
) | (*this & TBoxedCell
).inner();
490 inline Type
Type::ptr(Ptr kind
) const {
491 assertx(*this <= TGen
);
492 // Enforce a canonical representation for Bottom.
493 if (m_bits
== kBottom
) return TBottom
;
494 return Type(m_bits
<< kPtrShift
,
496 isSpecialized() && !m_hasConstVal
? m_extra
: 0);
499 inline Type
Type::deref() const {
500 assertx(*this <= TPtrToGen
);
501 return Type(m_bits
>> kPtrShift
,
502 Ptr::Unk
/* no longer a pointer */,
503 isSpecialized() ? m_extra
: 0);
506 inline Type
Type::derefIfPtr() const {
507 assertx(*this <= (TGen
| TPtrToGen
));
508 return *this <= TPtrToGen
? deref() : *this;
511 inline Type
Type::strip() const {
512 return derefIfPtr().unbox();
515 inline Ptr
Type::ptrKind() const {
516 return static_cast<Ptr
>(m_ptrKind
);
519 ///////////////////////////////////////////////////////////////////////////////
520 // Private constructors.
522 inline Type::Type(bits_t bits
, Ptr kind
, uintptr_t extra
/* = 0 */)
524 , m_ptrKind(static_cast<std::underlying_type
<Ptr
>::type
>(kind
))
525 , m_hasConstVal(false)
528 assertx(checkValid());
531 inline Type::Type(Type t
, ArraySpec arraySpec
)
533 , m_ptrKind(t
.m_ptrKind
)
534 , m_hasConstVal(false)
535 , m_arrSpec(arraySpec
)
537 assertx(checkValid());
538 assertx(m_arrSpec
!= ArraySpec::Bottom
);
541 inline Type::Type(Type t
, ClassSpec classSpec
)
543 , m_ptrKind(t
.m_ptrKind
)
544 , m_hasConstVal(false)
545 , m_clsSpec(classSpec
)
547 assertx(checkValid());
548 assertx(m_clsSpec
!= ClassSpec::Bottom
);
551 ///////////////////////////////////////////////////////////////////////////////