Re: ORBit mail 1 - Multiple-inheritence



Phil Dawes <philipd@parallax.co.uk> writes:
> David Wragg wrote:
> > [snip]
> > The object descriptor contains pointers to vtables, plus pointers for
> > the private use of the ORB, plus pointers to the servant. These are
> > repeated to make implicit upcasting work correctly.
> >
>
> I don't understand how implicit upcasting works in this case. Surely to
> make this look like an 'a_B' pointer (e.g. to use with B_m2() stub) you
> need to adjust the CORBA_Object pointer (i.e. do an explicit cast)?
> (or does the stub function do a search of the vtable for the correct
> pointer position?)

You are correct. It's me being confusing/getting confused.

I've been working on trivial upcasting (as in C++), and that's what I
was illustrating. The C servant mapping epv/vepv scheme basically
doesn't support any form of upcasting, and that's what I thought you
were describing, because you discussed the epv/vepv layout.

Oh well, just regard my previous mail as informational, and
s/implicit/trivial/g.

Going back through your post, I see you were (also?) talking about a
more fundamental problem:

Phil> Implicit upcasting is when you treat a pointer to a derived
Phil> class as if it were a pointer to a base class without any
Phil> change to that pointer.

You are absolutely right that this is a problem with MI, and this one
has no simple solution (at least, no-one has ever published one, and
this problem comes up when implementing many OO languages).

In fact, the C mapping doesn't even allow you to represent references
to derived interfaces as a different type to references to base
interfaces - all object references have to be of the type
CORBA_Object. This throws any form of static typing out the window,
and every C method call stub has to do a test on the type of the
object. This represents real stupidity on the part of the spec
authors, as it penalizes many possible ORBs without producing any
significant benefit for any other ORBs. So IMHO part of the solution
is to include a separate C mapping which doesn't have the problems of the
CORBA one.

However, the CORBA C mapping has to be offered as well and for this
dynamic type checks and conversions are needed in each stub
function. But these checks can be as cheap as ObjC or Smalltalk method
calls, or Java interface reference casts, which are commonly
considered acceptable. For instance, each interface is given an index,
and each vtable has an associated hash table, i.e.:

      Object Descriptor

          vtbl ----------------> conv_tbl -------------> ...
	   .    		 methods
       	   .   	       	       	    .
	  vtbl ----\    	    .
	   .        \
	   .         \
	              \--------> conv_tbl -------------> ...
	                         methods
	                            .
				    .

These hash tables map for interface ids to the offset in the object
descriptor required to yield an object reference of the interface, or
a special value saying that conversion is not possible. This is not so
expensive - it's quite possible that in modern machines the cost of
hash table lookups (if well implemented) will disappear into the noise
of caching effects.

>
> Could you show me what your a_B() stub function looks like?

???

>
>
> Also, I don't understand how this works (with reference to the above):
>
> /* Produced by IDL compiler: */
> void C_m2(CORBA_Object a_C, CORBA_Environment *ev)
> {
>     void **obj_descr = a_C;
>
>     ((void (*)(void))obj_descr[4][0])(obj_descr[6], ev);
> }
>
> Is this meant to be a full implementation of the stub function or just
> an illustration?
> Whats the row width of obj_descr? It's declared as a void** so my
> compiler complains that it doesn't know the length of void* when
> attempting to build the double-dereference code.

It's pseudo-C, because this is skirting around the edge of what can be
expressed in C, so a proper C version requires many many casts. It's
probably much better for me to describe the required steps, without a
type system to get in the way. See below.

Also, the code assume that a_C does in fact point to the right kind of
object descriptor (one implementing the interface C), which since it
is just a generic CORBA_Object it might not do. As I said:

DPW> (Note that this does not fully conform the the C mapping, since a_C
DPW> may not actually point to an instance of the interface C. Thus an
DPW> extra test/conversion is required here; yet another flaw in the CORBA
DPW> C mapping.)

This mentions the conversion via a hash table that I describe above.

Here's the picture again:

> > For:
> > interface A { void m1(); };
> > interface B { void m2(); };
> > interface C : A, B { void m3(); };
> >
> > On the client side, a reference to a C looks like:
> >
> >  Object Reference       Object descriptor        Vtables containing
> >  (a CORBA_Object)      (an array of void*)        function pointers
> >
> >      a_C     -------->  C_vtbl          -------------> m1
> >                         void *private                  m3
> >                         void *servant
> >                         B_vtbl          -----\
> >                         void *private         \
> >                         void *servant          \-----> m2

So to call method m2 of the object reference a_C (which is actually a
pointer to a pointer to a vtable), it must:

1) Offset a_C to get a pointer to a vtable for the interface B.
("obj_descr[4]")

2) Offset and dereference the result of (1) to get the pointer to the
implementation of m2. ("obj_descr[4][0]")

3) Offset and dereference a_C to get the "servant" pointer, needed by
the method implementation to get at its object data. ("obj_descr[6]")

4) Do the call to the result of (2), passing the result of (3) and all
the other params.

All actual numbers here are fairly arbitrary

--
Dave Wragg



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]