[ooc-compiler] Re: ooc-compiler digest, Vol 1 #249 - 1 msg
Brought to you by:
mva
|
From: Michael G. <mg...@co...> - 2006-01-14 16:51:41
|
ooc...@li... wrote: >Send ooc-compiler mailing list submissions to > ooc...@li... > >To subscribe or unsubscribe via the World Wide Web, visit > https://lists.sourceforge.net/lists/listinfo/ooc-compiler >or, via email, send a message with subject or body 'help' to > ooc...@li... > >You can reach the person managing the list at > ooc...@li... > >When replying, please edit your Subject line so it is more specific >than "Re: Contents of ooc-compiler digest..." > > >Today's Topics: > > 1. PROPOSAL: Interface to C++ objects and methods (Stewart Greenhill) > >--__--__-- > >Message: 1 >Date: Thu, 12 Jan 2006 17:10:09 +0800 >From: Stewart Greenhill <sgr...@ii...> >To: ooc...@li... >Subject: [ooc-compiler] PROPOSAL: Interface to C++ objects and methods > >Hi Folks, > >I'm interested in being able to use existing C++ APIs from Oberon-2. > >Currently, oo2c has a limited ability to call methods of C++ objects. >When one declares a record with the VTABLE flag, oo2c builds a C++-style >virtual method table for all instantiated objects, and calls methods of >that object via VTABLE dispatch. This means (for example) that you can >call methods of COM interfaces, and even implement your own COM objects. > >This is fine if one follows a design methodology like COM, which ensures >that there is a language-independent binary interface to your API. COM >uses abstract interfaces and VTABLE method dispatch. It also has a >language-independent type mechanism (ie. IUnknown::QueryInterface). >Unfortunately, most C++ coders seem completely uninterested in language >interoperability. The biggest obstacle with existing C++ APIs is the use >of static (ie. non-virtual) methods. Its only really possible to call >these methods from a C++ compiler, since the symbol names are mangled to >include type information. > >The approach that I'm proposing is to: > >1) Introduce a [STATIC] method flag. This causes calls to methods to be >dispatched statically, rather than using type-descriptor lookup. > >2) Write (by hand, or automatically) a FOREIGN implementation that can >be processed by the C++ compiler. This dispatches method calls to the >C++ objects. > >I'll try to illustrate this by means of an example. Suppose we have a >simple C++ library: > >-- Foreign.h -- >class T { >public: > virtual void Virtual(void); > void Static(void); >}; >-- end Foreign.h -- > >-- Foreign.cpp -- >#include <stdio.h> >#include "Foreign.h" > >void T::Virtual(void) { > printf("T::Virtual\n"); >} > >void T::Static(void) { > printf("T::Static\n"); >} >-- end Foreign.cpp -- > >Using a VTABLE declaration, I can call method "Virtual", but not method >"Static". Now OOC already has a concept of static methods. A method is >called statically (ie. without using a type-descriptor method lookup) if >it is known not to be overridden, or if it is a special predefined >method like INIT. I'm proposing to add a "STATIC" procedure flag, which >specifies that a method is to be treated as a static method (ie. it has >procClass = staticMethod) rather than a virtual method. The address of >the method is always based on an objects static type. > >This allows us to write: > >-- ForeignStatic.Mod -- >MODULE ForeignStatic [ FOREIGN "C"; LINK FILE "ForeignStatic.cpp"; LIB >"foreign"; LIB "stdc++" END ]; > >TYPE > TDesc* = RECORD [VTABLE] END; > T* = POINTER TO TDesc; > >PROCEDURE (t : T) Virtual*; > >PROCEDURE (t : T) [STATIC] Static*; > >PROCEDURE NewT* () : T; > >END ForeignStatic. >-- end ForeignStatic.Mod -- > >Now to make things work, we need the FOREIGN implementation. For the >above library, it looks like this: > >-- ForeignStatic.cpp -- >#include "Foreign.h" >extern "C" { >#include <ForeignStatic.d> >#include <__oo2c.h> >#include <setjmp.h> > >void ForeignStatic__TDesc_Virtual(ForeignStatic__T t) { > ((T*) t)->Virtual(); >} > >void ForeignStatic__TDesc_Static(ForeignStatic__T t) { > ((T*) t)->Static(); >} > >void OOC_ForeignStatic_init(void) { > > return; > ; >} > >void OOC_ForeignStatic_destroy(void) { >} > >ForeignStatic__TDesc* ForeignStatic__NewT(void) { return >(ForeignStatic__TDesc *) new T(); } > >} >/* --- */ >-- end ForeignStatic.cpp -- > >To generate this, I compiled a "stub" module using oo2c, and manually >inserted a few things. >- Included the header for the C++ library. >- The "extern C" is necessary so that the C++ compiler does not mangle >the symbol names. >- Inserted dispatch statements in any methods that are to be called >statically. Actually, "Virtual" is alreadly dispatched by OOC through >the VTABLE, but I could have allowed C++ to do the virtual dispatch here >by declaring it STATIC. >- Inserted a constructor. > >This allows one to do this sort of thing: > >-- TestForeignStatic.Mod -- >MODULE TestForeignStatic; > >IMPORT ForeignStatic; > >PROCEDURE TestForeignStatic1; >VAR t : ForeignStatic.T; >BEGIN > t := ForeignStatic.NewT(); > t.Virtual; > t.Static; >END TestForeignStatic1; > >BEGIN > TestForeignStatic1; >END TestForeignStatic. >-- end TestForeignStatic.Mod -- > >That is, I can call virtual or static methods of objects as if they are >native objects. Note that I don't need to change the calling conventions >used within OOC. It already handles virtual and static dispatch. The >wrapper functions simply redirect the method dispatch using the host >compiler. > >Anyway, with a bit of fiddling I managed to get it to work. The STATIC >flag was easy to implement, but it would be nice if this process could >be streamlined somehow. Ideally, the FOREIGN wrapper implementation >should be generated automatically by OO2C. This should not be hard to do >- If we can get some consensus regarding how it should work I'm willing >to have a go at it. Since the wrapper requires the use of >implementation-specific symbol names and structures it would make sense >for the compiler to provide this feature, rather than an external tool. > >1) There would need to be a declaration that this is a special type of >FOREIGN module (eg. "WRAPPER", or "PROXY"?). Records declared within are >assumed to have no type descriptors. Stub procedures are generated that >dispatch methods in the host ("C++") language. > >2) There should be a list of headers to include at the top of the object >file. > >3) For each record type, we need an optional "link name" saying what the >proxy C++ type is called. This would be used to generate the type casts >in the wrapper methods. > >4) For each method, we need an optional "link name" saying what the >method of the proxy C++ type is called. In the case of an overloaded >method, there will be multiple Oberon-2 names that map to the same C++ name. > >5) There would need to be a way of declaring constructors which would be >dispatched via new(). > >What do people think about these issues? Any suggestions, or violent >objections? ;-) > >Cheers, > Stewart > > > Nice concept. I was thinking about a C++ interface at one point but didn't get very far since I didn't know much about the C++ name mangling. Your approach look like it would solve this problem. Michael G. |