[Mono-list] Mono C# to C++ compiler - C++ to CIL and CIL to C++ interaction done, working on jitbindgen.exe

Ben Cooley bencooley@cinematix.com
Thu, 18 Jul 2002 13:34:08 +0900


This is a multi-part message in MIME format.

------=_NextPart_000_00AD_01C22E5F.CB6F1220
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

Hi,

I'm still working on the C# to C++ output module for mcs.  The changes =
to "Mint", and "Mono" are now complete (at least for the version of Mono =
and Mint I have), and they are very minor.   Both Mint and Mono now can =
freely incorporate, create, call, and be called by C++ classes, and C++ =
statically compiled classes are now incorporated directly into the Mono =
runtime as managed types.  The overhead for a Jit to C++ call is minor, =
and there is absolutely no overhead for the C++ to Jit calls.

The mono to C++ bindings and integration are accomplished through a =
change in the mono vtable layout.  I made mono's vtable extend backwards =
from the front of the vtable structure with -slot vtable indexes, while =
c++'s vtable extends forwards after the mono vtable info with normal =
positive indexes. =20

I also made a special platform dependent module which extracts a classes =
vtable and method pointers is used to register the C++'s methods as mono =
"internal" methods, and also give mono the layout of the C++'s vtable so =
that mono can build the correct hybrid mono/c++ vtables when it =
instantiates a c++ class.  In the hybrid system, mono is responsible for =
allocating and building all objects, both C++ and managed, but as far as =
mono is concerned there is no difference between the two.  I think this =
should also work with practically any C++ compiler, though the user will =
have to make a small interface to extract the method and vtable =
pointers.

The C++ to mono bindings use macros which utilize C's variable length =
argument list (...) format and function pointer semantics to simply get =
the mono vtable function adress, and call it with the arguments to the =
C++ version of the function.  This compiles down into a very very nice =
inline call in C++ that is really no different than calling a native C++ =
method, except that the target of the call may be a trampolined Jit =
compiled method or an interpreted method.

There was a bug in the mono trampoline code (eax,edx,ecx were out of =
order), but since this code has been replaced in the latest version, the =
problem is moot.  Also, I had to actually make the Mint system create =
real native calls for the vtable.. the version I had was just placing =
mono "method" pointers in the vtable slots.

Finally, I converted both "mono" and "mint" into statically linkable =
libraries with the expedient of changing their "main()" functions to =
"mono()" and "mint()" respectively when MONO_LIB or MINT_LIB was =
defined.

My test program works as follows...

The program initializes, and all global constructors for the =
"Mono_Cpp::RegClass" classes add themselves to the void =
(*mono_initialize_callback)() function pointer I added in order for mono =
to call them back during mono's initialization.

The "main" method of my program is called.  I simply call create a 2 =
element array for mono's argv[] array with the name of my internal =
metadata image file as the image to run (i.e. const char* _argv[] =3D { =
argv[0], "internal:\\MyTest.exe" }; mono(2, _argv); )  Mono then begins =
as if it had been run from the command line with "internal:\\MyTest.exe" =
as the image to run.

Mono then initializes, and after it loads up and initializes =
"corlib.dll" it calls back my registration classes.  Then the linked =
list of Registration classes each register the c++ vtable, c++ method =
pointers for each C++ class, and for the entrypoint class, the metadata =
binary image for the assembly.  The metadata binary image is simply a =
CIL compiled template of the assembly (in my case "Test.exe") with all =
methods marked as "internal calls".

Then mono proceeds on normall.. searches for an entry point.. finds it =
in my dummy metadata, calls it, executes my C++ main funciton with an =
internal call, I then call System::Console::WriteLine() from inside my =
test program, and I get "Hello World!".  Tada.

------------------------------------------------------------

Right now I am finishing up the jitbindgen.c program which will process =
a mono assembly and generate .h files with the C++ to Jit bindings.  =
I've done this by hand in my test programs, but I need to automate to =
get the whole library.  At that point, you will be able to code by hand =
a C++ program that can utilize the CLR class runtime using C++.   After =
that, it's just back to finishing up the C# to C++ translator.

Ben






