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// (selected on ARM64 regardless of _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION) 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 164struct __type_info_implementations { 165 struct __string_impl_base { 166 typedef const char* __type_name_t; 167 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 168 _LIBCPP_CONSTEXPR static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { 169 return __v; 170 } 171 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 172 _LIBCPP_CONSTEXPR static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { 173 return __v; 174 } 175 }; 176 177 struct __unique_impl : __string_impl_base { 178 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 179 static size_t __hash(__type_name_t __v) _NOEXCEPT { 180 return reinterpret_cast<size_t>(__v); 181 } 182 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 183 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 184 return __lhs == __rhs; 185 } 186 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 187 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 188 return __lhs < __rhs; 189 } 190 }; 191 192 struct __non_unique_impl : __string_impl_base { 193 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 194 static size_t __hash(__type_name_t __ptr) _NOEXCEPT { 195 size_t __hash = 5381; 196 while (unsigned char __c = static_cast<unsigned char>(*__ptr++)) 197 __hash = (__hash * 33) ^ __c; 198 return __hash; 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 || __builtin_strcmp(__lhs, __rhs) == 0; 203 } 204 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 205 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 206 return __builtin_strcmp(__lhs, __rhs) < 0; 207 } 208 }; 209 210 struct __non_unique_arm_rtti_bit_impl { 211 typedef uintptr_t __type_name_t; 212 213 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 214 static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { 215 return reinterpret_cast<const char*>(__v & 216 ~__non_unique_rtti_bit::value); 217 } 218 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 219 static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { 220 return reinterpret_cast<__type_name_t>(__v); 221 } 222 223 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 224 static size_t __hash(__type_name_t __v) _NOEXCEPT { 225 if (__is_type_name_unique(__v)) 226 return reinterpret_cast<size_t>(__v); 227 return __non_unique_impl::__hash(__type_name_to_string(__v)); 228 } 229 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 230 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 231 if (__lhs == __rhs) 232 return true; 233 if (__is_type_name_unique(__lhs, __rhs)) 234 return false; 235 return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; 236 } 237 _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE 238 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 239 if (__is_type_name_unique(__lhs, __rhs)) 240 return __lhs < __rhs; 241 return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; 242 } 243 244 private: 245 // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when 246 // this implementation is actually used. 247 typedef std::integral_constant<__type_name_t, 248 (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> __non_unique_rtti_bit; 249 250 _LIBCPP_INLINE_VISIBILITY 251 static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { 252 return !(__lhs & __non_unique_rtti_bit::value); 253 } 254 _LIBCPP_INLINE_VISIBILITY 255 static bool __is_type_name_unique(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 256 return !((__lhs & __rhs) & __non_unique_rtti_bit::value); 257 } 258 }; 259 260 typedef 261#if defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__) 262 __non_unique_arm_rtti_bit_impl 263#elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 1 264 __unique_impl 265#elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 2 266 __non_unique_impl 267#else 268# error invalid configuration for _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 269#endif 270 __impl; 271}; 272 273class _LIBCPP_EXCEPTION_ABI type_info 274{ 275 type_info& operator=(const type_info&); 276 type_info(const type_info&); 277 278 protected: 279 typedef __type_info_implementations::__impl __impl; 280 281 __impl::__type_name_t __type_name; 282 283 _LIBCPP_INLINE_VISIBILITY 284 explicit type_info(const char* __n) 285 : __type_name(__impl::__string_to_type_name(__n)) {} 286 287public: 288 _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE 289 virtual ~type_info(); 290 291 _LIBCPP_INLINE_VISIBILITY 292 const char* name() const _NOEXCEPT 293 { 294 return __impl::__type_name_to_string(__type_name); 295 } 296 297 _LIBCPP_INLINE_VISIBILITY 298 bool before(const type_info& __arg) const _NOEXCEPT 299 { 300 return __impl::__lt(__type_name, __arg.__type_name); 301 } 302 303 _LIBCPP_INLINE_VISIBILITY 304 size_t hash_code() const _NOEXCEPT 305 { 306 return __impl::__hash(__type_name); 307 } 308 309 _LIBCPP_INLINE_VISIBILITY 310 bool operator==(const type_info& __arg) const _NOEXCEPT 311 { 312 return __impl::__eq(__type_name, __arg.__type_name); 313 } 314 315 _LIBCPP_INLINE_VISIBILITY 316 bool operator!=(const type_info& __arg) const _NOEXCEPT 317 { return !operator==(__arg); } 318}; 319#endif // defined(_LIBCPP_ABI_MICROSOFT) 320 321class _LIBCPP_EXCEPTION_ABI bad_cast 322 : public exception 323{ 324 public: 325 bad_cast() _NOEXCEPT; 326 bad_cast(const bad_cast&) _NOEXCEPT = default; 327 virtual ~bad_cast() _NOEXCEPT; 328 virtual const char* what() const _NOEXCEPT; 329}; 330 331class _LIBCPP_EXCEPTION_ABI bad_typeid 332 : public exception 333{ 334 public: 335 bad_typeid() _NOEXCEPT; 336 virtual ~bad_typeid() _NOEXCEPT; 337 virtual const char* what() const _NOEXCEPT; 338}; 339 340} // std 341 342#endif // defined(_LIBCPP_ABI_VCRUNTIME) 343 344_LIBCPP_BEGIN_NAMESPACE_STD 345_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY 346void __throw_bad_cast() 347{ 348#ifndef _LIBCPP_NO_EXCEPTIONS 349 throw bad_cast(); 350#else 351 _VSTD::abort(); 352#endif 353} 354_LIBCPP_END_NAMESPACE_STD 355 356#endif // __LIBCPP_TYPEINFO 357