RTTI draft proposal

Daveed Vandevoorde daveed at edg.com
Fri Aug 20 00:05:27 UTC 1999


Jason Merrill wrote:
> 
> >>>>> Daveed Vandevoorde <daveed at edg.com> writes:
[...]
>  > Assuming that after linking and loading only one type_info structure is
>  > active for any particular type symbol
> 
> We've found that we can't always rely on that, when people build shared
> libraries with -B symbolic.  So we fall back on strcmp of the mangled name.

Is there a -B symbolic option on IA-64? (Is it a base ABI issue, or can
every vendor do what they please?) If so, that is quite unfortunate I 
suppose. (Unless we cab "escape" from the -B somehow.)

We then have the option that you suggest, or we can follow Sun's idea
of using a strong hash (which is not 100% tight, but "close enough").

>  > std::extended_type_info derives from std::type_info but adds no fields
>  > to the latter; it is introduced solely to follow the suggestion of the
>  > C++ standard.
> 
> That seems wrong; the idea of extended_type_info was supposed to extend the
> type_info API so that the user could access more information about
> classes.  Stuff like member lists and whatnot.  If we aren't doing anything
> like that, we shouldn't introduce extended_type_info.

This was suggested by the J16 core discussion list some time ago.
I don't see it wrong either way; I cannot see it hurting either.

>  > 6. std::__qualifier_type_info is similar to std::__pointer_type_info but
>  > describes top level qualifiers as in "int const" and "char *const".
> 
> Where would this be used?  I included it in the G++ implementation, but
> have since come to the conclusion that it was a mistake.

How do you check qualification conversions when catching exceptions?

>  > 7. std::__class_type_info introduces a variable length structure.
>  > The variable part that follows consists of a sequence of base class
>  > descriptions having the following structure:
>  >     struct std::__base_class_info {
>  >        std::type_info *type; /* Null if unused. */
>  >        std::ptrdiff_t offset;
>  >        std::__base_class_index next; /* Hash table link. */
>  >        int is_direct: 1;
>  >        int is_floating: 1; /* I.e., virtual or base of virtual subobject. */
>  >        int is_virtual: 1; /* Implies is_floating. */
>  >        int is_shared: 1; /* Implies is_floating and the virtual subobject
>  >                             appears on multiple derivation paths. */
>  >        int is_accessible: 1;
>  >        int is_ambiguous: 1;
>  >     };
> 
> So you're proposing that we store the info about all bases in the type_info
> for a class, not just the info for direct bases? 

Yes. (The HP and EDG implementation chose that avenue.  I'm not sure what
Sun does from reading Michael's mail, but my inference is that they do the
same.)

> That would certainly make
> upcasts (i.e. EH matching and cross dynamic_casts) faster, at the price of
> larger RTTI info.

Indeed.

>  >  The fixed length introduction adds the following fields to std::type_info:
>  >   . a word with flags describing details about the class such as whether
>  >     it is a class/struct/union and whether it is polymorphic.
> 
> Why?

Just my inclination of the moment.  I probably thought at some point that the
"polymorphic" bit might be useful in the run-time support library, but that
is not the case.

>  >   . a hashvalue that can be used for quick lookups in a variable length
>  >     structure describing base classes.
> 
> How is this calculated/used?

I haven't made up my mind about its calculation.  I don't recall the HP's
strategy, but it does have a slight historical burden as I recall.  You
could hash the mangled name in some way.

For its use: whenever you try to find a base of type "T" in a complete
type "C", you just search the list rooted at the entry whose subscript
is INFO(T).hashvalue%INFO(T).base_table_size.  That speeds things up a
bit.

>  >   . the number of base class descriptions that follow it (a power of two).
> 
> Why a power of two?

To make the modulo operation above faster.

>  > The dynamic_cast algorithm
>  > --------------------------
>  >   . If, in the most derived object pointed (referred) to by v, v points
>  >     (refers) to a public base class sub-object of a T object [note: this can
>  >     be checked at compile time], and if only one object of type T is derived
>  >     from the sub-object pointed (referred) to by v, the result is a pointer
>  >     (an lvalue referring) to that T object.
> 
> More precisely, we can check at compile time whether T has a unique base
> subobject of type typeof(*v).  We don't know anything about the true
> referent of v.