------=_NextPart_000_00AD_01C22E5F.CB6F1220
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2716.2200" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3DArial size=3D2>Hi,</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>I'm still working on the C# to C++ =
output module=20
for mcs.&nbsp; The changes to "Mint", and "Mono" are now complete (at =
least for=20
the version of Mono and Mint I have), and they are very =
minor.&nbsp;&nbsp; Both=20
Mint and Mono now can freely incorporate, create, call, and be called by =
C++=20
classes, and C++ statically compiled classes are now incorporated =
directly into=20
the Mono runtime as managed types.&nbsp; The overhead for a Jit to C++ =
call is=20
minor, and there is absolutely no overhead for the C++ to Jit=20
calls.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The mono to C++ bindings and =
integration are=20
accomplished through a change in the mono vtable layout.&nbsp;&nbsp;I =
made=20
mono's vtable extend backwards from the front of the vtable structure =
with -slot=20
vtable indexes, while c++'s vtable extends forwards after the mono =
vtable info=20
with normal positive indexes.&nbsp; </FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>I also made a special platform =
dependent module=20
which extracts a classes vtable and method pointers is used to register =
the=20
C++'s methods as mono "internal" methods, and also give mono the layout =
of the=20
C++'s vtable so that mono can build the correct hybrid mono/c++ vtables =
when it=20
instantiates a c++ class.&nbsp; In the hybrid system,&nbsp;mono&nbsp;is=20
responsible for allocating and building all objects, both C++ and =
managed, but=20
as far as mono is concerned there is no difference between the =
two.&nbsp; I=20
think this should also work with practically any C++ compiler, though =
the user=20
will have to make a small interface to extract the method and vtable=20
pointers.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The C++ to mono bindings use macros =
which utilize=20
C's variable length argument list (...) format and function pointer =
semantics to=20
simply get the mono vtable function adress, and call it with the =
arguments to=20
the C++ version of the function.&nbsp; This compiles down into a very =
very nice=20
inline call in C++ that is really no different than calling a native C++ =
method,=20
except that the target of the call may be a trampolined Jit compiled =
method or=20
an interpreted method.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>There was a bug in the mono trampoline =
code=20
(eax,edx,ecx were out of order), but since this code has been replaced =
in the=20
latest version, the problem is moot.&nbsp; Also, I had to actually make =
the Mint=20
system create real native calls for the vtable.. the version I had was =
just=20
placing mono "method" pointers in the vtable slots.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Finally, I converted both "mono" and =
"mint" into=20
statically linkable libraries with the expedient of changing their =
"main()"=20
functions to "mono()" and "mint()" respectively when&nbsp;MONO_LIB or =
MINT_LIB=20
was defined.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>My test program works as =
follows...</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The program initializes, and all global =

constructors for the "Mono_Cpp::RegClass" classes&nbsp;add themselves to =
the=20
void (*mono_initialize_callback)() function pointer I added&nbsp;in =
order for=20
mono to call them back during mono's initialization.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The "main" method of my program is =
called.&nbsp; I=20
simply call&nbsp;create a 2 element array for mono's argv[] array with =
the name=20
of my internal metadata image file as the image to run (i.e.&nbsp;const =
char*=20
_argv[] =3D { argv[0],&nbsp;"internal:\\MyTest.exe" }; mono(2, _argv); =
)&nbsp;=20
Mono then begins as if it had been run from the command line with=20
"internal:\\MyTest.exe" as the image to run.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Mono then initializes, and after it =
loads up and=20
initializes "corlib.dll" it calls back my registration classes.&nbsp; =
Then the=20
linked list of Registration classes&nbsp;each register the c++ vtable, =
c++=20
method pointers for each C++ class, and for the entrypoint class, the =
metadata=20
binary image for the assembly.&nbsp;&nbsp;</FONT><FONT face=3DArial =
size=3D2>The=20
metadata binary image is simply a CIL compiled template of the assembly =
(in my=20
case "Test.exe") with all methods marked as "internal =
calls".</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Then mono proceeds on normall.. =
searches for an=20
entry point.. finds it in my dummy metadata, calls it, executes my C++ =
main=20
funciton with an internal call, I then call System::Console::WriteLine() =
from=20
inside my test program, and I get "Hello World!".&nbsp; =
Tada.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial=20
size=3D2>------------------------------------------------------------</FO=
NT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Right now I am finishing up the =
jitbindgen.c=20
program which will process a mono assembly and generate .h files with =
the C++ to=20
Jit bindings.&nbsp; I've done this by hand in my test programs, but I =
need to=20
automate to get the whole library.&nbsp; At that point, you will be able =
to code=20
by hand a C++ program that can utilize the CLR class runtime using=20
C++.&nbsp;&nbsp; After that, it's just back to finishing up the C# to =
C++=20
translator.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Ben</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV></BODY></HTML>

------=_NextPart_000_00AD_01C22E5F.CB6F1220--