summaryrefslogtreecommitdiff
path: root/libcxxabi/src/private_typeinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libcxxabi/src/private_typeinfo.cpp')
-rw-r--r--libcxxabi/src/private_typeinfo.cpp1052
1 files changed, 0 insertions, 1052 deletions
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
deleted file mode 100644
index 04ce90133767..000000000000
--- a/libcxxabi/src/private_typeinfo.cpp
+++ /dev/null
@@ -1,1052 +0,0 @@
-//===----------------------- private_typeinfo.cpp -------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "private_typeinfo.h"
-
-namespace __cxxabiv1
-{
-
-#pragma GCC visibility push(hidden)
-
-// __shim_type_info
-
-__shim_type_info::~__shim_type_info()
-{
-}
-
-void __shim_type_info::noop1() const {}
-void __shim_type_info::noop2() const {}
-
-// __fundamental_type_info
-
-// This miraculously (compiler magic) emits the type_info's for:
-// 1. all of the fundamental types
-// 2. pointers to all of the fundamental types
-// 3. pointers to all of the const fundamental types
-__fundamental_type_info::~__fundamental_type_info()
-{
-}
-
-// __array_type_info
-
-__array_type_info::~__array_type_info()
-{
-}
-
-// __function_type_info
-
-__function_type_info::~__function_type_info()
-{
-}
-
-// __enum_type_info
-
-__enum_type_info::~__enum_type_info()
-{
-}
-
-// __class_type_info
-
-__class_type_info::~__class_type_info()
-{
-}
-
-// __si_class_type_info
-
-__si_class_type_info::~__si_class_type_info()
-{
-}
-
-// __vmi_class_type_info
-
-__vmi_class_type_info::~__vmi_class_type_info()
-{
-}
-
-// __pbase_type_info
-
-__pbase_type_info::~__pbase_type_info()
-{
-}
-
-// __pointer_type_info
-
-__pointer_type_info::~__pointer_type_info()
-{
-}
-
-// __pointer_to_member_type_info
-
-__pointer_to_member_type_info::~__pointer_to_member_type_info()
-{
-}
-
-// can_catch
-
-// A handler is a match for an exception object of type E if
-// 1. The handler is of type cv T or cv T& and E and T are the same type
-// (ignoring the top-level cv-qualifiers), or
-// 2. the handler is of type cv T or cv T& and T is an unambiguous public
-// base class of E, or
-// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be
-// converted to the type of the handler by either or both of
-// A. a standard pointer conversion (4.10) not involving conversions to
-// pointers to private or protected or ambiguous classes
-// B. a qualification conversion
-// 4. the handler is a pointer or pointer to member type and E is
-// std::nullptr_t.
-
-// adjustedPtr:
-//
-// catch (A& a) : adjustedPtr == &a
-// catch (A* a) : adjustedPtr == a
-// catch (A** a) : adjustedPtr == a
-//
-// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object)
-// catch (D2* d2) : adjustedPtr == d2
-// catch (D2*& d2) : adjustedPtr == d2
-//
-// catch (...) : adjustedPtr == & of the exception
-
-// Handles bullet 1
-bool
-__fundamental_type_info::can_catch(const __shim_type_info* thrown_type,
- void*&) const
-{
- return this == thrown_type;
-}
-
-bool
-__array_type_info::can_catch(const __shim_type_info*, void*&) const
-{
- // We can get here if someone tries to catch an array by reference.
- // However if someone tries to throw an array, it immediately gets
- // converted to a pointer, which will not convert back to an array
- // at the catch clause. So this can never catch anything.
- return false;
-}
-
-bool
-__function_type_info::can_catch(const __shim_type_info*, void*&) const
-{
- // We can get here if someone tries to catch a function by reference.
- // However if someone tries to throw a function, it immediately gets
- // converted to a pointer, which will not convert back to a function
- // at the catch clause. So this can never catch anything.
- return false;
-}
-
-// Handles bullet 1
-bool
-__enum_type_info::can_catch(const __shim_type_info* thrown_type,
- void*&) const
-{
- return this == thrown_type;
-}
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-
-// Handles bullets 1 and 2
-bool
-__class_type_info::can_catch(const __shim_type_info* thrown_type,
- void*& adjustedPtr) const
-{
- // bullet 1
- if (this == thrown_type)
- return true;
- const __class_type_info* thrown_class_type =
- dynamic_cast<const __class_type_info*>(thrown_type);
- if (thrown_class_type == 0)
- return false;
- // bullet 2
- __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0};
- info.number_of_dst_type = 1;
- thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
- if (info.path_dst_ptr_to_static_ptr == public_path)
- {
- adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
- return true;
- }
- return false;
-}
-
-#pragma clang diagnostic pop
-
-void
-__class_type_info::process_found_base_class(__dynamic_cast_info* info,
- void* adjustedPtr,
- int path_below) const
-{
- if (info->dst_ptr_leading_to_static_ptr == 0)
- {
- // First time here
- info->dst_ptr_leading_to_static_ptr = adjustedPtr;
- info->path_dst_ptr_to_static_ptr = path_below;
- info->number_to_static_ptr = 1;
- }
- else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
- {
- // We've been here before. Update path to "most public"
- if (info->path_dst_ptr_to_static_ptr == not_public_path)
- info->path_dst_ptr_to_static_ptr = path_below;
- }
- else
- {
- // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
- // to a static_type
- info->number_to_static_ptr += 1;
- info->path_dst_ptr_to_static_ptr = not_public_path;
- info->search_done = true;
- }
-}
-
-void
-__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
- void* adjustedPtr,
- int path_below) const
-{
- if (this == info->static_type)
- process_found_base_class(info, adjustedPtr, path_below);
-}
-
-void
-__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
- void* adjustedPtr,
- int path_below) const
-{
- if (this == info->static_type)
- process_found_base_class(info, adjustedPtr, path_below);
- else
- __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
-}
-
-void
-__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
- void* adjustedPtr,
- int path_below) const
-{
- ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
- if (__offset_flags & __virtual_mask)
- {
- const char* vtable = *static_cast<const char*const*>(adjustedPtr);
- offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
- }
- __base_type->has_unambiguous_public_base(info,
- static_cast<char*>(adjustedPtr) + offset_to_base,
- (__offset_flags & __public_mask) ?
- path_below :
- not_public_path);
-}
-
-void
-__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
- void* adjustedPtr,
- int path_below) const
-{
- if (this == info->static_type)
- process_found_base_class(info, adjustedPtr, path_below);
- else
- {
- typedef const __base_class_type_info* Iter;
- const Iter e = __base_info + __base_count;
- Iter p = __base_info;
- p->has_unambiguous_public_base(info, adjustedPtr, path_below);
- if (++p < e)
- {
- do
- {
- p->has_unambiguous_public_base(info, adjustedPtr, path_below);
- if (info->search_done)
- break;
- } while (++p < e);
- }
- }
-}
-
-// Handles bullets 1 and 4 for both pointers and member pointers
-bool
-__pbase_type_info::can_catch(const __shim_type_info* thrown_type,
- void*&) const
-{
- if (this == thrown_type)
- return true;
- return thrown_type == &typeid(std::nullptr_t);
-}
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-
-// Handles bullets 1, 3 and 4
-bool
-__pointer_type_info::can_catch(const __shim_type_info* thrown_type,
- void*& adjustedPtr) const
-{
- // Do the dereference adjustment
- adjustedPtr = *static_cast<void**>(adjustedPtr);
- // bullets 1 and 4
- if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
- return true;
- // bullet 3
- const __pointer_type_info* thrown_pointer_type =
- dynamic_cast<const __pointer_type_info*>(thrown_type);
- if (thrown_pointer_type == 0)
- return false;
- // bullet 3B
- if (thrown_pointer_type->__flags & ~__flags)
- return false;
- if (__pointee == thrown_pointer_type->__pointee)
- return true;
- // bullet 3A
- if (__pointee == &typeid(void))
- return true;
- const __class_type_info* catch_class_type =
- dynamic_cast<const __class_type_info*>(__pointee);
- if (catch_class_type == 0)
- return false;
- const __class_type_info* thrown_class_type =
- dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
- if (thrown_class_type == 0)
- return false;
- __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0};
- info.number_of_dst_type = 1;
- thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
- if (info.path_dst_ptr_to_static_ptr == public_path)
- {
- adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
- return true;
- }
- return false;
-}
-
-#pragma clang diagnostic pop
-
-#pragma GCC visibility pop
-#pragma GCC visibility push(default)
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-
-// __dynamic_cast
-
-// static_ptr: pointer to an object of type static_type; nonnull, and since the
-// object is polymorphic, *(void**)static_ptr is a virtual table pointer.
-// static_ptr is &v in the expression dynamic_cast<T>(v).
-// static_type: static type of the object pointed to by static_ptr.
-// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").
-// src2dst_offset: a static hint about the location of the
-// source subobject with respect to the complete object;
-// special negative values are:
-// -1: no hint
-// -2: static_type is not a public base of dst_type
-// -3: static_type is a multiple public base type but never a
-// virtual base type
-// otherwise, the static_type type is a unique public nonvirtual
-// base type of dst_type at offset src2dst_offset from the
-// origin of dst_type.
-//
-// (dynamic_ptr, dynamic_type) are the run time type of the complete object
-// referred to by static_ptr and a pointer to it. These can be found from
-// static_ptr for polymorphic types.
-// static_type is guaranteed to be a polymorphic type.
-//
-// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each
-// node of the tree represents a base class/object of its parent (or parents) below.
-// Each node is uniquely represented by a pointer to the object, and a pointer
-// to a type_info - its type. Different nodes may have the same pointer and
-// different nodes may have the same type. But only one node has a specific
-// (pointer-value, type) pair. In C++ two objects of the same type can not
-// share the same address.
-//
-// There are two flavors of nodes which have the type dst_type:
-// 1. Those that are derived from (below) (static_ptr, static_type).
-// 2. Those that are not derived from (below) (static_ptr, static_type).
-//
-// Invariants of the DAG:
-//
-// There is at least one path from the root (dynamic_ptr, dynamic_type) to
-// the node (static_ptr, static_type). This path may or may not be public.
-// There may be more than one such path (some public some not). Such a path may
-// or may not go through a node having type dst_type.
-//
-// No node of type T appears above a node of the same type. That means that
-// there is only one node with dynamic_type. And if dynamic_type == dst_type,
-// then there is only one dst_type in the DAG.
-//
-// No node of type dst_type appears above a node of type static_type. Such
-// DAG's are possible in C++, but the compiler computes those dynamic_casts at
-// compile time, and only calls __dynamic_cast when dst_type lies below
-// static_type in the DAG.
-//
-// dst_type != static_type: The compiler computes the dynamic_cast in this case too.
-// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too.
-//
-// Returns:
-//
-// If there is exactly one dst_type of flavor 1, and
-// If there is a public path from that dst_type to (static_ptr, static_type), or
-// If there are 0 dst_types of flavor 2, and there is a public path from
-// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public
-// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return
-// a pointer to that dst_type.
-// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and
-// if there is a public path from (dynamic_ptr, dynamic_type) to
-// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
-// to the one dst_type, then return a pointer to that one dst_type.
-// Else return nullptr.
-//
-// If dynamic_type == dst_type, then the above algorithm collapses to the
-// following cheaper algorithm:
-//
-// If there is a public path from (dynamic_ptr, dynamic_type) to
-// (static_ptr, static_type), then return dynamic_ptr.
-// Else return nullptr.
-extern "C"
-void*
-__dynamic_cast(const void* static_ptr,
- const __class_type_info* static_type,
- const __class_type_info* dst_type,
- std::ptrdiff_t src2dst_offset)
-{
- // Possible future optimization: Take advantage of src2dst_offset
- // Currently clang always sets src2dst_offset to -1 (no hint).
-
- // Get (dynamic_ptr, dynamic_type) from static_ptr
- void** vtable = *(void***)static_ptr;
- ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
- const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
- const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
-
- // Initialize answer to nullptr. This will be changed from the search
- // results if a non-null answer is found. Regardless, this is what will
- // be returned.
- const void* dst_ptr = 0;
- // Initialize info struct for this search.
- __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
-
- // Find out if we can use a giant short cut in the search
- if (dynamic_type == dst_type)
- {
- // Using giant short cut. Add that information to info.
- info.number_of_dst_type = 1;
- // Do the search
- dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path);
- // Query the search.
- if (info.path_dst_ptr_to_static_ptr == public_path)
- dst_ptr = dynamic_ptr;
- }
- else
- {
- // Not using giant short cut. Do the search
- dynamic_type->search_below_dst(&info, dynamic_ptr, public_path);
- // Query the search.
- switch (info.number_to_static_ptr)
- {
- case 0:
- if (info.number_to_dst_ptr == 1 &&
- info.path_dynamic_ptr_to_static_ptr == public_path &&
- info.path_dynamic_ptr_to_dst_ptr == public_path)
- dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
- break;
- case 1:
- if (info.path_dst_ptr_to_static_ptr == public_path ||
- (
- info.number_to_dst_ptr == 0 &&
- info.path_dynamic_ptr_to_static_ptr == public_path &&
- info.path_dynamic_ptr_to_dst_ptr == public_path
- )
- )
- dst_ptr = info.dst_ptr_leading_to_static_ptr;
- break;
- }
- }
- return const_cast<void*>(dst_ptr);
-}
-
-#pragma clang diagnostic pop
-
-#pragma GCC visibility pop
-#pragma GCC visibility push(hidden)
-
-// Call this function when you hit a static_type which is a base (above) a dst_type.
-// Let caller know you hit a static_type. But only start recording details if
-// this is (static_ptr, static_type) -- the node we are casting from.
-// If this is (static_ptr, static_type)
-// Record the path (public or not) from the dst_type to here. There may be
-// multiple paths from the same dst_type to here, record the "most public" one.
-// Record the dst_ptr as pointing to (static_ptr, static_type).
-// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),
-// then mark this dyanmic_cast as ambiguous and stop the search.
-void
-__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info,
- const void* dst_ptr,
- const void* current_ptr,
- int path_below) const
-{
- // Record that we found a static_type
- info->found_any_static_type = true;
- if (current_ptr == info->static_ptr)
- {
- // Record that we found (static_ptr, static_type)
- info->found_our_static_ptr = true;
- if (info->dst_ptr_leading_to_static_ptr == 0)
- {
- // First time here
- info->dst_ptr_leading_to_static_ptr = dst_ptr;
- info->path_dst_ptr_to_static_ptr = path_below;
- info->number_to_static_ptr = 1;
- // If there is only one dst_type in the entire tree and the path from
- // there to here is public then we are done!
- if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
- info->search_done = true;
- }
- else if (info->dst_ptr_leading_to_static_ptr == dst_ptr)
- {
- // We've been here before. Update path to "most public"
- if (info->path_dst_ptr_to_static_ptr == not_public_path)
- info->path_dst_ptr_to_static_ptr = path_below;
- // If there is only one dst_type in the entire tree and the path from
- // there to here is public then we are done!
- if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
- info->search_done = true;
- }
- else
- {
- // We've detected an ambiguous cast from (static_ptr, static_type)
- // to a dst_type
- info->number_to_static_ptr += 1;
- info->search_done = true;
- }
- }
-}
-
-// Call this function when you hit a static_type which is not a base (above) a dst_type.
-// If this is (static_ptr, static_type)
-// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be
-// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one.
-void
-__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,
- const void* current_ptr,
- int path_below) const
-{
- if (current_ptr == info->static_ptr)
- {
- // Record the most public path from (dynamic_ptr, dynamic_type) to
- // (static_ptr, static_type)
- if (info->path_dynamic_ptr_to_static_ptr != public_path)
- info->path_dynamic_ptr_to_static_ptr = path_below;
- }
-}
-
-// Call this function when searching below a dst_type node. This function searches
-// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes.
-// If it finds a static_type node, there is no need to further search base classes
-// above.
-// If it finds a dst_type node it should search base classes using search_above_dst
-// to find out if this dst_type points to (static_ptr, static_type) or not.
-// Either way, the dst_type is recorded as one of two "flavors": one that does
-// or does not point to (static_ptr, static_type).
-// If this is neither a static_type nor a dst_type node, continue searching
-// base classes above.
-// All the hoopla surrounding the search code is doing nothing but looking for
-// excuses to stop the search prematurely (break out of the for-loop). That is,
-// the algorithm below is simply an optimization of this:
-// void
-// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
-// const void* current_ptr,
-// int path_below) const
-// {
-// typedef const __base_class_type_info* Iter;
-// if (this == info->static_type)
-// process_static_type_below_dst(info, current_ptr, path_below);
-// else if (this == info->dst_type)
-// {
-// // Record the most public access path that got us here
-// if (info->path_dynamic_ptr_to_dst_ptr != public_path)
-// info->path_dynamic_ptr_to_dst_ptr = path_below;
-// bool does_dst_type_point_to_our_static_type = false;
-// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p)
-// {
-// p->search_above_dst(info, current_ptr, current_ptr, public_path);
-// if (info->found_our_static_ptr)
-// does_dst_type_point_to_our_static_type = true;
-// // break out early here if you can detect it doesn't matter if you do
-// }
-// if (!does_dst_type_point_to_our_static_type)
-// {
-// // We found a dst_type that doesn't point to (static_ptr, static_type)
-// // So record the address of this dst_ptr and increment the
-// // count of the number of such dst_types found in the tree.
-// info->dst_ptr_not_leading_to_static_ptr = current_ptr;
-// info->number_to_dst_ptr += 1;
-// }
-// }
-// else
-// {
-// // This is not a static_type and not a dst_type.
-// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
-// {
-// p->search_below_dst(info, current_ptr, public_path);
-// // break out early here if you can detect it doesn't matter if you do
-// }
-// }
-// }
-void
-__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
- const void* current_ptr,
- int path_below) const
-{
- typedef const __base_class_type_info* Iter;
- if (this == info->static_type)
- process_static_type_below_dst(info, current_ptr, path_below);
- else if (this == info->dst_type)
- {
- // We've been here before if we've recorded current_ptr in one of these
- // two places:
- if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
- current_ptr == info->dst_ptr_not_leading_to_static_ptr)
- {
- // We've seen this node before, and therefore have already searched
- // its base classes above.
- // Update path to here that is "most public".
- if (path_below == public_path)
- info->path_dynamic_ptr_to_dst_ptr = public_path;
- }
- else // We have haven't been here before
- {
- // Record the access path that got us here
- // If there is more than one dst_type this path doesn't matter.
- info->path_dynamic_ptr_to_dst_ptr = path_below;
- // Only search above here if dst_type derives from static_type, or
- // if it is unknown if dst_type derives from static_type.
- if (info->is_dst_type_derived_from_static_type != no)
- {
- // Set up flags to record results from all base classes
- bool is_dst_type_derived_from_static_type = false;
- bool does_dst_type_point_to_our_static_type = false;
- // We've found a dst_type with a potentially public path to here.
- // We have to assume the path is public because it may become
- // public later (if we get back to here with a public path).
- // We can stop looking above if:
- // 1. We've found a public path to (static_ptr, static_type).
- // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
- // This is detected at the (static_ptr, static_type).
- // 3. We can prove that there is no public path to (static_ptr, static_type)
- // above here.
- const Iter e = __base_info + __base_count;
- for (Iter p = __base_info; p < e; ++p)
- {
- // Zero out found flags
- info->found_our_static_ptr = false;
- info->found_any_static_type = false;
- p->search_above_dst(info, current_ptr, current_ptr, public_path);
- if (info->search_done)
- break;
- if (info->found_any_static_type)
- {
- is_dst_type_derived_from_static_type = true;
- if (info->found_our_static_ptr)
- {
- does_dst_type_point_to_our_static_type = true;
- // If we found what we're looking for, stop looking above.
- if (info->path_dst_ptr_to_static_ptr == public_path)
- break;
- // We found a private path to (static_ptr, static_type)
- // If there is no diamond then there is only one path
- // to (static_ptr, static_type) and we just found it.
- if (!(__flags & __diamond_shaped_mask))
- break;
- }
- else
- {
- // If we found a static_type that isn't the one we're looking
- // for, and if there are no repeated types above here,
- // then stop looking.
- if (!(__flags & __non_diamond_repeat_mask))
- break;
- }
- }
- }
- if (!does_dst_type_point_to_our_static_type)
- {
- // We found a dst_type that doesn't point to (static_ptr, static_type)
- // So record the address of this dst_ptr and increment the
- // count of the number of such dst_types found in the tree.
- info->dst_ptr_not_leading_to_static_ptr = current_ptr;
- info->number_to_dst_ptr += 1;
- // If there exists another dst with a private path to
- // (static_ptr, static_type), then the cast from
- // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
- // so stop search.
- if (info->number_to_static_ptr == 1 &&
- info->path_dst_ptr_to_static_ptr == not_public_path)
- info->search_done = true;
- }
- // If we found no static_type,s then dst_type doesn't derive
- // from static_type, else it does. Record this result so that
- // next time we hit a dst_type we will know not to search above
- // it if it doesn't derive from static_type.
- if (is_dst_type_derived_from_static_type)
- info->is_dst_type_derived_from_static_type = yes;
- else
- info->is_dst_type_derived_from_static_type = no;
- }
- }
- }
- else
- {
- // This is not a static_type and not a dst_type.
- const Iter e = __base_info + __base_count;
- Iter p = __base_info;
- p->search_below_dst(info, current_ptr, path_below);
- if (++p < e)
- {
- if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
- {
- // If there are multiple paths to a base above from here, or if
- // a dst_type pointing to (static_ptr, static_type) has been found,
- // then there is no way to break out of this loop early unless
- // something below detects the search is done.
- do
- {
- if (info->search_done)
- break;
- p->search_below_dst(info, current_ptr, path_below);
- } while (++p < e);
- }
- else if (__flags & __non_diamond_repeat_mask)
- {
- // There are not multiple paths to any base class from here and a
- // dst_type pointing to (static_ptr, static_type) has not yet been
- // found.
- do
- {
- if (info->search_done)
- break;
- // If we just found a dst_type with a public path to (static_ptr, static_type),
- // then the only reason to continue the search is to make sure
- // no other dst_type points to (static_ptr, static_type).
- // If !diamond, then we don't need to search here.
- if (info->number_to_static_ptr == 1 &&
- info->path_dst_ptr_to_static_ptr == public_path)
- break;
- p->search_below_dst(info, current_ptr, path_below);
- } while (++p < e);
- }
- else
- {
- // There are no repeated types above this node.
- // There are no nodes with multiple parents above this node.
- // no dst_type has been found to (static_ptr, static_type)
- do
- {
- if (info->search_done)
- break;
- // If we just found a dst_type with a public path to (static_ptr, static_type),
- // then the only reason to continue the search is to make sure sure
- // no other dst_type points to (static_ptr, static_type).
- // If !diamond, then we don't need to search here.
- // if we just found a dst_type with a private path to (static_ptr, static_type),
- // then we're only looking for a public path to (static_ptr, static_type)
- // and to check for other dst_types.
- // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
- // and not a dst_type under here.
- if (info->number_to_static_ptr == 1)
- break;
- p->search_below_dst(info, current_ptr, path_below);
- } while (++p < e);
- }
- }
- }
-}
-
-// This is the same algorithm as __vmi_class_type_info::search_below_dst but
-// simplified to the case that there is only a single base class.
-void
-__si_class_type_info::search_below_dst(__dynamic_cast_info* info,
- const void* current_ptr,
- int path_below) const
-{
- if (this == info->static_type)
- process_static_type_below_dst(info, current_ptr, path_below);
- else if (this == info->dst_type)
- {
- // We've been here before if we've recorded current_ptr in one of these
- // two places:
- if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
- current_ptr == info->dst_ptr_not_leading_to_static_ptr)
- {
- // We've seen this node before, and therefore have already searched
- // its base classes above.
- // Update path to here that is "most public".
- if (path_below == public_path)
- info->path_dynamic_ptr_to_dst_ptr = public_path;
- }
- else // We have haven't been here before
- {
- // Record the access path that got us here
- // If there is more than one dst_type this path doesn't matter.
- info->path_dynamic_ptr_to_dst_ptr = path_below;
- // Only search above here if dst_type derives from static_type, or
- // if it is unknown if dst_type derives from static_type.
- if (info->is_dst_type_derived_from_static_type != no)
- {
- // Set up flags to record results from all base classes
- bool is_dst_type_derived_from_static_type = false;
- bool does_dst_type_point_to_our_static_type = false;
- // Zero out found flags
- info->found_our_static_ptr = false;
- info->found_any_static_type = false;
- __base_type->search_above_dst(info, current_ptr, current_ptr, public_path);
- if (info->found_any_static_type)
- {
- is_dst_type_derived_from_static_type = true;
- if (info->found_our_static_ptr)
- does_dst_type_point_to_our_static_type = true;
- }
- if (!does_dst_type_point_to_our_static_type)
- {
- // We found a dst_type that doesn't point to (static_ptr, static_type)
- // So record the address of this dst_ptr and increment the
- // count of the number of such dst_types found in the tree.
- info->dst_ptr_not_leading_to_static_ptr = current_ptr;
- info->number_to_dst_ptr += 1;
- // If there exists another dst with a private path to
- // (static_ptr, static_type), then the cast from
- // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
- if (info->number_to_static_ptr == 1 &&
- info->path_dst_ptr_to_static_ptr == not_public_path)
- info->search_done = true;
- }
- // If we found no static_type,s then dst_type doesn't derive
- // from static_type, else it does. Record this result so that
- // next time we hit a dst_type we will know not to search above
- // it if it doesn't derive from static_type.
- if (is_dst_type_derived_from_static_type)
- info->is_dst_type_derived_from_static_type = yes;
- else
- info->is_dst_type_derived_from_static_type = no;
- }
- }
- }
- else
- {
- // This is not a static_type and not a dst_type
- __base_type->search_below_dst(info, current_ptr, path_below);
- }
-}
-
-// This is the same algorithm as __vmi_class_type_info::search_below_dst but
-// simplified to the case that there is no base class.
-void
-__class_type_info::search_below_dst(__dynamic_cast_info* info,
- const void* current_ptr,
- int path_below) const
-{
- typedef const __base_class_type_info* Iter;
- if (this == info->static_type)
- process_static_type_below_dst(info, current_ptr, path_below);
- else if (this == info->dst_type)
- {
- // We've been here before if we've recorded current_ptr in one of these
- // two places:
- if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
- current_ptr == info->dst_ptr_not_leading_to_static_ptr)
- {
- // We've seen this node before, and therefore have already searched
- // its base classes above.
- // Update path to here that is "most public".
- if (path_below == public_path)
- info->path_dynamic_ptr_to_dst_ptr = public_path;
- }
- else // We have haven't been here before
- {
- // Record the access path that got us here
- // If there is more than one dst_type this path doesn't matter.
- info->path_dynamic_ptr_to_dst_ptr = path_below;
- // We found a dst_type that doesn't point to (static_ptr, static_type)
- // So record the address of this dst_ptr and increment the
- // count of the number of such dst_types found in the tree.
- info->dst_ptr_not_leading_to_static_ptr = current_ptr;
- info->number_to_dst_ptr += 1;
- // If there exists another dst with a private path to
- // (static_ptr, static_type), then the cast from
- // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
- if (info->number_to_static_ptr == 1 &&
- info->path_dst_ptr_to_static_ptr == not_public_path)
- info->search_done = true;
- // We found that dst_type does not derive from static_type
- info->is_dst_type_derived_from_static_type = no;
- }
- }
-}
-
-// Call this function when searching above a dst_type node. This function searches
-// for a public path to (static_ptr, static_type).
-// This function is guaranteed not to find a node of type dst_type.
-// Theoretically this is a very simple function which just stops if it finds a
-// static_type node: All the hoopla surrounding the search code is doing
-// nothing but looking for excuses to stop the search prematurely (break out of
-// the for-loop). That is, the algorithm below is simply an optimization of this:
-// void
-// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
-// const void* dst_ptr,
-// const void* current_ptr,
-// int path_below) const
-// {
-// if (this == info->static_type)
-// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
-// else
-// {
-// typedef const __base_class_type_info* Iter;
-// // This is not a static_type and not a dst_type
-// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
-// {
-// p->search_above_dst(info, dst_ptr, current_ptr, public_path);
-// // break out early here if you can detect it doesn't matter if you do
-// }
-// }
-// }
-void
-__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
- const void* dst_ptr,
- const void* current_ptr,
- int path_below) const
-{
- if (this == info->static_type)
- process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
- else
- {
- typedef const __base_class_type_info* Iter;
- // This is not a static_type and not a dst_type
- // Save flags so they can be restored when returning to nodes below.
- bool found_our_static_ptr = info->found_our_static_ptr;
- bool found_any_static_type = info->found_any_static_type;
- // We've found a dst_type below with a path to here. If the path
- // to here is not public, there may be another path to here that
- // is public. So we have to assume that the path to here is public.
- // We can stop looking above if:
- // 1. We've found a public path to (static_ptr, static_type).
- // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
- // This is detected at the (static_ptr, static_type).
- // 3. We can prove that there is no public path to (static_ptr, static_type)
- // above here.
- const Iter e = __base_info + __base_count;
- Iter p = __base_info;
- // Zero out found flags
- info->found_our_static_ptr = false;
- info->found_any_static_type = false;
- p->search_above_dst(info, dst_ptr, current_ptr, path_below);
- if (++p < e)
- {
- do
- {
- if (info->search_done)
- break;
- if (info->found_our_static_ptr)
- {
- // If we found what we're looking for, stop looking above.
- if (info->path_dst_ptr_to_static_ptr == public_path)
- break;
- // We found a private path to (static_ptr, static_type)
- // If there is no diamond then there is only one path
- // to (static_ptr, static_type) from here and we just found it.
- if (!(__flags & __diamond_shaped_mask))
- break;
- }
- else if (info->found_any_static_type)
- {
- // If we found a static_type that isn't the one we're looking
- // for, and if there are no repeated types above here,
- // then stop looking.
- if (!(__flags & __non_diamond_repeat_mask))
- break;
- }
- // Zero out found flags
- info->found_our_static_ptr = false;
- info->found_any_static_type = false;
- p->search_above_dst(info, dst_ptr, current_ptr, path_below);
- } while (++p < e);
- }
- // Restore flags
- info->found_our_static_ptr = found_our_static_ptr;
- info->found_any_static_type = found_any_static_type;
- }
-}
-
-// This is the same algorithm as __vmi_class_type_info::search_above_dst but
-// simplified to the case that there is only a single base class.
-void
-__si_class_type_info::search_above_dst(__dynamic_cast_info* info,
- const void* dst_ptr,
- const void* current_ptr,
- int path_below) const
-{
- if (this == info->static_type)
- process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
- else
- __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below);
-}
-
-// This is the same algorithm as __vmi_class_type_info::search_above_dst but
-// simplified to the case that there is no base class.
-void
-__class_type_info::search_above_dst(__dynamic_cast_info* info,
- const void* dst_ptr,
- const void* current_ptr,
- int path_below) const
-{
- if (this == info->static_type)
- process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
-}
-
-// The search functions for __base_class_type_info are simply convenience
-// functions for adjusting the current_ptr and path_below as the search is
-// passed up to the base class node.
-
-void
-__base_class_type_info::search_above_dst(__dynamic_cast_info* info,
- const void* dst_ptr,
- const void* current_ptr,
- int path_below) const
-{
- ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
- if (__offset_flags & __virtual_mask)
- {
- const char* vtable = *static_cast<const char*const*>(current_ptr);
- offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
- }
- __base_type->search_above_dst(info, dst_ptr,
- static_cast<const char*>(current_ptr) + offset_to_base,
- (__offset_flags & __public_mask) ?
- path_below :
- not_public_path);
-}
-
-void
-__base_class_type_info::search_below_dst(__dynamic_cast_info* info,
- const void* current_ptr,
- int path_below) const
-{
- ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
- if (__offset_flags & __virtual_mask)
- {
- const char* vtable = *static_cast<const char*const*>(current_ptr);
- offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
- }
- __base_type->search_below_dst(info,
- static_cast<const char*>(current_ptr) + offset_to_base,
- (__offset_flags & __public_mask) ?
- path_below :
- not_public_path);
-}
-
-#pragma GCC visibility pop
-
-} // __cxxabiv1