1// -*- C++ -*- 2//===-------------------------- typeinfo ----------------------------------===// 3// 4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5// See https://llvm.org/LICENSE.txt for license information. 6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef __LIBCPP_TYPEINFO 11#define __LIBCPP_TYPEINFO 12 13/* 14 15 typeinfo synopsis 16 17namespace std { 18 19class type_info 20{ 21public: 22 virtual ~type_info(); 23 24 bool operator==(const type_info& rhs) const noexcept; 25 bool operator!=(const type_info& rhs) const noexcept; 26 27 bool before(const type_info& rhs) const noexcept; 28 size_t hash_code() const noexcept; 29 const char* name() const noexcept; 30 31 type_info(const type_info& rhs) = delete; 32 type_info& operator=(const type_info& rhs) = delete; 33}; 34 35class bad_cast 36 : public exception 37{ 38public: 39 bad_cast() noexcept; 40 bad_cast(const bad_cast&) noexcept; 41 bad_cast& operator=(const bad_cast&) noexcept; 42 virtual const char* what() const noexcept; 43}; 44 45class bad_typeid 46 : public exception 47{ 48public: 49 bad_typeid() noexcept; 50 bad_typeid(const bad_typeid&) noexcept; 51 bad_typeid& operator=(const bad_typeid&) noexcept; 52 virtual const char* what() const noexcept; 53}; 54 55} // std 56 57*/ 58 59#include <__config> 60#include <exception> 61#include <cstddef> 62#include <cstdint> 63#include <type_traits> 64#ifdef _LIBCPP_NO_EXCEPTIONS 65#include <cstdlib> 66#endif 67 68#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 69#pragma GCC system_header 70#endif 71 72#if defined(_LIBCPP_ABI_VCRUNTIME) 73#include <vcruntime_typeinfo.h> 74#else 75 76namespace std // purposefully not using versioning namespace 77{ 78 79 80#if defined(_LIBCPP_ABI_MICROSOFT) 81 82class _LIBCPP_EXCEPTION_ABI type_info 83{ 84 type_info& operator=(const type_info&); 85 type_info(const type_info&); 86 87 mutable struct { 88 const char *__undecorated_name; 89 const char __decorated_name[1]; 90 } __data; 91 92 int __compare(const type_info &__rhs) const _NOEXCEPT; 93 94public: 95 _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE 96 virtual ~type_info(); 97 98 const char *name() const _NOEXCEPT; 99 100 _LIBCPP_INLINE_VISIBILITY 101 bool before(const type_info& __arg) const _NOEXCEPT { 102 return __compare(__arg) < 0; 103 } 104 105 size_t hash_code() const _NOEXCEPT; 106 107 _LIBCPP_INLINE_VISIBILITY 108 bool operator==(const type_info& __arg) const _NOEXCEPT { 109 return __compare(__arg) == 0; 110 } 111 112 _LIBCPP_INLINE_VISIBILITY 113 bool operator!=(const type_info& __arg) const _NOEXCEPT 114 { return !operator==(__arg); } 115}; 116 117#else // !defined(_LIBCPP_ABI_MICROSOFT) 118 119// ========================================================================== // 120// Implementations 121// ========================================================================== // 122// ------------------------------------------------------------------------- // 123// Unique 124// ------------------------------------------------------------------------- // 125// This implementation of type_info assumes a unique copy of the RTTI for a 126// given type inside a program. This is a valid assumption when abiding to 127// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components). 128// Under this assumption, we can always compare the addresses of the type names 129// to implement equality-comparison of type_infos instead of having to perform 130// a deep string comparison. 131// -------------------------------------------------------------------------- // 132// NonUnique 133// -------------------------------------------------------------------------- // 134// This implementation of type_info does not assume there is always a unique 135// copy of the RTTI for a given type inside a program. For various reasons 136// the linker may have failed to merge every copy of a types RTTI 137// (For example: -Bsymbolic or llvm.org/PR37398). Under this assumption, two 138// type_infos are equal if their addresses are equal or if a deep string 139// comparison is equal. 140// -------------------------------------------------------------------------- // 141// NonUniqueARMRTTIBit 142// -------------------------------------------------------------------------- // 143// This implementation of type_info does not assume always a unique copy of 144// the RTTI for a given type inside a program. It packs the pointer to the 145// type name into a uintptr_t and reserves the high bit of that pointer (which 146// is assumed to be free for use under the ABI in use) to represent whether 147// that specific copy of the RTTI can be assumed unique inside the program. 148// To implement equality-comparison of type_infos, we check whether BOTH 149// type_infos are guaranteed unique, and if so, we simply compare the addresses 150// of their type names instead of doing a deep string comparison, which is 151// faster. If at least one of the type_infos can't guarantee uniqueness, we 152// have no choice but to fall back to a deep string comparison. 153// 154// This implementation is specific to ARM64 on Apple platforms. 155// 156// Note that the compiler is the one setting (or unsetting) the high bit of 157// the pointer when it constructs the type_info, depending on whether it can 158// guarantee uniqueness for that specific type_info. 159 160struct __type_info_implementations { 161 struct __string_impl_base { 162 typedef const char* __type_name_t; 163 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 164 _LIBCPP_CONSTEXPR static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { 165 return __v; 166 } 167 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 168 _LIBCPP_CONSTEXPR static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { 169 return __v; 170 } 171 }; 172 173 struct __unique_impl : __string_impl_base { 174 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 175 static size_t __hash(__type_name_t __v) _NOEXCEPT { 176 return reinterpret_cast<size_t>(__v); 177 } 178 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 179 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 180 return __lhs == __rhs; 181 } 182 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 183 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 184 return __lhs < __rhs; 185 } 186 }; 187 188 struct __non_unique_impl : __string_impl_base { 189 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 190 static size_t __hash(__type_name_t __ptr) _NOEXCEPT { 191 size_t __hash = 5381; 192 while (unsigned char __c = static_cast<unsigned char>(*__ptr++)) 193 __hash = (__hash * 33) ^ __c; 194 return __hash; 195 } 196 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 197 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 198 return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; 199 } 200 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 201 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 202 return __builtin_strcmp(__lhs, __rhs) < 0; 203 } 204 }; 205 206 struct __non_unique_arm_rtti_bit_impl { 207 typedef uintptr_t __type_name_t; 208 209 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 210 static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { 211 return reinterpret_cast<const char*>(__v & 212 ~__non_unique_rtti_bit::value); 213 } 214 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 215 static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { 216 return reinterpret_cast<__type_name_t>(__v); 217 } 218 219 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 220 static size_t __hash(__type_name_t __v) _NOEXCEPT { 221 if (__is_type_name_unique(__v)) 222 return reinterpret_cast<size_t>(__v); 223 return __non_unique_impl::__hash(__type_name_to_string(__v)); 224 } 225 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 226 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 227 if (__lhs == __rhs) 228 return true; 229 if (__is_type_name_unique(__lhs, __rhs)) 230 return false; 231 return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; 232 } 233 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 234 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 235 if (__is_type_name_unique(__lhs, __rhs)) 236 return __lhs < __rhs; 237 return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; 238 } 239 240 private: 241 // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when 242 // this implementation is actually used. 243 typedef std::integral_constant<__type_name_t, 244 (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> __non_unique_rtti_bit; 245 246 _LIBCPP_INLINE_VISIBILITY 247 static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { 248 return !(__lhs & __non_unique_rtti_bit::value); 249 } 250 _LIBCPP_INLINE_VISIBILITY 251 static bool __is_type_name_unique(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 252 return !((__lhs & __rhs) & __non_unique_rtti_bit::value); 253 } 254 }; 255 256 typedef 257#if defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__) 258 __non_unique_arm_rtti_bit_impl 259#elif _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT == 0 260 __non_unique_impl 261#elif _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT == 1 262 __unique_impl 263#else 264# error invalid configuration for _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT 265#endif 266 __impl; 267}; 268 269class _LIBCPP_EXCEPTION_ABI type_info 270{ 271 type_info& operator=(const type_info&); 272 type_info(const type_info&); 273 274 protected: 275 typedef __type_info_implementations::__impl __impl; 276 277 __impl::__type_name_t __type_name; 278 279 _LIBCPP_INLINE_VISIBILITY 280 explicit type_info(const char* __n) 281 : __type_name(__impl::__string_to_type_name(__n)) {} 282 283public: 284 _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE 285 virtual ~type_info(); 286 287 _LIBCPP_INLINE_VISIBILITY 288 const char* name() const _NOEXCEPT 289 { 290 return __impl::__type_name_to_string(__type_name); 291 } 292 293 _LIBCPP_INLINE_VISIBILITY 294 bool before(const type_info& __arg) const _NOEXCEPT 295 { 296 return __impl::__lt(__type_name, __arg.__type_name); 297 } 298 299 _LIBCPP_INLINE_VISIBILITY 300 size_t hash_code() const _NOEXCEPT 301 { 302 return __impl::__hash(__type_name); 303 } 304 305 _LIBCPP_INLINE_VISIBILITY 306 bool operator==(const type_info& __arg) const _NOEXCEPT 307 { 308 return __impl::__eq(__type_name, __arg.__type_name); 309 } 310 311 _LIBCPP_INLINE_VISIBILITY 312 bool operator!=(const type_info& __arg) const _NOEXCEPT 313 { return !operator==(__arg); } 314}; 315#endif // defined(_LIBCPP_ABI_MICROSOFT) 316 317class _LIBCPP_EXCEPTION_ABI bad_cast 318 : public exception 319{ 320 public: 321 bad_cast() _NOEXCEPT; 322 virtual ~bad_cast() _NOEXCEPT; 323 virtual const char* what() const _NOEXCEPT; 324}; 325 326class _LIBCPP_EXCEPTION_ABI bad_typeid 327 : public exception 328{ 329 public: 330 bad_typeid() _NOEXCEPT; 331 virtual ~bad_typeid() _NOEXCEPT; 332 virtual const char* what() const _NOEXCEPT; 333}; 334 335} // std 336 337#endif // defined(_LIBCPP_ABI_VCRUNTIME) 338 339_LIBCPP_BEGIN_NAMESPACE_STD 340_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY 341void __throw_bad_cast() 342{ 343#ifndef _LIBCPP_NO_EXCEPTIONS 344 throw bad_cast(); 345#else 346 _VSTD::abort(); 347#endif 348} 349_LIBCPP_END_NAMESPACE_STD 350 351#endif // __LIBCPP_TYPEINFO 352