Re: ORBit mail 1 - Multiple-inheritence



Phil Dawes <philipd@parallax.co.uk> writes:
> [snip]

I agree with Phil's analysis up to this point.

> Suggestions for ORBit
> ---------------------
>
> Either we ditch Multiple Inheritence, or we ditch the implicit casting
> part of the C-language mapping - AFAIK we can't have both without gross
> inefficiency.

IMHO you can have both, and the overheads are well within acceptable
limits. See below.

> I don't think we should ditch multiple inheritence because it is a
> cornerstone of the corba object model. In addition, it is very useful
> for mix-in objects. These are objects which support interfaces that
> are not part of their 'semantic' type but merely add some extra
> functionality - e.g. To make objects 'streamable' by adding the
> streamable interface to the inheritence tree.

Ditching MI is tantamount to ditching CORBA. You might as well throw
out the whole spec.

> Ditching the implicit upcasting rule from the C-Mapping means
> providing an explicit way of casting object pointers to their base
> interfaces. This may be a function or macro.

If you do this, you aren't implementing the CORBA C mapping (since
"all object references are of the well-known opaque type CORBA_Object"
- section 19.3 of the CORBA v2.2 spec). So, unless there is _another_
C mapping which does conform, ORBit will not be CORBA-complient.

(IMHO, there are a number of good reasons to supply an additional C
mapping with deviates from the CORBA C mapping. But the CORBA C
mapping has to be supplied as well.)


But, as I said, there is a way to have full CORBA compliance and an
efficient C mapping. There is nothing that requires invocations to be
dispatched directly through the C mappings ugly "vepv"
arrangement. The object reference can point to a pointer to a vtable
with a nice layout, just like in C++ implementations.

Of course, these vtables have to be built by the ORB. There are a
limited number of ways for a CORBA program to convert a servant
(i.e. the data structure representing the object implementation) to an
object reference. For instance, the servant_to_reference POA operation
(p9-36). So when an object reference is first produced for a servant,
the vtable can be built. The function pointers in the vepv can be
copied over into the vtable.

Here's what my current design looks like:

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


The layount of this vtables handles MI and implicit upcasts, just like
C++.

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.

The significant trick here is that the servant pointers are held
within the object descriptor, rather than being derived from it
address. This allows function pointers from the epv to be used
directly in the vtables, without any kind of thunking. Object
descriptors get built by the ORB when an object reference is first
needed for an servant.

Method invocations in C work like:

/* 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);
}

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

Hopefully you can see that this can call directly into a C
servant. 

This is slightly more expensive than a C++ virtual function call, but
not by a great deal. (And unlike C++ virtual function calls, it
doesn't need thunks to cope with MI!)

This design is also much more friendly towards object implementations
in other languages (especially C++).

--
Dave Wragg



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