PageRenderTime 28ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/vm/jit/type-inl.h

https://gitlab.com/alvinahmadov2/hhvm
C Header | 509 lines | 352 code | 96 blank | 61 comment | 44 complexity | 4253016aa72f104083f9f105dd7f5a45 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2015 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. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_JIT_TYPE_INL_H_
  17. #error "type-inl.h should only be included by type.h"
  18. #endif
  19. #include "hphp/runtime/base/string-data.h"
  20. #include "hphp/runtime/vm/class.h"
  21. #include "hphp/util/hash.h"
  22. #include <cstring>
  23. namespace HPHP { namespace jit {
  24. ///////////////////////////////////////////////////////////////////////////////
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // Predefined Types
  27. constexpr inline Type::Type(bits_t bits, Ptr kind)
  28. : m_bits(bits)
  29. , m_ptrKind(static_cast<ptr_t>(kind))
  30. , m_hasConstVal(false)
  31. , m_extra(0)
  32. {}
  33. #define IRT(name, ...) constexpr Type T##name{Type::k##name, Ptr::NotPtr};
  34. #define IRTP(name, ptr, bits) constexpr Type T##name{Type::bits, Ptr::ptr};
  35. IRT_PHP(IRT_BOXES_AND_PTRS)
  36. IRT_PHP_UNIONS(IRT_BOXES_AND_PTRS)
  37. IRT_SPECIAL
  38. #undef IRT
  39. #undef IRTP
  40. #define IRT(name, ...) constexpr Type T##name{Type::k##name, Ptr::Bottom};
  41. IRT_RUNTIME
  42. #undef IRT
  43. /*
  44. * Abbreviated namespace for predefined types.
  45. *
  46. * Used for macro codegen for types declared in ir.specification.
  47. */
  48. namespace TypeNames {
  49. #define IRT(name, ...) UNUSED constexpr Type name = T##name;
  50. #define IRTP(name, ...) IRT(name)
  51. IR_TYPES
  52. #undef IRT
  53. #undef IRTP
  54. };
  55. namespace type_detail {
  56. ///////////////////////////////////////////////////////////////////////////////
  57. /*
  58. * Widen a constant value if needed.
  59. */
  60. template<class T>
  61. using needs_promotion = std::integral_constant<
  62. bool,
  63. (std::is_integral<T>::value ||
  64. std::is_same<T,bool>::value ||
  65. std::is_enum<T>::value)
  66. >;
  67. template<class T>
  68. typename std::enable_if<needs_promotion<T>::value,uint64_t>::type
  69. promote_cns_if_needed(T t) { return static_cast<uint64_t>(t); }
  70. template<class T>
  71. typename std::enable_if<!needs_promotion<T>::value,T>::type
  72. promote_cns_if_needed(T t) { return t; }
  73. /*
  74. * Return the Type to use for a given C++ value.
  75. *
  76. * The only interesting case is int/bool disambiguation. Enums are treated as
  77. * ints.
  78. */
  79. template<class T>
  80. typename std::enable_if<
  81. std::is_integral<T>::value || std::is_enum<T>::value,
  82. Type
  83. >::type for_const(T) {
  84. return std::is_same<T,bool>::value ? TBool : TInt;
  85. }
  86. inline Type for_const(const StringData* sd) {
  87. assertx(sd->isStatic());
  88. return TStaticStr;
  89. }
  90. inline Type for_const(const ArrayData* ad) {
  91. assertx(ad->isStatic());
  92. return Type::StaticArray(ad->kind());
  93. }
  94. inline Type for_const(double) { return TDbl; }
  95. inline Type for_const(const Func*) { return TFunc; }
  96. inline Type for_const(const Class*) { return TCls; }
  97. inline Type for_const(ConstCctx) { return TCctx; }
  98. inline Type for_const(TCA) { return TTCA; }
  99. ///////////////////////////////////////////////////////////////////////////////
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. // Type.
  103. inline Type::Type()
  104. : m_bits(kBottom)
  105. , m_ptrKind(static_cast<ptr_t>(Ptr::Bottom))
  106. , m_hasConstVal(false)
  107. , m_extra(0)
  108. {}
  109. inline Type::Type(DataType outer, DataType inner)
  110. : m_bits(bitsFromDataType(outer, inner))
  111. , m_ptrKind(static_cast<ptr_t>(outer == KindOfClass ? Ptr::Bottom
  112. : Ptr::NotPtr))
  113. , m_hasConstVal(false)
  114. , m_extra(0)
  115. {}
  116. inline size_t Type::hash() const {
  117. return hash_int64_pair(m_raw, m_extra);
  118. }
  119. ///////////////////////////////////////////////////////////////////////////////
  120. // Comparison.
  121. inline bool Type::operator==(Type rhs) const {
  122. return m_raw == rhs.m_raw && m_extra == rhs.m_extra;
  123. }
  124. inline bool Type::operator!=(Type rhs) const {
  125. return !operator==(rhs);
  126. }
  127. inline bool Type::operator>=(Type rhs) const {
  128. return rhs <= *this;
  129. }
  130. inline bool Type::operator<(Type rhs) const {
  131. return *this != rhs && *this <= rhs;
  132. }
  133. inline bool Type::operator>(Type rhs) const {
  134. return rhs < *this;
  135. }
  136. template<typename... Types>
  137. bool Type::subtypeOfAny(Type t2, Types... ts) const {
  138. return *this <= t2 || subtypeOfAny(ts...);
  139. }
  140. inline bool Type::subtypeOfAny() const {
  141. return false;
  142. }
  143. inline bool Type::maybe(Type t2) const {
  144. return (*this & t2) != TBottom;
  145. }
  146. ///////////////////////////////////////////////////////////////////////////////
  147. // Is-a methods.
  148. inline bool Type::isUnion() const {
  149. // This will return true iff more than 1 bit is set in m_bits.
  150. return (m_bits & (m_bits - 1)) != 0;
  151. }
  152. inline bool Type::isKnownDataType() const {
  153. assertx(*this <= TStkElem);
  154. // Some unions correspond to single KindOfs.
  155. return subtypeOfAny(TStr, TArr, TBoxedCell) || !isUnion();
  156. }
  157. inline bool Type::needsReg() const {
  158. return *this <= TStkElem && !isKnownDataType();
  159. }
  160. inline bool Type::isSimpleType() const {
  161. return subtypeOfAny(TBool, TInt, TDbl, TNull);
  162. }
  163. inline bool Type::isReferenceType() const {
  164. return subtypeOfAny(TStr, TArr, TObj, TRes);
  165. }
  166. ///////////////////////////////////////////////////////////////////////////////
  167. // Constant type creation.
  168. template<typename T>
  169. Type Type::cns(T val, Type ret) {
  170. assertx(!ret.m_hasConstVal);
  171. ret.m_hasConstVal = true;
  172. static_assert(sizeof(T) <= sizeof(ret),
  173. "Constant data was larger than supported");
  174. static_assert(std::is_pod<T>::value,
  175. "Constant data wasn't a pod");
  176. const auto toCopy = type_detail::promote_cns_if_needed(val);
  177. static_assert(sizeof(toCopy) == 8,
  178. "Unexpected size for toCopy");
  179. std::memcpy(&ret.m_extra, &toCopy, sizeof(toCopy));
  180. return ret;
  181. }
  182. template<typename T>
  183. Type Type::cns(T val) {
  184. return cns(val, type_detail::for_const(val));
  185. }
  186. inline Type Type::cns(std::nullptr_t) {
  187. return TNullptr;
  188. }
  189. inline Type Type::cns(const TypedValue& tv) {
  190. if (tv.m_type == KindOfUninit) return TUninit;
  191. if (tv.m_type == KindOfNull) return TInitNull;
  192. auto ret = [&] {
  193. switch (tv.m_type) {
  194. case KindOfUninit:
  195. case KindOfNull:
  196. not_reached();
  197. case KindOfClass:
  198. case KindOfBoolean:
  199. case KindOfInt64:
  200. case KindOfDouble:
  201. return Type(tv.m_type);
  202. case KindOfStaticString:
  203. case KindOfString:
  204. return type_detail::for_const(tv.m_data.pstr);
  205. case KindOfPersistentArray:
  206. case KindOfArray:
  207. return type_detail::for_const(tv.m_data.parr);
  208. case KindOfObject:
  209. case KindOfResource:
  210. case KindOfRef:
  211. always_assert(false && "Invalid KindOf for constant TypedValue");
  212. }
  213. not_reached();
  214. }();
  215. ret.m_hasConstVal = true;
  216. ret.m_extra = tv.m_data.num;
  217. return ret;
  218. }
  219. inline Type Type::dropConstVal() const {
  220. if (!m_hasConstVal) return *this;
  221. assertx(!isUnion());
  222. if (*this <= TStaticArr) {
  223. return Type::StaticArray(arrVal()->kind());
  224. }
  225. return Type(m_bits, ptrKind());
  226. }
  227. ///////////////////////////////////////////////////////////////////////////////
  228. // Constant introspection.
  229. inline bool Type::hasConstVal() const {
  230. return m_hasConstVal;
  231. }
  232. inline bool Type::hasConstVal(Type t) const {
  233. return hasConstVal() && *this <= t;
  234. }
  235. template<typename T>
  236. bool Type::hasConstVal(T val) const {
  237. return hasConstVal(cns(val));
  238. }
  239. inline uint64_t Type::rawVal() const {
  240. assertx(hasConstVal());
  241. return m_extra;
  242. }
  243. #define IMPLEMENT_CNS_VAL(TypeName, name, valtype) \
  244. inline valtype Type::name##Val() const { \
  245. assertx(hasConstVal(TypeName)); \
  246. return m_##name##Val; \
  247. }
  248. IMPLEMENT_CNS_VAL(TBool, bool, bool)
  249. IMPLEMENT_CNS_VAL(TInt, int, int64_t)
  250. IMPLEMENT_CNS_VAL(TDbl, dbl, double)
  251. IMPLEMENT_CNS_VAL(TStaticStr, str, const StringData*)
  252. IMPLEMENT_CNS_VAL(TStaticArr, arr, const ArrayData*)
  253. IMPLEMENT_CNS_VAL(TFunc, func, const HPHP::Func*)
  254. IMPLEMENT_CNS_VAL(TCls, cls, const Class*)
  255. IMPLEMENT_CNS_VAL(TCctx, cctx, ConstCctx)
  256. IMPLEMENT_CNS_VAL(TTCA, tca, jit::TCA)
  257. IMPLEMENT_CNS_VAL(TRDSHandle, rdsHandle, rds::Handle)
  258. #undef IMPLEMENT_CNS_VAL
  259. ///////////////////////////////////////////////////////////////////////////////
  260. // Specialized type creation.
  261. inline Type Type::Array(ArrayData::ArrayKind kind) {
  262. return Type(TArr, ArraySpec(kind));
  263. }
  264. inline Type Type::Array(const RepoAuthType::Array* rat) {
  265. return Type(TArr, ArraySpec(rat));
  266. }
  267. inline Type Type::Array(const Shape* shape) {
  268. return Type(TArr, ArraySpec(shape));
  269. }
  270. inline Type Type::StaticArray(ArrayData::ArrayKind kind) {
  271. return Type(TStaticArr, ArraySpec(kind));
  272. }
  273. inline Type Type::StaticArray(const RepoAuthType::Array* rat) {
  274. return Type(TStaticArr, ArraySpec(rat));
  275. }
  276. inline Type Type::StaticArray(const Shape* shape) {
  277. return Type(TStaticArr, ArraySpec(shape));
  278. }
  279. inline Type Type::SubObj(const Class* cls) {
  280. if (cls->attrs() & AttrNoOverride) return ExactObj(cls);
  281. return Type(TObj, ClassSpec(cls, ClassSpec::SubTag{}));
  282. }
  283. inline Type Type::ExactObj(const Class* cls) {
  284. return Type(TObj, ClassSpec(cls, ClassSpec::ExactTag{}));
  285. }
  286. inline Type Type::SubCls(const Class* cls) {
  287. if (cls->attrs() & AttrNoOverride) return ExactCls(cls);
  288. return Type(TCls, ClassSpec(cls, ClassSpec::SubTag{}));
  289. }
  290. inline Type Type::ExactCls(const Class* cls) {
  291. return Type::cns(cls);
  292. }
  293. inline Type Type::unspecialize() const {
  294. return Type(m_bits, ptrKind());
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////
  297. // Specialization introspection.
  298. inline bool Type::isSpecialized() const {
  299. return clsSpec() || arrSpec();
  300. }
  301. inline bool Type::supports(bits_t bits, SpecKind kind) {
  302. switch (kind) {
  303. case SpecKind::None:
  304. return true;
  305. case SpecKind::Array:
  306. return bits & kArrSpecBits;
  307. case SpecKind::Class:
  308. return bits & kClsSpecBits;
  309. }
  310. not_reached();
  311. }
  312. inline bool Type::supports(SpecKind kind) const {
  313. return supports(m_bits, kind);
  314. }
  315. inline ArraySpec Type::arrSpec() const {
  316. if (!supports(SpecKind::Array)) return ArraySpec::Bottom;
  317. // Currently, a Type which supports multiple specializations is trivial along
  318. // all of them.
  319. if (supports(SpecKind::Class)) return ArraySpec::Top;
  320. if (m_hasConstVal) {
  321. return ArraySpec(arrVal()->kind());
  322. }
  323. assertx(m_arrSpec != ArraySpec::Bottom);
  324. return m_arrSpec;
  325. }
  326. inline ClassSpec Type::clsSpec() const {
  327. if (!supports(SpecKind::Class)) return ClassSpec::Bottom;
  328. // Currently, a Type which supports multiple specializations is trivial along
  329. // all of them.
  330. if (supports(SpecKind::Array)) return ClassSpec::Top;
  331. if (m_hasConstVal) {
  332. return ClassSpec(clsVal(), ClassSpec::ExactTag{});
  333. }
  334. assertx(m_clsSpec != ClassSpec::Bottom);
  335. return m_clsSpec;
  336. }
  337. inline TypeSpec Type::spec() const {
  338. return TypeSpec(arrSpec(), clsSpec());
  339. }
  340. ///////////////////////////////////////////////////////////////////////////////
  341. // Inner types.
  342. inline Type Type::box() const {
  343. assertx(*this <= TCell);
  344. // Boxing Uninit returns InitNull but that logic doesn't belong here.
  345. assertx(!maybe(TUninit) || *this == TCell);
  346. return Type(m_bits << kBoxShift,
  347. ptrKind(),
  348. isSpecialized() && !m_hasConstVal ? m_extra : 0);
  349. }
  350. inline Type Type::inner() const {
  351. assertx(*this <= TBoxedCell);
  352. return Type(m_bits >> kBoxShift, ptrKind(), m_extra);
  353. }
  354. inline Type Type::unbox() const {
  355. assertx(*this <= TGen);
  356. return (*this & TCell) | (*this & TBoxedCell).inner();
  357. }
  358. inline Type Type::ptr(Ptr kind) const {
  359. assertx(*this <= TGen);
  360. assertx(kind <= Ptr::Ptr);
  361. // Enforce a canonical representation for Bottom.
  362. if (m_bits == kBottom) return TBottom;
  363. return Type(m_bits,
  364. kind,
  365. isSpecialized() && !m_hasConstVal ? m_extra : 0);
  366. }
  367. inline Type Type::deref() const {
  368. assertx(*this <= TPtrToGen);
  369. if (m_bits == kBottom) return TBottom;
  370. return Type(m_bits,
  371. Ptr::NotPtr,
  372. isSpecialized() ? m_extra : 0);
  373. }
  374. inline Type Type::derefIfPtr() const {
  375. assertx(*this <= (TGen | TPtrToGen));
  376. return *this <= TPtrToGen ? deref() : *this;
  377. }
  378. inline Type Type::strip() const {
  379. return derefIfPtr().unbox();
  380. }
  381. inline Ptr Type::ptrKind() const {
  382. return static_cast<Ptr>(m_ptrKind);
  383. }
  384. ///////////////////////////////////////////////////////////////////////////////
  385. // Private constructors.
  386. inline Type::Type(bits_t bits, Ptr kind, uintptr_t extra)
  387. : m_bits(bits)
  388. , m_ptrKind(static_cast<ptr_t>(kind))
  389. , m_hasConstVal(false)
  390. , m_extra(extra)
  391. {
  392. assertx(checkValid());
  393. }
  394. inline Type::Type(Type t, ArraySpec arraySpec)
  395. : m_bits(t.m_bits)
  396. , m_ptrKind(t.m_ptrKind)
  397. , m_hasConstVal(false)
  398. , m_arrSpec(arraySpec)
  399. {
  400. assertx(checkValid());
  401. assertx(m_arrSpec != ArraySpec::Bottom);
  402. }
  403. inline Type::Type(Type t, ClassSpec classSpec)
  404. : m_bits(t.m_bits)
  405. , m_ptrKind(t.m_ptrKind)
  406. , m_hasConstVal(false)
  407. , m_clsSpec(classSpec)
  408. {
  409. assertx(checkValid());
  410. assertx(m_clsSpec != ClassSpec::Bottom);
  411. }
  412. ///////////////////////////////////////////////////////////////////////////////
  413. }}