Store num args instead of offset in prologue and func entry SrcKeys
[hiphop-php.git] / hphp / runtime / vm / jit / type-inl.h
blob9ce7716f479dfc76fc550eebe99ccffa8b9354ef
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
19 #endif
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"
28 #include <cstring>
30 namespace HPHP::jit {
31 ///////////////////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////////////////
34 // Predefined Types
36 constexpr inline Type::Type(bits_t bits, PtrLocation ptr)
37 : m_bits(bits)
38 , m_ptr(ptr)
39 , m_hasConstVal(false)
40 , m_extra(0)
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};
53 IRT_PHP
54 IRT_PHP_UNIONS
55 IRT_PTRS_LVALS
56 IRT_SPECIAL
57 #undef IRT
58 #undef IRTP
59 #undef IRTL
60 #undef IRTM
61 #undef IRTX
63 #define IRT(name, ...) \
64 constexpr Type T##name{Type::k##name, PtrLocation::Bottom};
65 IRT_RUNTIME
66 #undef IRT
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.
79 namespace TypeNames {
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)
85 IR_TYPES
86 #undef IRT
87 #undef IRTP
88 #undef IRTL
89 #undef IRTM
90 #undef IRTX
93 namespace type_detail {
94 ///////////////////////////////////////////////////////////////////////////////
97 * Widen a constant value if needed.
99 template<class T>
100 using needs_promotion = std::integral_constant<
101 bool,
102 (std::is_integral<T>::value ||
103 std::is_same<T,bool>::value ||
104 std::is_enum<T>::value)
107 template<class T>
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); }
111 template<class 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
119 * ints.
121 template<class T>
122 typename std::enable_if<
123 std::is_integral<T>::value || std::is_enum<T>::value,
124 Type
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());
130 return TStaticStr;
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;
137 not_reached();
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 ///////////////////////////////////////////////////////////////////////////////
150 // Type.
152 inline Type::Type()
153 : m_bits(kBottom)
154 , m_ptr(PtrLocation::Bottom)
155 , m_hasConstVal(false)
156 , m_extra(0)
159 inline Type::Type(DataType outer)
160 : m_bits(bitsFromDataType(outer))
161 , m_ptr(PtrLocation::Bottom)
162 , m_hasConstVal(false)
163 , m_extra(0)
166 inline size_t Type::hash() const {
167 return hash_int64_pair(
168 hash_int64_pair(
169 m_bits.hash(),
170 static_cast<uint64_t>(m_ptr) ^ m_hasConstVal
172 m_extra
176 ///////////////////////////////////////////////////////////////////////////////
177 // Comparison.
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 {
191 return rhs <= *this;
194 inline bool Type::operator<(Type rhs) const {
195 return *this != rhs && *this <= rhs;
198 inline bool Type::operator>(Type rhs) const {
199 return rhs < *this;
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 {
207 return false;
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 ///////////////////////////////////////////////////////////////////////////////
219 // Combinators.
221 inline Type Type::unionAll() {
222 return TBottom;
225 template<typename... Types>
226 inline Type Type::unionAll(Type t, Types... ts) {
227 return t | unionAll(ts...);
230 ///////////////////////////////////////////////////////////////////////////////
231 // Is-a methods.
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.
261 template<typename T>
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());
277 return ret;
280 template<typename T>
281 Type Type::cns(T val) {
282 return cns(val, type_detail::for_const(val));
285 inline Type Type::cns(std::nullptr_t) {
286 return TNullptr;
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> {
301 switch (tv.m_type) {
302 case KindOfUninit:
303 case KindOfNull:
304 not_reached();
306 case KindOfBoolean:
307 case KindOfInt64:
308 case KindOfDouble:
309 return Type(tv.m_type);
311 case KindOfPersistentString:
312 case KindOfString:
313 return type_detail::for_const(tv.m_data.pstr);
315 case KindOfPersistentVec:
316 case KindOfVec:
317 case KindOfPersistentDict:
318 case KindOfDict:
319 case KindOfPersistentKeyset:
320 case KindOfKeyset:
321 return type_detail::for_const(tv.m_data.parr);
322 case KindOfLazyClass:
323 return type_detail::for_const(tv.m_data.plazyclass);
324 // TODO (T29639296)
325 case KindOfFunc:
326 return type_detail::for_const(tv.m_data.pfunc);
327 case KindOfClass:
328 return type_detail::for_const(tv.m_data.pclass);
329 case KindOfClsMeth:
330 return type_detail::for_const(tv.m_data.pclsmeth);
332 case KindOfObject:
333 case KindOfResource:
334 case KindOfRFunc:
335 case KindOfRClsMeth:
336 return std::nullopt;
338 not_reached();
339 }();
340 if (ret) {
341 ret->m_hasConstVal = true;
342 ret->m_extra = tv.m_data.num;
344 return ret;
347 inline Type Type::dropConstVal() const {
348 if (!m_hasConstVal) return *this;
350 assertx(!isUnion());
351 auto const result = Type(m_bits, ptrLocation());
353 if (*this <= TArrLike) {
354 return Type(result, ArraySpec(ArrayLayout::FromArray(m_arrVal)));
356 return result;
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;
370 template<typename 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());
381 return m_extra;
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) {
477 switch (kind) {
478 case SpecKind::None:
479 return true;
480 case SpecKind::Array:
481 return (bits & kArrSpecBits) != kBottom;
482 case SpecKind::Class:
483 return (bits & kClsSpecBits) != kBottom;
485 not_reached();
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.)
501 if (m_hasConstVal) {
502 if (m_bits & kMem) return ArraySpec::Top();
503 return ArraySpec(ArrayLayout::FromArray(m_arrVal));
506 assertx(m_arrSpec != ArraySpec::Bottom());
507 return m_arrSpec;
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();
517 if (m_hasConstVal) {
518 if (m_bits & kMem) return ClassSpec::Top();
519 return ClassSpec(clsVal(), ClassSpec::ExactTag{});
522 assertx(m_clsSpec != ClassSpec::Bottom());
523 return m_clsSpec;
526 inline TypeSpec Type::spec() const {
527 return TypeSpec(arrSpec(), clsSpec());
530 ///////////////////////////////////////////////////////////////////////////////
531 // Inner types.
533 inline PtrLocation Type::ptrLocation() const {
534 return m_ptr;
537 inline Type Type::ptrToLval() const {
538 auto temp = *this;
539 if (temp.m_bits & kPtr) {
540 temp.m_bits &= ~kPtr;
541 temp.m_bits |= kLval;
543 return temp;
546 inline Type Type::lvalToPtr() const {
547 auto temp = *this;
548 if (temp.m_bits & kLval) {
549 temp.m_bits &= ~kLval;
550 temp.m_bits |= kPtr;
552 return temp;
555 ///////////////////////////////////////////////////////////////////////////////
556 // Private constructors.
558 inline Type::Type(bits_t bits, PtrLocation ptr, bool hasConstVal,
559 uintptr_t extra)
560 : m_bits(bits)
561 , m_ptr(ptr)
562 , m_hasConstVal(hasConstVal)
563 , m_extra(extra)
565 assertx(checkValid());
568 inline Type::Type(Type t, ArraySpec arraySpec)
569 : m_bits(t.m_bits)
570 , m_ptr(t.m_ptr)
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)
579 : m_bits(t.m_bits)
580 , m_ptr(t.m_ptr)
581 , m_hasConstVal(false)
582 , m_clsSpec(classSpec)
584 assertx(checkValid());
585 assertx(m_clsSpec != ClassSpec::Bottom());
588 ///////////////////////////////////////////////////////////////////////////////