Darn.

>  >   . Otherwise, if v points (refers) to a public base class sub-object of the
>  >     most derived object, and the type of the most derived object has an
>  >     unambiguous public base class of type T, the result is a pointer (an
>  >     lvalue referring) to the T sub-object of the most derived object.
>  >   . Otherwise, the run-time check fails.
> 
>  > The first check corresponds to a "base-to-derived cast" and the second to a
>  > "cross cast".  These tests are implemented by std::__dynamic_cast.
> 
>  >    void* std::__dynamic_cast(void *sub, std::__class_type_info *src,
>  >                                         std::__class_type_info *dst,
>  >                                         std::ptrdiff_t src2dst_offset) {
>  >      // Pick up vtable pointer from given object:
>  >      void *vptr = *(void**)sub;
>  >      if (src2dst_offset>=0 && NO_VBASE(sub, vptr)) {
>  >        // If the type of "v" was not an accessible nonvirtual base type of
>  >        // "T", src2dst_offset should have been set to -1 if it was an
>  >        // accessible but floating base of "T" and to -2 if it was not at all
>  >        // an accessible base of "T".
>  >        // In addition, the vtable should contain an entry to indicate that
>  >        // the complete object has no virtual bases (e.g., a count of the
>  >        // vbase locator entries).
>  >        return (char*)sub+src2dst_offset;
> 
> What about the case where v doesn't point to a base subobject of T at all,
> even though the compile time check says it could?  Consider
> 
>   struct V;
>   struct T: public V;
>   struct A: public V;
>   struct B: public A, public T;
> 
>   B b;
>   V* v = (V*)(A*)&b;
>   dynamic_cast<T*>(v);
> 
> The static check says this could be a downcast, but it's really a cross-cast.

Ah yes, you mentioned it last time but I hadn't grasped it at the time.
So the algorithm needs to be modified.

> Who passes in src2dst_offset?

The compiler.

> In a typical downcast, the offset from src to dst will be negative.

Is the architecture biased? I.e., do we care about the sign convention for this value?

>  >      } else {
>  >        // Slower case
>  >        void *result = 0;
>  >        if (src2dst_offset==-1) {
>  >          // Possibly a "floating" base-to-derived cast:
>  >          result = floating_base2derived(sub, src, dst);
>  >        }
>  >        if (result==0) {
>  >          // The base-to-derived case did not succeed, so we should attempt
>  >          // the cross-cast (which is really a derived-to-base cast from the
>  >          // complete object):
>  >          result = derived2base(complete, dst);
>  >        }
>  >      }
>  >      return result;
>  >    }
> 
> Where are the defns of floating_base2derived and derived2base?

Handwaving <g>.

>  > The exception handler matching algorithm
>  > ----------------------------------------
> 
>  >    bool __eh_match(std::type_info *thrown_type,
>  >                    std::type_info *handled_type) {
>  >      if (thrown_type == handled_type) {
>  >        return true;
>  >      } else if (IS_REFTYPE(handled_type)) {
>  >        std::type_info *caught_type = REMOVE_REFTYPE(handled_type);
>  >        if (IS_CVQUAL(caught_type)) {
>  >          caught_type = REMOVE_CVQUAL(caught_type);
>  >        }
>  >        return thrown_type==caught_type;
> 
> We do derived-to-base conversions for non-pointers, too.

YAB (yet another bug).

[...]
> FWIW, g++ turns all dynamic_casts into upcasts, using the original pointer
> for disambiguation.  I'm not yet convinced that there's a good way to
> accelerate downcasts.

I'm afraid you may be right.  Except perhaps that checking if a base
of type T is at the offset guessed by the base-to-derived cast may
be more efficient than a full-fledged complete-to-base conversion.

	Daveed




More information about the cxx-abi-dev mailing list