cp-tree.h (new_abi_rtti_p): Use flag_new_abi.

* cp-tree.h (new_abi_rtti_p): Use flag_new_abi.

	Runtime support for new-abi rtti.
	* inc/typeinfo (type_info::operator!=): Define in class.
	(type_info::before, type_info::name, type_info::operator==,
	type_info::operator!=): Define new ABI implementations.
	(type_info::is_pointer_p, type_info::is_function_p): Declare
	new virtual functions.
	(type_info::do_catch, type_info::do_upcast): Likewise.

	* tinfo.h (__base_class_info): Define new class.
	(__class_type_info): Likewise.
	(__si_class_type_info): Likewise.
	(__vmi_class_type_info): Likewise.
	(__dynamic_cast): Prototype.

	* tinfo.cc: Conditionalize old and new rtti mechanisms.
	(type_info::is_pointer_p): Define new function.
	(type_info::is_function_p): Likewise.
	(type_info::do_catch): Likewise.
	(type_info::do_upcast): Likewise.
	(vtable_prefix): New structure for vtable access.
	(adjust_pointer): Define new template function.
	(contained_p, public_p, virtual_p, contained_public_p,
	contained_nonpublic_p, contained_nonvirtual_p): Define new
	functions.
	(nonvirtual_base_type): New local variable.
	(__class_type_info::~__class_type_info): Define.
	(__si_class_type_info::~__si_class_type_info): Likewise.
	(__vmi_class_type_info::~__vmi_class_type_info): Likewise.
	(__class_type_info::do_catch): Define new function.
	(__class_type_info::do_upcast): Likewise.
	(__class_type_info::find_public_src): Likewise.
	(__class_type_info::do_find_public_src): Likewise.
	(__si_class_type_info::do_find_public_src): Likewise.
	(__vmi_class_type_info::do_find_public_src): Likewise.
	(__class_type_info::do_dyncast): Likewise.
	(__si_class_type_info::do_dyncast): Likewise.
	(__vmi_class_type_info::do_dyncast): Likewise.
	(__class_type_info::do_upcast): Likewise.
	(__si_class_type_info::do_upcast): Likewise.
	(__vmi_class_type_info::do_upcast): Likewise.
	(__dynamic_cast): Likewise.

	* tinfo2.cc (__fundamental_type_info): Define new class.
	(__pointer_type_info): Likewise.
	(__reference_type_info): Likewise.
	(__array_type_info): Likewise.
	(__function_type_info): Likewise.
	(__enum_type_info): Likewise.
	(__ptr_to_member_type_info): Likewise.
	(__fundamental_type_info::~__fundamental_type_info): Define.
	(__pointer_type_info::~__pointer_type_info): Likewise.
	(__reference_type_info::~__reference_type_info): Likewise.
	(__array_type_info::~__array_type_info): Likewise.
	(__function_type_info::~__function_type_info): Likewise.
	(__enum_type_info::~__enum_type_info): Likewise.
	(__ptr_to_member_type_info::~__ptr_to_member_type_info): Likewise.
	(__pointer_type_info::do_catch): Define new function.
	(__ptr_to_member_type_info::do_catch): Define new function.

	(__throw_type_match_rtti_2): Use new ABI interface, if enabled.
	(__is_pointer): Likewise.

	* exception.cc (__cplus_type_matcher): Deal with new-abi rtti.

From-SVN: r31713
This commit is contained in:
Nathan Sidwell 2000-01-31 10:21:47 +00:00 committed by Nathan Sidwell
parent ab5cffc5e8
commit 808c61c8d3
7 changed files with 1234 additions and 21 deletions

View File

@ -1,3 +1,71 @@
2000-01-31 Nathan Sidwell <sidwell@codesourcery.com>
* cp-tree.h (new_abi_rtti_p): Use flag_new_abi.
Runtime support for new-abi rtti.
* inc/typeinfo (type_info::operator!=): Define in class.
(type_info::before, type_info::name, type_info::operator==,
type_info::operator!=): Define new ABI implementations.
(type_info::is_pointer_p, type_info::is_function_p): Declare
new virtual functions.
(type_info::do_catch, type_info::do_upcast): Likewise.
* tinfo.h (__base_class_info): Define new class.
(__class_type_info): Likewise.
(__si_class_type_info): Likewise.
(__vmi_class_type_info): Likewise.
(__dynamic_cast): Prototype.
* tinfo.cc: Conditionalize old and new rtti mechanisms.
(type_info::is_pointer_p): Define new function.
(type_info::is_function_p): Likewise.
(type_info::do_catch): Likewise.
(type_info::do_upcast): Likewise.
(vtable_prefix): New structure for vtable access.
(adjust_pointer): Define new template function.
(contained_p, public_p, virtual_p, contained_public_p,
contained_nonpublic_p, contained_nonvirtual_p): Define new
functions.
(nonvirtual_base_type): New local variable.
(__class_type_info::~__class_type_info): Define.
(__si_class_type_info::~__si_class_type_info): Likewise.
(__vmi_class_type_info::~__vmi_class_type_info): Likewise.
(__class_type_info::do_catch): Define new function.
(__class_type_info::do_upcast): Likewise.
(__class_type_info::find_public_src): Likewise.
(__class_type_info::do_find_public_src): Likewise.
(__si_class_type_info::do_find_public_src): Likewise.
(__vmi_class_type_info::do_find_public_src): Likewise.
(__class_type_info::do_dyncast): Likewise.
(__si_class_type_info::do_dyncast): Likewise.
(__vmi_class_type_info::do_dyncast): Likewise.
(__class_type_info::do_upcast): Likewise.
(__si_class_type_info::do_upcast): Likewise.
(__vmi_class_type_info::do_upcast): Likewise.
(__dynamic_cast): Likewise.
* tinfo2.cc (__fundamental_type_info): Define new class.
(__pointer_type_info): Likewise.
(__reference_type_info): Likewise.
(__array_type_info): Likewise.
(__function_type_info): Likewise.
(__enum_type_info): Likewise.
(__ptr_to_member_type_info): Likewise.
(__fundamental_type_info::~__fundamental_type_info): Define.
(__pointer_type_info::~__pointer_type_info): Likewise.
(__reference_type_info::~__reference_type_info): Likewise.
(__array_type_info::~__array_type_info): Likewise.
(__function_type_info::~__function_type_info): Likewise.
(__enum_type_info::~__enum_type_info): Likewise.
(__ptr_to_member_type_info::~__ptr_to_member_type_info): Likewise.
(__pointer_type_info::do_catch): Define new function.
(__ptr_to_member_type_info::do_catch): Define new function.
(__throw_type_match_rtti_2): Use new ABI interface, if enabled.
(__is_pointer): Likewise.
* exception.cc (__cplus_type_matcher): Deal with new-abi rtti.
2000-01-30 Mark Mitchell <mark@codesourcery.com>
* cp/class.c (build_vtable): Rename to build_primary_vtable.

