Skip to content

Commit

Permalink
[libc++] Disentangle the 3 implementations of type_info
Browse files Browse the repository at this point in the history
Summary:
We currently have effectively 3 implementations of type_info: one for
the Microsoft ABI, one that does not assume that there's a unique copy
of each RTTI in a progran, and one that assumes a unique copy.

Those 3 implementations are entangled into the same class with nested
ifdefs, which makes it very difficult to understand. Furthermore, the
benefit of doing this is rather small since the code that is duplicated
across implementations is just a couple of trivial lines.

This patch stamps out the 3 versions of type_info explicitly to increase
readability. It also explains what's going on with short comments, because
it's far from obvious.

Reviewers: EricWF, mclow.lists

Subscribers: christof, jkorous, dexonsmith

Differential Revision: https://reviews.llvm.org/D57606

llvm-svn: 352905
  • Loading branch information
ldionne committed Feb 1, 2019
1 parent 8b323f5 commit 6b653fc
Showing 1 changed file with 75 additions and 31 deletions.
106 changes: 75 additions & 31 deletions libcxx/include/typeinfo
Expand Up @@ -79,48 +79,24 @@ public:
namespace std // purposefully not using versioning namespace
{

#if defined(_LIBCPP_ABI_MICROSOFT)

class _LIBCPP_EXCEPTION_ABI type_info
{
type_info& operator=(const type_info&);
type_info(const type_info&);

#if defined(_LIBCPP_HAS_NONUNIQUE_TYPEINFO)
_LIBCPP_INLINE_VISIBILITY
int __compare_nonunique_names(const type_info &__arg) const _NOEXCEPT
{ return __builtin_strcmp(name(), __arg.name()); }
#endif

#if defined(_LIBCPP_ABI_MICROSOFT)
mutable struct {
const char *__undecorated_name;
const char __decorated_name[1];
} __data;

int __compare(const type_info &__rhs) const _NOEXCEPT;
#endif // _LIBCPP_ABI_MICROSOFT

protected:
#if !defined(_LIBCPP_ABI_MICROSOFT)
#if defined(_LIBCPP_HAS_NONUNIQUE_TYPEINFO)
// A const char* with the non-unique RTTI bit possibly set.
uintptr_t __type_name;

_LIBCPP_INLINE_VISIBILITY
explicit type_info(const char* __n)
: __type_name(reinterpret_cast<uintptr_t>(__n)) {}
#else
const char *__type_name;

_LIBCPP_INLINE_VISIBILITY
explicit type_info(const char* __n) : __type_name(__n) {}
#endif
#endif // ! _LIBCPP_ABI_MICROSOFT

public:
_LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
virtual ~type_info();

#if defined(_LIBCPP_ABI_MICROSOFT)
const char *name() const _NOEXCEPT;

_LIBCPP_INLINE_VISIBILITY
Expand All @@ -134,8 +110,48 @@ public:
bool operator==(const type_info& __arg) const _NOEXCEPT {
return __compare(__arg) == 0;
}
#else
#if defined(_LIBCPP_HAS_NONUNIQUE_TYPEINFO)

_LIBCPP_INLINE_VISIBILITY
bool operator!=(const type_info& __arg) const _NOEXCEPT
{ return !operator==(__arg); }
};

#elif defined(_LIBCPP_HAS_NONUNIQUE_TYPEINFO)

// This implementation of type_info does not assume always a unique copy of
// the RTTI for a given type inside a program. It packs the pointer to the
// type name into a uintptr_t and reserves the high bit of that pointer (which
// is assumed to be free for use under the ABI in use) to represent whether
// that specific copy of the RTTI can be assumed unique inside the program.
// To implement equality-comparison of type_infos, we check whether BOTH
// type_infos are guaranteed unique, and if so, we simply compare the addresses
// of their type names instead of doing a deep string comparison, which is
// faster. If at least one of the type_infos can't guarantee uniqueness, we
// have no choice but to fall back to a deep string comparison.
//
// Note that the compiler is the one setting (or unsetting) the high bit of
// the pointer when it constructs the type_info, depending on whether it can
// guarantee uniqueness for that specific type_info.
class _LIBCPP_EXCEPTION_ABI type_info
{
type_info& operator=(const type_info&);
type_info(const type_info&);

_LIBCPP_INLINE_VISIBILITY
int __compare_nonunique_names(const type_info &__arg) const _NOEXCEPT
{ return __builtin_strcmp(name(), __arg.name()); }

protected:
uintptr_t __type_name;

_LIBCPP_INLINE_VISIBILITY
explicit type_info(const char* __n)
: __type_name(reinterpret_cast<uintptr_t>(__n)) {}

public:
_LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
virtual ~type_info();

_LIBCPP_INLINE_VISIBILITY
const char* name() const _NOEXCEPT
{
Expand Down Expand Up @@ -174,7 +190,35 @@ public:
return false;
return __compare_nonunique_names(__arg) == 0;
}
#else

_LIBCPP_INLINE_VISIBILITY
bool operator!=(const type_info& __arg) const _NOEXCEPT
{ return !operator==(__arg); }
};

#else // !_LIBCPP_ABI_MICROSOFT && !_LIBCPP_HAS_NONUNIQUE_TYPEINFO

// This implementation of type_info assumes a unique copy of the RTTI for a
// given type inside a program. This is a valid assumption when abiding to
// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components).
// Under this assumption, we can always compare the addresses of the type names
// to implement equality-comparison of type_infos instead of having to perform
// a deep string comparison.
class _LIBCPP_EXCEPTION_ABI type_info
{
type_info& operator=(const type_info&);
type_info(const type_info&);

protected:
const char *__type_name;

_LIBCPP_INLINE_VISIBILITY
explicit type_info(const char* __n) : __type_name(__n) {}

public:
_LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
virtual ~type_info();

_LIBCPP_INLINE_VISIBILITY
const char* name() const _NOEXCEPT
{ return __type_name; }
Expand All @@ -190,14 +234,14 @@ public:
_LIBCPP_INLINE_VISIBILITY
bool operator==(const type_info& __arg) const _NOEXCEPT
{ return __type_name == __arg.__type_name; }
#endif
#endif // _LIBCPP_ABI_MICROSOFT

_LIBCPP_INLINE_VISIBILITY
bool operator!=(const type_info& __arg) const _NOEXCEPT
{ return !operator==(__arg); }
};

#endif

class _LIBCPP_EXCEPTION_ABI bad_cast
: public exception
{
Expand Down

0 comments on commit 6b653fc

Please sign in to comment.