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