Switch-related cleanup
[hiphop-php.git] / hphp / runtime / vm / jit / type-inl.h
blob517a2cf8a7d66bbcaed234d7a9d831371809f6f8
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_INL_H_
18 #error "type-inl.h should only be included by type.h"
19 #endif
21 #include "hphp/runtime/base/string-data.h"
22 #include "hphp/runtime/vm/class.h"
24 #include "hphp/util/hash.h"
26 #include <cstring>
28 namespace HPHP { namespace jit {
29 ///////////////////////////////////////////////////////////////////////////////
31 ///////////////////////////////////////////////////////////////////////////////
32 // Predefined Types
34 constexpr inline Type::Type(bits_t bits, Ptr kind)
35 : m_bits(bits)
36 , m_ptrKind(static_cast<std::underlying_type<Ptr>::type>(kind))
37 , m_hasConstVal(false)
38 , m_extra(0)
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};
43 IR_TYPES
44 #undef IRT
45 #undef IRTP
48 * Abbreviated namespace for predefined types.
50 * Used for macro codegen for types declared in ir.specification.
52 namespace TypeNames {
53 #define IRT(name, ...) UNUSED constexpr Type name = T##name;
54 #define IRTP(name, ...) IRT(name)
55 IR_TYPES
56 #undef IRT
57 #undef IRTP
60 namespace type_detail {
61 ///////////////////////////////////////////////////////////////////////////////
64 * Widen a constant value if needed.
66 template<class T>
67 using needs_promotion = std::integral_constant<
68 bool,
69 (std::is_integral<T>::value ||
70 std::is_same<T,bool>::value ||
71 std::is_enum<T>::value)
74 template<class T>
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); }
78 template<class 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
86 * ints.
88 template<class T>
89 typename std::enable_if<
90 std::is_integral<T>::value || std::is_enum<T>::value,
91 Type
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());
97 return TStaticStr;
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 ///////////////////////////////////////////////////////////////////////////////
113 // Ptr.
115 inline Ptr add_ref(Ptr p) {
116 if (p == Ptr::Unk || p == Ptr::ClsInit || p == Ptr::ClsCns) {
117 return p;
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 ///////////////////////////////////////////////////////////////////////////////
134 // Type.
136 inline Type::Type()
137 : m_bits(kBottom)
138 , m_ptrKind(0)
139 , m_hasConstVal(false)
140 , m_extra(0)
143 inline Type::Type(DataType outer, DataType inner)
144 : m_bits(bitsFromDataType(outer, inner))
145 , m_ptrKind(0)
146 , m_hasConstVal(false)
147 , m_extra(0)
150 inline Type::Type(DataType outer, KindOfAny)
151 : m_bits(outer == KindOfRef ? kBoxedCell
152 : bitsFromDataType(outer, KindOfUninit))
153 , m_ptrKind(0)
154 , m_hasConstVal(false)
155 , m_extra(0)
158 inline Type& Type::operator=(Type b) {
159 m_bits = b.m_bits;
160 m_hasConstVal = b.m_hasConstVal;
161 m_ptrKind = b.m_ptrKind;
162 m_extra = b.m_extra;
163 return *this;
166 inline size_t Type::hash() const {
167 return hash_int64_pair(m_rawInt, m_extra);
170 ///////////////////////////////////////////////////////////////////////////////
171 // Comparison.
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 {
182 auto lhs = *this;
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) {
186 return false;
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())) {
204 return false;
207 // Compare specializations only if `rhs' is specialized.
208 return !rhs.isSpecialized() || lhs.spec() <= rhs.spec();
211 inline bool Type::operator>=(Type rhs) const {
212 return rhs <= *this;
215 inline bool Type::operator<(Type rhs) const {
216 return *this != rhs && *this <= rhs;
219 inline bool Type::operator>(Type rhs) const {
220 return rhs < *this;
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 {
228 return false;
231 inline bool Type::maybe(Type t2) const {
232 return (*this & t2) != TBottom;
235 ///////////////////////////////////////////////////////////////////////////////
236 // Is-a methods.
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.
265 template<typename T>
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));
280 return ret;
283 template<typename T>
284 Type Type::cns(T val) {
285 return cns(val, type_detail::for_const(val));
288 inline Type Type::cns(std::nullptr_t) {
289 return TNullptr;
292 inline Type Type::cns(const TypedValue& tv) {
293 if (tv.m_type == KindOfUninit) return TUninit;
294 if (tv.m_type == KindOfNull) return TInitNull;
296 auto ret = [&] {
297 switch (tv.m_type) {
298 case KindOfUninit:
299 case KindOfNull:
300 not_reached();
302 case KindOfClass:
303 case KindOfBoolean:
304 case KindOfInt64:
305 case KindOfDouble:
306 case KindOfStaticString:
307 return Type(tv.m_type);
309 case KindOfString:
310 return type_detail::for_const(tv.m_data.pstr);
312 case KindOfArray:
313 return type_detail::for_const(tv.m_data.parr);
315 case KindOfObject:
316 case KindOfResource:
317 case KindOfRef:
318 always_assert(false && "Invalid KindOf for constant TypedValue");
320 not_reached();
321 }();
322 ret.m_hasConstVal = true;
323 ret.m_extra = tv.m_data.num;
324 return ret;
327 inline Type Type::dropConstVal() const {
328 if (!m_hasConstVal) return *this;
329 assertx(!isUnion());
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;
348 template<typename T>
349 bool Type::hasConstVal(T val) const {
350 return hasConstVal(cns(val));
353 inline uint64_t Type::rawVal() const {
354 assertx(hasConstVal());
355 return m_extra;
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 {
425 switch (kind) {
426 case SpecKind::None:
427 return true;
428 case SpecKind::Array:
429 return m_bits & kAnyArr;
430 case SpecKind::Class:
431 return m_bits & kAnyObj;
433 not_reached();
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
440 // all of them.
441 if (supports(SpecKind::Class)) return ArraySpec::Top;
443 if (m_hasConstVal) {
444 return ArraySpec(arrVal()->kind());
446 assertx(m_arrSpec != ArraySpec::Bottom);
447 return m_arrSpec;
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
454 // all of them.
455 if (supports(SpecKind::Array)) return ClassSpec::Top;
457 if (m_hasConstVal) {
458 return ClassSpec(clsVal(), ClassSpec::ExactTag{});
460 assertx(m_clsSpec != ClassSpec::Bottom);
461 return m_clsSpec;
464 inline TypeSpec Type::spec() const {
465 return TypeSpec(arrSpec(), clsSpec());
468 ///////////////////////////////////////////////////////////////////////////////
469 // Inner types.
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,
476 ptrKind(),
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,
495 kind,
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 */)
523 : m_bits(bits)
524 , m_ptrKind(static_cast<std::underlying_type<Ptr>::type>(kind))
525 , m_hasConstVal(false)
526 , m_extra(extra)
528 assertx(checkValid());
531 inline Type::Type(Type t, ArraySpec arraySpec)
532 : m_bits(t.m_bits)
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)
542 : m_bits(t.m_bits)
543 , m_ptrKind(t.m_ptrKind)
544 , m_hasConstVal(false)
545 , m_clsSpec(classSpec)
547 assertx(checkValid());
548 assertx(m_clsSpec != ClassSpec::Bottom);
551 ///////////////////////////////////////////////////////////////////////////////