Skip to content

Commit 17095dc

Browse files
committed
[libc++][NFC] Increase readability of typeinfo comparison of ARM64
We wasted a good deal of time trying to figure out whether our implementation was correct. In the end, it was, but it wasn't so easy to determine. This patch dumbs down the implementation and improves the documentation to make it easier to validate. See https://lists.llvm.org/pipermail/libcxx-dev/2020-December/001060.html. Differential Revision: https://reviews.llvm.org/D97802
1 parent 6225004 commit 17095dc

File tree

1 file changed

+25
-20
lines changed

1 file changed

+25
-20
lines changed

libcxx/include/typeinfo

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public:
125125
// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 1)
126126
// ------------------------------------------------------------------------- //
127127
// 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
128+
// given type inside a program. This is a valid assumption when abiding to the
129129
// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components).
130130
// Under this assumption, we can always compare the addresses of the type names
131131
// to implement equality-comparison of type_infos instead of having to perform
@@ -144,22 +144,29 @@ public:
144144
// NonUniqueARMRTTIBit
145145
// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 3)
146146
// -------------------------------------------------------------------------- //
147+
// This implementation is specific to ARM64 on Apple platforms.
148+
//
147149
// 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.
150+
// the RTTI for a given type inside a program. When constructing the type_info,
151+
// the compiler packs the pointer to the type name into a uintptr_t and reserves
152+
// the high bit of that pointer, which is assumed to be free for use under that
153+
// ABI. If that high bit is set, that specific copy of the RTTI can't be assumed
154+
// to be unique within the program. If the high bit is unset, then the RTTI can
155+
// be assumed to be unique within the program.
157156
//
158-
// This implementation is specific to ARM64 on Apple platforms.
157+
// When comparing type_infos, if both RTTIs can be assumed to be unique, it
158+
// suffices to compare their addresses. If both the RTTIs can't be assumed to
159+
// be unique, we must perform a deep string comparison of the type names.
160+
// However, if one of the RTTIs is guaranteed unique and the other one isn't,
161+
// then both RTTIs are necessarily not to be considered equal.
159162
//
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+
// The intent of this design is to remove the need for weak symbols. Specifically,
164+
// if a type would normally have a default-visibility RTTI emitted as a weak
165+
// symbol, it is given hidden visibility instead and the non-unique bit is set.
166+
// Otherwise, types declared with hidden visibility are always considered to have
167+
// a unique RTTI: the RTTI is emitted with linkonce_odr linkage and is assumed
168+
// to be deduplicated by the linker within the linked image. Across linked image
169+
// boundaries, such types are thus considered different types.
163170

164171
// This value can be overriden in the __config_site. When it's not overriden,
165172
// we pick a default implementation based on the platform here.
@@ -248,13 +255,15 @@ struct __type_info_implementations {
248255
static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
249256
if (__lhs == __rhs)
250257
return true;
251-
if (__is_type_name_unique(__lhs, __rhs))
258+
if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs))
259+
// Either both are unique and have a different address, or one of them
260+
// is unique and the other one isn't. In both cases they are unequal.
252261
return false;
253262
return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0;
254263
}
255264
_LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
256265
static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
257-
if (__is_type_name_unique(__lhs, __rhs))
266+
if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs))
258267
return __lhs < __rhs;
259268
return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0;
260269
}
@@ -269,10 +278,6 @@ struct __type_info_implementations {
269278
static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT {
270279
return !(__lhs & __non_unique_rtti_bit::value);
271280
}
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-
}
276281
};
277282

278283
typedef

0 commit comments

Comments
 (0)