Alternative rtti proposals

Nathan Sidwell nathan at codesourcery.com
Thu Apr 6 11:44:03 UTC 2000


Hi,
The current RTTI proposal loses the property that all type_info objects
can be compared for equality and orderability by address comparison.
Instead, type_info::operator== must involve a virtual function call
or unconditionaly strcmp. (An alternative of testing the typeid of the
polymorphic type_info objects results in infinite recursion!)

Here are two proposals which reinstate the address equality property.
The first is rather different to the current scheme, but when I was
done documenting it, I realised there was a minor modification to the
current scheme, which partially reinstates the address equality. I
present both for consideration. Feel free to shot them down ...

Proposal A

1) The typeid operator produces a std::type_info object for all types.
No subclassing of std::type_info is done. The object has comdat linkage,
and hence after linking and loading, only one object of that name is
active. For typeid(X) it does not matter whether X is incomplete, or
direct or indirect pointer to incomplete. The functionality required
of typeid is to produce objects which can test for type equality and
(implementation defined) type orderability. No information about the
internal structure of the type is required.

2) Dynamic_cast and catch matching require more information. Primarily
the heirarchy of a class type, and the target of pointer types. To do
this, a separate class heirarchy is used. These objects are also emitted
with comdat linkage, and with a different name to the std::type_info
objects produced by typeid. (It is not _necessary_ for these to have
comdat linkage, but that will reduce overall program size.)

The base class of these is,

class abi::__type_info
{
  std::type_info const *type; // pointer to typeid(foo) object.
  virtual ~__type_info ();
  ... other implementation defined member functions
};

This contains a pointer to the type_info object produced by the typeid
operator, for whatever type this is describing. That will be a unique
object.

There are a number of necessary derivations of this type, which can
be taken largely unaltered from the current proposal. 

It is necessary to distinguish function types, so that catch matching
can distinguish a data pointer object from a function pointer object.
Other types (fundamental, enum, array) need not be distinguished, and
can be represented by an abi::__type_info object. (Or we could keep the
current proposal of having separate derivations for these.)

class abi::__function_type_info
  : public abi::__type_info
{
  virtual ~__function_type_info ();
  ... other implementation defined member functions
};

Pointers are as they currently are, other than the base
class change. We still need the incomplete target flag.

class abi::__pointer_type_info
  : public abi::__type_info 
{
  abi::__type_info const *target;   // target type of the pointer
  unsigned flags;  		    // flags, as currently specified
  virtual ~__pointer_type_info ();
  ... other implementation defined member functions
};

Pointers to member could be a sibling class of non member pointers,
however, they do share common functionality, and IMO it makes sense
to derive from __pointer_type_info.

class abi::__pointer_to_member_type_info
  : public abi::__pointer_type_info
{
  abi::__class_type_info const *klass;  // class of the member
  virtual ~__pointer_to_member_type_info ();
  ... other implementation defined member functions
};

The __class_type_info, __si_class_type_info and __vmi_class_type_info
are unchanged, other than the change to __class_type_info's base.

class abi::__class_type_info
  : public abi::__type_info
{
  ... as currently defined
}

The vtable slot -1, (which currently holds a pointer to the
std::type_info object for a class), points to the
abi::__class_type_info object. To implement typeid(X), where X is
polymorphic, involves an additional indirection through the
abi::__type_info base to return the `type' member.

dynamic_cast uses the abi::__class_type_info object pointed to in the
vtable. throwing and catch matching use the abi::__type_info object
for the type being thrown or caught.

As with the current proposal, an incomplete type is represented by an
abi::__class_type_info object. Note that its abi::__type_info base
will point to the unique std::type_info object for that type, regardless
of whether a DSO completes the type. This incomplete type is prevented
from preempting the complete type information.

Also direct or indirect pointers to incomplete have their incomplete flag
set, and are also prevented from preempting the equivalent pointer to
complete object.

During catch matching, comparison of pointers can compare the
abi::__pointer_type_info addresses, unless either has the incomplete flag
set, in which case the std::type_info objects pointed to must be compared.
(The std::type_info objects could be compared even when the incomplete
flags are clear.)

There are two or three naming schemes with this proposal.
1) The naming of the std::type_info object produced by typeid.
2) The naming of the abi::__type_info object required for dynamic cast and
catch matching
3) Optionally, the naming of the incomplete abi::__class_type_info and
direct or indirect pointers to it. If that mangling is specified, we can
emit those as comdat objects too, rather than forcing them to be statics.

Advantages of this proposal are,
*) Address equivalence of std::type_info objects is maintained in all
cases.
*) Generating the std::type_info of a pointer type does not force the
emission of the std::type_info objects for the pointer chain.
*) Generating the std::type_info of a type is always 16 bytes, additional
information is only produced when necessary.
*) When address equivalence of abi::__type_info objects is not possible,
the type's std::type_info object is available for that purpose. There
is no requirement to compare the NTBS's of the types.
*) We do not have to expose any implementation hooks in the
<typeinfo> header file.

The cost of this proposal is
*) Producing the std::type_info for a polymorphic type involves an
additional indirection.
*) The std::type_info and abi::__type_info derivative for a particular
type occupies an additional 16bytes (The size of std::type_info).


Proposal B

The first proposal is essentially using the std::type_info objects as
unique objects, via which incomplete types can be compared. We already
have such a unique object candidate -- the NTBS name member of
std::type_info. Currently we've not said anything about that. If, however,
we give that NTBS comdat linkage, a unique name, and prevent it being
commonized with other strings, we have a proxy. These features can be
obtained by treating it as a `const char []' rather than a string constant.
type_info equality and orderability can now use the address of this array,
rather than the type_info objects themselves. We can do this in all cases,
even though it is only necessary for the pointer to incomplete case, as
that avoids a virtual function call. Here is an implementaion of
type_info::operator==

bool type_info::operator== (type_info const &other) throw ()
{
  return name == other.name;
}

We need to specify the naming scheme for the NTBS.

The advantages of this are
*) Minimal change from the current scheme.
*) type_info orderability is a pointer comparison

The costs over proposal A are
*) type_info orderability involves indirecting on the type_infos.

nathan

-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan at codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan at acm.org




More information about the cxx-abi-dev mailing list