View File

@ -244,7 +244,7 @@ extern int flag_rtti;
/* Nonzero if we use access type_info objects directly, and use the
cross-vendor layout for them. Zero if we use an accessor function
to get the type_info object address. */
#define new_abi_rtti_p() (0)
#define new_abi_rtti_p() (flag_new_abi)
/* Language-dependent contents of an identifier. */

View File

@ -184,7 +184,11 @@ __cplus_type_matcher (__eh_info *info_, void *match_info,
/* we don't worry about version info yet, there is only one version! */
void *match_type = ((void *(*)())match_info) ();
void *match_type = match_info;
#if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
match_type = ((void *(*)())match_type) ();
#endif
if (__throw_type_match_rtti_2 (match_type, info->type,
info->original_value, &info->value))

View File

@ -1,5 +1,10 @@
// RTTI support for -*- C++ -*-
// Copyright (C) 1994, 95-97, 1998 Free Software Foundation
// Copyright (C) 1994, 95-97, 1998, 2000 Free Software Foundation
// __GXX_ABI_VERSION distinguishes the ABI that is being used. Values <100
// indicate the `old' abi, which grew as C++ was defined. Values >=100
// indicate the `new' abi, which is a cross vendor C++ abi, documented at
// `http://reality.sgi.com/dehnert_engr/cxx/'.
#ifndef __TYPEINFO__
#define __TYPEINFO__
@ -12,33 +17,74 @@ extern "C++" {
namespace std {
#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
class __class_type_info;
#endif
class type_info {
public:
// Destructor. Being the first non-inline virtual function, this controls in
// which translation unit the vtable is emitted. The compiler makes use of
// that information to know where to emit the runtime-mandated type_info
// structures in the new-abi.
virtual ~type_info ();
private:
// assigning type_info is not supported. made private.
// Assigning type_info is not supported. made private.
type_info& operator= (const type_info&);
type_info (const type_info&);
protected:
explicit type_info (const char *n): _name (n) { }
const char *_name;
protected:
explicit type_info (const char *n): _name (n) { }
public:
// destructor
virtual ~type_info ();
// the public interface
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// In old abi, there can be multiple instances of a type_info object for one
// type. Uniqueness must use the _name value, not object address.
bool before (const type_info& arg) const;
const char* name () const
{ return _name; }
bool operator== (const type_info& arg) const;
bool operator!= (const type_info& arg) const;
};
bool operator!= (const type_info& arg) const
{ return !operator== (arg); }
inline bool type_info::
operator!= (const type_info& arg) const
{
return !operator== (arg);
}
#else
// In new abi we can rely on type_info's being unique,
// and therefore address comparisons are sufficient.
bool before (const type_info& arg) const
{ return this < &arg; }
const char* name () const
{ return _name; }
bool operator== (const type_info& arg) const
{ return &arg == this; }
bool operator!= (const type_info& arg) const
{ return !operator== (arg); }
#endif
// the internal interface
#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
public:
// return true if this is a pointer type of some kind
virtual bool is_pointer_p () const;
// return true if this is a function type
virtual bool is_function_p () const;
// Try and catch a thrown type. Store an adjusted pointer to the caught type
// in THR_OBJ. If THR_TYPE is not a pointer type, then THR_OBJ points to the
// thrown object. If THR_TYPE is a pointer type, then THR_OBJ is the pointer
// itself. OUTER indicates the number of outer pointers, and whether they
// were const qualified.
virtual bool do_catch (const type_info *thr_type, void **thr_obj,
unsigned outer) const;
// internally used during catch matching
virtual bool do_upcast (const __class_type_info *target, void **obj_ptr) const;
#endif
};
class bad_cast : public exception {
public:

View File

@ -67,6 +67,9 @@ std::type_info::
~type_info ()
{ }
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// original (old) abi
// We can't rely on common symbols being shared between shared objects.
bool std::type_info::
operator== (const std::type_info& arg) const
@ -539,3 +542,602 @@ do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *s
return not_contained;
}
#else
// new abi
namespace std {
// return true if this is a type_info for a pointer type
bool type_info::
is_pointer_p () const
{
return false;
}
// return true if this is a type_info for a function type
bool type_info::
is_function_p () const
{
return false;
}
// try and catch a thrown object.
bool type_info::
do_catch (const type_info *thr_type, void **, unsigned) const
{
return *this == *thr_type;
}
// upcast from this type to the target. __class_type_info will override
bool type_info::
do_upcast (const __class_type_info *, void **) const
{
return false;
}
};
namespace {
using namespace std;
// initial part of a vtable, this structure is used with offsetof, so we don't
// have to keep alignments consistent manually.
struct vtable_prefix {
ptrdiff_t whole_object; // offset to most derived object
const __class_type_info *whole_type; // pointer to most derived type_info
const void *origin; // what a class's vptr points to
};
template <typename T>
inline const T *
adjust_pointer (const void *base, ptrdiff_t offset)
{
return reinterpret_cast <const T *>
(reinterpret_cast <const char *> (base) + offset);
}
// some predicate functions for __class_type_info::sub_kind
inline bool contained_p (__class_type_info::sub_kind access_path)
{
return access_path >= __class_type_info::contained_mask;
}
inline bool public_p (__class_type_info::sub_kind access_path)
{
return access_path & __class_type_info::contained_public_mask;
}
inline bool virtual_p (__class_type_info::sub_kind access_path)
{
return (access_path & __class_type_info::contained_virtual_mask);
}
inline bool contained_public_p (__class_type_info::sub_kind access_path)
{
return (access_path & __class_type_info::contained_public) == __class_type_info::contained_public;
}
inline bool contained_nonpublic_p (__class_type_info::sub_kind access_path)
{
return (access_path & __class_type_info::contained_public) == __class_type_info::contained_mask;
}
inline bool contained_nonvirtual_p (__class_type_info::sub_kind access_path)
{
return (access_path & (__class_type_info::contained_mask | __class_type_info::contained_virtual_mask))
== __class_type_info::contained_mask;
}
static const __class_type_info *const nonvirtual_base_type =
static_cast <const __class_type_info *> (0) + 1;
}; // namespace
namespace std {
__class_type_info::
~__class_type_info ()
{}
__si_class_type_info::
~__si_class_type_info ()
{}
__vmi_class_type_info::
~__vmi_class_type_info ()
{}
bool __class_type_info::
do_catch (const type_info *thr_type, void **thr_obj,
unsigned outer) const
{
if (*this == *thr_type)
return true;
if (outer >= 4)
// Neither `A' nor `A *'.
return false;
return thr_type->do_upcast (this, thr_obj);
}
bool __class_type_info::
do_upcast (const __class_type_info *dst_type, void **obj_ptr) const
{
upcast_result result (details);
if (do_upcast (contained_public, dst_type, *obj_ptr, result))
return false;
*obj_ptr = const_cast <void *> (result.dst_ptr);
return contained_public_p (result.whole2dst);
}
inline __class_type_info::sub_kind __class_type_info::
find_public_src (ptrdiff_t src2dst,
const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr) const
{
if (src2dst >= 0)
return adjust_pointer <void> (obj_ptr, src2dst) == src_ptr
? contained_public : not_contained;
if (src2dst == -2)
return not_contained;
return do_find_public_src (src2dst, obj_ptr, src_type, src_ptr);
}
__class_type_info::sub_kind __class_type_info::
do_find_public_src (ptrdiff_t,
const void *obj_ptr,
const __class_type_info *,
const void *src_ptr) const
{
if (src_ptr == obj_ptr)
// Must be our type, as the pointers match.
return contained_public;
return not_contained;
}
__class_type_info::sub_kind __si_class_type_info::
do_find_public_src (ptrdiff_t src2dst,
const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr) const
{
if (src_ptr == obj_ptr && *this == *src_type)
return contained_public;
return base->do_find_public_src (src2dst, obj_ptr, src_type, src_ptr);
}
__class_type_info::sub_kind __vmi_class_type_info::
do_find_public_src (ptrdiff_t src2dst,
const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr) const
{
if (obj_ptr == src_ptr && *this == *src_type)
return contained_public;
for (size_t i = n_bases; i--;)
{
if (!base_list[i].is_public_p ())
continue; // Not public, can't be here.
const void *base = obj_ptr;
ptrdiff_t offset = base_list[i].offset;
if (base_list[i].is_virtual_p ())
{
if (src2dst == -3)
continue; // Not a virtual base, so can't be here.
const ptrdiff_t *vtable = *static_cast <const ptrdiff_t *const *> (base);
offset = vtable[offset];
}
base = adjust_pointer <void> (base, offset);
sub_kind base_kind = base_list[i].type->do_find_public_src
(src2dst, base, src_type, src_ptr);
if (contained_p (base_kind))
{
if (base_list[i].is_virtual_p ())
base_kind = sub_kind (base_kind | contained_virtual_mask);
return base_kind;
}
}
return not_contained;
}
bool __class_type_info::
do_dyncast (ptrdiff_t,
sub_kind access_path,
const __class_type_info *dst_type,
const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr,
dyncast_result &__restrict result) const
{
if (obj_ptr == src_ptr && *this == *src_type)
{
// The src object we started from. Indicate how we are accessible from
// the most derived object.
result.whole2src = access_path;
return false;
}
if (*this == *dst_type)
{
result.dst_ptr = obj_ptr;
result.whole2dst = access_path;
result.dst2src = not_contained;
return false;
}
return false;
}
bool __si_class_type_info::
do_dyncast (ptrdiff_t src2dst,
sub_kind access_path,
const __class_type_info *dst_type,
const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr,
dyncast_result &__restrict result) const
{
if (*this == *dst_type)
{
result.dst_ptr = obj_ptr;
result.whole2dst = access_path;
if (src2dst >= 0)
result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr
? contained_public : not_contained;
else if (src2dst == -2)
result.dst2src = not_contained;
return false;
}
if (obj_ptr == src_ptr && *this == *src_type)
{
// The src object we started from. Indicate how we are accessible from
// the most derived object.
result.whole2src = access_path;
return false;
}
return base->do_dyncast (src2dst, access_path, dst_type, obj_ptr,
src_type, src_ptr, result);
}
// This is a big hairy function. Although the run-time behaviour of
// dynamic_cast is simple to describe, it gives rise to some non-obvious
// behaviour. We also desire to determine as early as possible any definite
// answer we can get. Because it is unknown what the run-time ratio of
// succeeding to failing dynamic casts is, we do not know in which direction
// to bias any optimizations. To that end we make no particular effort towards
// early fail answers or early success answers. Instead we try to minimize
// work by filling in things lazily (when we know we need the information),
// and opportunisticly take early success or failure results.
bool __vmi_class_type_info::
do_dyncast (ptrdiff_t src2dst,
sub_kind access_path,
const __class_type_info *dst_type,
const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr,
dyncast_result &__restrict result) const
{
if (obj_ptr == src_ptr && *this == *src_type)
{
// The src object we started from. Indicate how we are accessible from
// the most derived object.
result.whole2src = access_path;
return false;
}
if (*this == *dst_type)
{
result.dst_ptr = obj_ptr;
result.whole2dst = access_path;
if (src2dst >= 0)
result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr
? contained_public : not_contained;
else if (src2dst == -2)
result.dst2src = not_contained;
return false;
}
bool result_ambig = false;
for (size_t i = n_bases; i--;)
{
dyncast_result result2;
void const *base = obj_ptr;
sub_kind base_access = access_path;
ptrdiff_t offset = base_list[i].offset;
if (base_list[i].is_virtual_p ())
{
base_access = sub_kind (base_access | contained_virtual_mask);
const ptrdiff_t *vtable = *static_cast <const ptrdiff_t *const *> (base);
offset = vtable[offset];
}
base = adjust_pointer <void> (base, offset);
if (!base_list[i].is_public_p ())
base_access = sub_kind (base_access & ~contained_public_mask);
bool result2_ambig
= base_list[i].type->do_dyncast (src2dst, base_access,
dst_type, base,
src_type, src_ptr, result2);
result.whole2src = sub_kind (result.whole2src | result2.whole2src);
if (result2.dst2src == contained_public
|| result2.dst2src == contained_ambig)
{
result.dst_ptr = result2.dst_ptr;
result.whole2dst = result2.whole2dst;
result.dst2src = result2.dst2src;
// Found a downcast which can't be bettered or an ambiguous downcast
// which can't be disambiguated
return result2_ambig;
}
if (!result_ambig && !result.dst_ptr)
{
// Not found anything yet.
result.dst_ptr = result2.dst_ptr;
result.whole2dst = result2.whole2dst;
result_ambig = result2_ambig;
}
else if (result.dst_ptr && result.dst_ptr == result2.dst_ptr)
{
// Found at same address, must be via virtual. Pick the most
// accessible path.
result.whole2dst =
sub_kind (result.whole2dst | result2.whole2dst);
}
else if ((result.dst_ptr && result2.dst_ptr)
|| (result_ambig && result2.dst_ptr)
|| (result2_ambig && result.dst_ptr))
{
// Found two different DST_TYPE bases, or a valid one and a set of
// ambiguous ones, must disambiguate. See whether SRC_PTR is
// contained publicly within one of the non-ambiguous choices. If it
// is in only one, then that's the choice. If it is in both, then
// we're ambiguous and fail. If it is in neither, we're ambiguous,
// but don't yet fail as we might later find a third base which does
// contain SRC_PTR.
sub_kind new_sub_kind = result2.dst2src;
sub_kind old_sub_kind = result.dst2src;
if (contained_nonvirtual_p (result.whole2src))
{
// We already found SRC_PTR as a non-virtual base of most
// derived. Therefore if it is in either choice, it can only be
// in one of them, and we will already know.
if (old_sub_kind == unknown)
old_sub_kind = not_contained;
if (new_sub_kind == unknown)
new_sub_kind = not_contained;
}
else
{
if (old_sub_kind >= not_contained)
;// already calculated
else if (contained_nonvirtual_p (new_sub_kind))
// Already found non-virtually inside the other choice,
// cannot be in this.
old_sub_kind = not_contained;
else
old_sub_kind = dst_type->find_public_src
(src2dst, result.dst_ptr, src_type, src_ptr);
if (new_sub_kind >= not_contained)
;// already calculated
else if (contained_nonvirtual_p (old_sub_kind))
// Already found non-virtually inside the other choice,
// cannot be in this.
new_sub_kind = not_contained;
else
new_sub_kind = dst_type->find_public_src
(src2dst, result2.dst_ptr, src_type, src_ptr);
}
// Neither sub_kind can be contained_ambig -- we bail out early
// when we find those.
if (contained_p (sub_kind (new_sub_kind ^ old_sub_kind)))
{
// Only on one choice, not ambiguous.
if (contained_p (new_sub_kind))
{
// Only in new.
result.dst_ptr = result2.dst_ptr;
result.whole2dst = result2.whole2dst;
result_ambig = false;
old_sub_kind = new_sub_kind;
}
result.dst2src = old_sub_kind;
if (public_p (result.dst2src))
return false; // Can't be an ambiguating downcast for later discovery.
if (!virtual_p (result.dst2src))
return false; // Found non-virtually can't be bettered
}
else if (contained_p (sub_kind (new_sub_kind & old_sub_kind)))
{
// In both.
result.dst_ptr = NULL;
result.dst2src = contained_ambig;
return true; // Fail.
}
else
{
// In neither publicly, ambiguous for the moment, but keep
// looking. It is possible that it was private in one or
// both and therefore we should fail, but that's just tough.
result.dst_ptr = NULL;
result.dst2src = not_contained;
result_ambig = true;
}
}
if (result.whole2src == contained_private)
// We found SRC_PTR as a private non-virtual base, therefore all
// cross casts will fail. We have already found a down cast, if
// there is one.
return result_ambig;
}
return result_ambig;
}
bool __class_type_info::
do_upcast (sub_kind access_path,
const __class_type_info *dst, const void *obj,
upcast_result &__restrict result) const
{
if (*this == *dst)
{
result.dst_ptr = obj;
result.base_type = nonvirtual_base_type;
result.whole2dst = access_path;
return contained_nonpublic_p (access_path);
}
return false;
}
bool __si_class_type_info::
do_upcast (sub_kind access_path,
const __class_type_info *dst, const void *obj_ptr,
upcast_result &__restrict result) const
{
if (*this == *dst)
{
result.dst_ptr = obj_ptr;
result.base_type = nonvirtual_base_type;
result.whole2dst = access_path;
return contained_nonpublic_p (access_path);
}
return base->do_upcast (access_path, dst, obj_ptr, result);
}
bool __vmi_class_type_info::
do_upcast (sub_kind access_path,
const __class_type_info *dst, const void *obj_ptr,
upcast_result &__restrict result) const
{
if (*this == *dst)
{
result.dst_ptr = obj_ptr;
result.base_type = nonvirtual_base_type;
result.whole2dst = access_path;
return contained_nonpublic_p (access_path);
}
for (size_t i = n_bases; i--;)
{
upcast_result result2 (result.src_details);
const void *base = obj_ptr;
sub_kind sub_access = access_path;
ptrdiff_t offset = base_list[i].offset;
if (!base_list[i].is_public_p ())
{
if (!(result.src_details & multiple_base_mask))
// original cannot have an ambiguous base
continue;
sub_access = sub_kind (sub_access & ~contained_public_mask);
}
if (base_list[i].is_virtual_p ())
{
sub_access = sub_kind (sub_access | contained_virtual_mask);
if (base)
{
const ptrdiff_t *vtable = *static_cast <const ptrdiff_t *const *> (base);
offset = vtable[offset];
}
}
if (base)
base = adjust_pointer <void> (base, offset);
if (base_list[i].type->do_upcast (sub_access, dst, base, result2))
return true; // must fail
if (result2.base_type)
{
if (result2.base_type == nonvirtual_base_type
&& base_list[i].is_virtual_p ())
result2.base_type = base_list[i].type;
if (!result.base_type)
{
result = result2;
if (!(details & multiple_base_mask))
// cannot have an ambiguous other base
return false;
}
else if (result.dst_ptr != result2.dst_ptr)
{
// Found an ambiguity.
result.dst_ptr = NULL;
result.whole2dst = contained_ambig;
return true;
}
else if (result.dst_ptr)
{
// Ok, found real object via a virtual path.
result.whole2dst
= sub_kind (result.whole2dst | result2.whole2dst);
}
else
{
// Dealing with a null pointer, need to check vbase
// containing each of the two choices.
if (result2.base_type == nonvirtual_base_type
|| result.base_type == nonvirtual_base_type
|| !(*result2.base_type == *result.base_type))
{
// Already ambiguous, not virtual or via different virtuals.
// Cannot match.
result.whole2dst = contained_ambig;
return true;
}
}
}
}
return false;
}
// this is the external interface to the dynamic cast machinery
void *
__dynamic_cast (const void *src_ptr, // object started from
const __class_type_info *src_type, // type of the starting object
const __class_type_info *dst_type, // desired target type
ptrdiff_t src2dst) // how src and dst are related
{
const void *vtable = *static_cast <const void *const *> (src_ptr);
const vtable_prefix *prefix =
adjust_pointer <vtable_prefix> (vtable, 0);
// FIXME: the above offset should be -offsetof (vtable_prefix, origin));
// but we don't currently layout vtables correctly.
const void *whole_ptr =
adjust_pointer <void> (src_ptr, prefix->whole_object);
const __class_type_info *whole_type = prefix->whole_type;
__class_type_info::dyncast_result result;
whole_type->do_dyncast (src2dst, __class_type_info::contained_public,
dst_type, whole_ptr, src_type, src_ptr, result);
if (!result.dst_ptr)
return NULL;
if (contained_public_p (result.dst2src))
return const_cast <void *> (result.dst_ptr);
if (contained_public_p (__class_type_info::sub_kind (result.whole2src & result.whole2dst)))
// Found a valid cross cast
return const_cast <void *> (result.dst_ptr);
if (contained_nonvirtual_p (result.whole2src))
// Found an invalid cross cast, which cannot also be a down cast
return NULL;
if (!(whole_type->details & __class_type_info::private_base_mask))
// whole type has no private bases
return const_cast <void *> (result.dst_ptr);
if (result.dst2src == __class_type_info::unknown)
result.dst2src = dst_type->find_public_src (src2dst, result.dst_ptr,
src_type, src_ptr);
if (contained_public_p (result.dst2src))
// Found a valid down cast
return const_cast <void *> (result.dst_ptr);
// Must be an invalid down cast, or the cross cast wasn't bettered
return NULL;
}
}; // namespace std
#endif

View File

@ -5,6 +5,9 @@
// Class declarations shared between the typeinfo implementation files.
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// original (old) abi
// type_info for a class with no base classes (or an enum).
struct __user_type_info : public std::type_info {
@ -167,11 +170,7 @@ public:
// type_info for a general class.
#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
typedef int USItype __attribute__ ((mode (SI)));
#else
typedef unsigned int USItype __attribute__ ((mode (SI)));
#endif
struct __class_type_info : public __user_type_info {
enum access { PUBLIC = 1, PROTECTED = 2, PRIVATE = 3 };
@ -200,3 +199,230 @@ struct __class_type_info : public __user_type_info {
virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
void *objptr, void *subptr) const;
};
#else
// new abi
#include "stddef.h"
typedef int USItype __attribute__ ((mode (SI)));
namespace std {
class __class_type_info;
// helper class for __vmi_class_type
struct __base_class_info {
const __class_type_info *type; // base class type
ptrdiff_t offset; // offset to the sub object
int vmi_flags; // about the base
// implementation specific parts
enum vmi_masks {
virtual_mask = 0x1,
public_mask = 0x2,
hwm_bit = 2
};
public:
bool is_virtual_p () const
{ return vmi_flags & virtual_mask; }
bool is_public_p () const
{ return vmi_flags & public_mask; }
};
// type information for a class
class __class_type_info : public type_info {
protected:
virtual ~__class_type_info ();
public:
int details; // details about the class heirarchy
// implementation specific parts
enum detail_masks {
multiple_base_mask = 0x1, // multiple inheritance of the same base type
polymorphic_mask = 0x2, // is a polymorphic type
virtual_base_mask = 0x4, // has virtual bases (direct or indirect)
private_base_mask = 0x8 // has private bases (direct or indirect)
};
public:
// sub_kind tells us about how a base object is contained within a derived
// object. We often do this lazily, hence the UNKNOWN value. At other times
// we may use NOT_CONTAINED to mean not publicly contained.
enum sub_kind
{
unknown = 0, // we have no idea
not_contained, // not contained within us (in some
// circumstances this might mean not contained
// publicly)
contained_ambig, // contained ambiguously
contained_virtual_mask = __base_class_info::virtual_mask, // via a virtual path
contained_public_mask = __base_class_info::public_mask, // via a public path
contained_mask = 1 << __base_class_info::hwm_bit, // contained within us
contained_private = contained_mask,
contained_public = contained_mask | contained_public_mask
};
public:
struct upcast_result
{
const void *dst_ptr; // pointer to caught object
sub_kind whole2dst; // path from most derived object to target
int src_details; // hints about the source type
const __class_type_info *base_type; // where we found the target,
// if in vbase the __class_type_info of vbase
// if a non-virtual base then 1
// else NULL
public:
upcast_result (int d)
:dst_ptr (NULL), whole2dst (unknown), src_details (d), base_type (NULL)
{}
};
public:
// dyncast_result is used to hold information during traversal of a class
// heirarchy when dynamic casting.
struct dyncast_result
{
const void *dst_ptr; // pointer to target object or NULL
sub_kind whole2dst; // path from most derived object to target
sub_kind whole2src; // path from most derived object to sub object
sub_kind dst2src; // path from target to sub object
public:
dyncast_result ()
:dst_ptr (NULL), whole2dst (unknown),
whole2src (unknown), dst2src (unknown)
{}
};
public:
explicit __class_type_info (const char *n,
int details_)
: type_info (n), details (details_)
{ }
protected:
virtual bool do_upcast (const __class_type_info *dst_type, void **obj_ptr) const;
protected:
virtual bool do_catch (const type_info *thr_type, void **thr_obj,
unsigned outer) const;
public:
// Helper for upcast. See if DST is us, or one of our bases. ACCESS_PATH
// gives the access from the start object. Return TRUE if we know the upcast
// fails.
virtual bool do_upcast (sub_kind access_path,
const __class_type_info *dst, const void *obj,
upcast_result &__restrict result) const;
public:
// Indicate whether SRC_PTR of type SRC_TYPE is contained publicly within
// OBJ_PTR. OBJ_PTR points to a base object of our type, which is the
// destination type. SRC2DST indicates how SRC objects might be contained
// within this type. If SRC_PTR is one of our SRC_TYPE bases, indicate the
// virtuality. Returns not_contained for non containment or private
// containment.
inline sub_kind find_public_src (ptrdiff_t src2dst, const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr) const;
public:
// dynamic cast helper. ACCESS_PATH gives the access from the most derived
// object to this base. DST_TYPE indicates the desired type we want. OBJ_PTR
// points to a base of our type within the complete object. SRC_TYPE
// indicates the static type started from and SRC_PTR points to that base
// within the most derived object. Fill in RESULT with what we find. Return
// true if we have located an ambiguous match.
virtual bool do_dyncast (ptrdiff_t src2dst, sub_kind access_path,
const __class_type_info *dst_type, const void *obj_ptr,
const __class_type_info *src_type, const void *src_ptr,
dyncast_result &result) const;
public:
// Helper for find_public_subobj. SRC2DST indicates how SRC_TYPE bases are
// inherited by the type started from -- which is not necessarily the
// current type. The current type will be a base of the destination type.
// OBJ_PTR points to the current base.
virtual sub_kind do_find_public_src (ptrdiff_t src2dst, const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr) const;
};
// type information for a class with a single non-virtual base
class __si_class_type_info : public __class_type_info {
protected:
virtual ~__si_class_type_info ();
protected:
const __class_type_info *base; // base type
public:
explicit __si_class_type_info (const char *n,
int details_,
const __class_type_info *base_)
: __class_type_info (n, details_), base (base_)
{ }
// implementation specific parts
protected:
virtual bool do_dyncast (ptrdiff_t src2dst, sub_kind access_path,
const __class_type_info *dst_type, const void *obj_ptr,
const __class_type_info *src_type, const void *src_ptr,
dyncast_result &result) const;
virtual sub_kind do_find_public_src (ptrdiff_t src2dst, const void *obj_ptr,
const __class_type_info *src_type,
const void *sub_ptr) const;
virtual bool do_upcast (sub_kind access_path,
const __class_type_info *dst, const void *obj,
upcast_result &__restrict result) const;
};
// type information for a class with multiple and/or virtual bases
class __vmi_class_type_info : public __class_type_info {
protected:
virtual ~__vmi_class_type_info ();
protected:
int n_bases; // number of direct bases
__base_class_info base_list[1]; // array of bases
// The array of bases uses the trailing array struct hack
// so this class is not constructable with a normal constructor. It is
// internally generated by the compiler.
public:
explicit __vmi_class_type_info (const char *n,
int details_)
: __class_type_info (n, details_), n_bases (0)
{ }
// implementation specific parts
protected:
virtual bool do_dyncast (ptrdiff_t src2dst, sub_kind access_path,
const __class_type_info *dst_type, const void *obj_ptr,
const __class_type_info *src_type, const void *src_ptr,
dyncast_result &result) const;
virtual sub_kind do_find_public_src (ptrdiff_t src2dst, const void *obj_ptr,
const __class_type_info *src_type,
const void *src_ptr) const;
virtual bool do_upcast (sub_kind access_path,
const __class_type_info *dst, const void *obj,
upcast_result &__restrict result) const;
};
// dynamic cast runtime
void *__dynamic_cast (const void *src_ptr, // object started from
const __class_type_info *src_type, // static type of object
const __class_type_info *dst_type, // desired target type
ptrdiff_t src2dst); // how src and dst are related
// src2dst has the following possible values
// >= 0: src_type is a unique public non-virtual base of dst_type
// dst_ptr + src2dst == src_ptr
// -1: unspecified relationship
// -2: src_type is not a public base of dst_type
// -3: src_type is a multiple public non-virtual base of dst_type
}; // namespace std
#endif

View File

@ -31,6 +31,7 @@
using std::type_info;
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
bool
type_info::before (const type_info &arg) const
{
@ -88,6 +89,248 @@ struct __array_type_info : public type_info {
__array_type_info (const char *n): type_info (n) {}
};
#else
namespace std {
// type information for int, float etc
class __fundamental_type_info : public type_info {
public:
virtual ~__fundamental_type_info ();
public:
explicit __fundamental_type_info (const char *n)
: type_info (n)
{ }
};
// type information for pointer to data or function, but not pointer to member
class __pointer_type_info : public type_info {
public:
virtual ~__pointer_type_info ();
// external parts
int quals; // qualification of the target object
const type_info *target; // type of object being pointed to
// internal parts
enum quals_masks {
const_mask = 0x1,
volatile_mask = 0x2
};
public:
explicit __pointer_type_info (const char *n,
int quals_,
const type_info *target_)
: type_info (n), quals (quals_), target (target_)
{ }
protected:
virtual bool is_pointer_p () const;
virtual bool do_catch (const type_info *thr_type, void **thr_obj,
unsigned outer) const;
};
// type information for reference to data
class __reference_type_info : public type_info {
public:
virtual ~__reference_type_info ();
int quals; // qualification of the target object
const type_info *target; // type of object being referenced
// internal parts
enum quals_masks {
const_mask = 0x1,
volatile_mask = 0x2
};
public:
explicit __reference_type_info (const char *n,
int quals_,
const type_info *target_)
: type_info (n), quals (quals_), target (target_)
{ }
};
// type information for array objects
class __array_type_info : public type_info {
public:
virtual ~__array_type_info ();
public:
explicit __array_type_info (const char *n)
: type_info (n)
{ }
};
// type information for functions (both member and non-member)
class __function_type_info : public type_info {
public:
virtual ~__function_type_info ();
public:
explicit __function_type_info (const char *n)
: type_info (n)
{ }
protected:
virtual bool is_function_p () const;
};
// type information for enumerations
class __enum_type_info : public type_info {
public:
virtual ~__enum_type_info ();
public:
explicit __enum_type_info (const char *n)
: type_info (n)
{ }
};
// type information for a pointer to member variable (not function)
class __ptr_to_member_type_info : public type_info {
public:
virtual ~__ptr_to_member_type_info ();
// external parts
const __class_type_info *klass; // class of the member
const type_info *type; // type of the member
int quals; // qualifications of the pointed to type
// internal parts
enum quals_masks {
const_mask = 0x1,
volatile_mask = 0x2
};
public:
explicit __ptr_to_member_type_info (const char *n,
const __class_type_info *klass_,
const type_info *type_,
int quals_)
: type_info (n), klass (klass_), type (type_), quals (quals_)
{ }
protected:
virtual bool do_catch (const type_info *thr_type, void **thr_obj,
unsigned outer) const;
};
}; // namespace std
#endif
#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
namespace std {
// This has special meaning to the compiler, and will cause it
// to emit the type_info structures for the fundamental types which are
// mandated to exist in the runtime.
__fundamental_type_info::
~__fundamental_type_info ()
{}
__pointer_type_info::
~__pointer_type_info ()
{}
__reference_type_info::
~__reference_type_info ()
{}
__array_type_info::
~__array_type_info ()
{}
__function_type_info::
~__function_type_info ()
{}
__enum_type_info::
~__enum_type_info ()
{}
__ptr_to_member_type_info::
~__ptr_to_member_type_info ()
{}
bool __pointer_type_info::
is_pointer_p () const
{
return true;
}
bool __function_type_info::
is_function_p () const
{
return true;
}
bool __pointer_type_info::
do_catch (const type_info *thr_type,
void **thr_obj,
unsigned outer) const
{
if (*this == *thr_type)
return true; // same type
if (typeid (*this) != typeid (*thr_type))
return false; // not both pointers
if (!(outer & 1))
// We're not the same and our outer pointers are not all const qualified
// Therefore there must at least be a qualification conversion involved
// But for that to be valid, our outer pointers must be const qualified.
return false;
const __pointer_type_info *thrown_type =
static_cast <const __pointer_type_info *> (thr_type);
if (thrown_type->quals & ~quals)
// We're less qualified.
return false;
if (!(quals & const_mask))
outer &= ~1;
if (outer < 2 && *target == typeid (void))
{
// conversion to void
return !thrown_type->is_function_p ();
}
return target->do_catch (thrown_type->target, thr_obj, outer + 2);
}
bool __ptr_to_member_type_info::
do_catch (const type_info *thr_type,
void **thr_obj,
unsigned outer) const
{
if (*this == *thr_type)
return true; // same type
if (typeid (*this) != typeid (*thr_type))
return false; // not both pointers to member
if (!(outer & 1))
// We're not the same and our outer pointers are not all const qualified
// Therefore there must at least be a qualification conversion involved.
// But for that to be valid, our outer pointers must be const qualified.
return false;
const __ptr_to_member_type_info *thrown_type =
static_cast <const __ptr_to_member_type_info *> (thr_type);
if (thrown_type->quals & ~quals)
// We're less qualified.
return false;
if (!(quals & const_mask))
outer &= ~1;
if (*klass != *thrown_type->klass)
return false; // not pointers to member of same class
return type->do_catch (thrown_type->type, thr_obj, outer + 2);
}
} // namespace std
#endif
// Entry points for the compiler.
/* Low level match routine used by compiler to match types of catch
@ -102,6 +345,8 @@ __throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r,
*valp = objptr;
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// old abi
if (catch_type == throw_type)
return 1;
@ -213,10 +458,15 @@ __throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r,
}
}
}
#else
// new abi
return catch_type.do_catch (&throw_type, valp, 1);
#endif
return 0;
}
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
/* Backward compatibility wrapper. */
extern "C" void*
@ -228,6 +478,7 @@ __throw_type_match_rtti (const void *catch_type_r, const void *throw_type_r,
return ret;
return NULL;
}
#endif
/* Called from __cp_pop_exception. Is P the type_info node for a pointer
of some kind? */
@ -236,11 +487,20 @@ bool
__is_pointer (void *p)
{
const type_info *t = reinterpret_cast <const type_info *>(p);
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// old abi
const __pointer_type_info *pt =
dynamic_cast <const __pointer_type_info *> (t);
return pt != 0;
#else
// new abi
return t->is_pointer_p ();
#endif
}
#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
// old abi
extern "C" void
__rtti_ptr (void *addr, const char *n, const type_info *ti)
{ new (addr) __pointer_type_info (n, *ti); }
@ -302,3 +562,10 @@ BUILTIN (v); BUILTIN (x); BUILTIN (l); BUILTIN (i); BUILTIN (s); BUILTIN (b);
BUILTIN (c); BUILTIN (w); BUILTIN (r); BUILTIN (d); BUILTIN (f);
BUILTIN (Ui); BUILTIN (Ul); BUILTIN (Ux); BUILTIN (Us); BUILTIN (Uc);
BUILTIN (Sc);
#else
// new abi
// we need to define the fundamental type type_info's, but the name mangling is
// not yet defined.
#endif