Thu Sep 6 15:38:00 CEST 2001 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Thu, 6 Sep 2001 09:46:03 +0000 (09:46 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Thu, 6 Sep 2001 09:46:03 +0000 (09:46 -0000)
* x86/x86-codegen.h: added x86_rdtsc() and fixes.
* x86/tramp.c: create trampolines to call pinvoke methods.
* x86/Makefile.am: create a libmonoarch convenience library.

Thu Sep 6 15:41:24 CEST 2001 Paolo Molaro <lupus@ximian.com>

* Makefile.am: link to libmonoarch.
* interp.h, interp.c: use mono_create_trampoline ().
Pass the command line arguments to Main (String[]) methods.

svn path=/trunk/mono/; revision=728

configure.in
mono/Makefile.am
mono/arch/ChangeLog
mono/arch/Makefile.am [new file with mode: 0644]
mono/arch/x86/Makefile.am [new file with mode: 0644]
mono/arch/x86/tramp.c [new file with mode: 0644]
mono/arch/x86/x86-codegen.h
mono/interpreter/ChangeLog
mono/interpreter/Makefile.am
mono/interpreter/interp.c
mono/interpreter/interp.h

index d1603cc683606e49a516776ee5f9c8793a20d736..172d4d93996d26be0ad5e49d39baa90f58b4e5ca 100644 (file)
@@ -38,6 +38,8 @@ mono/Makefile
 mono/metadata/Makefile
 mono/dis/Makefile
 mono/cil/Makefile
+mono/arch/Makefile
+mono/arch/x86/Makefile
 mono/interpreter/Makefile
 mono/tests/Makefile
 mono/wrapper/Makefile
index 8c363783b05945439376a1f694521d6e40cc1587..5a34ceb4206bd581d9e13e63183b9d619c9d22c3 100644 (file)
@@ -1 +1 @@
-SUBDIRS = monoburg metadata cil dis interpreter wrapper 
+SUBDIRS = monoburg metadata cil dis arch interpreter wrapper 
index 0116763cbe435d4253c0ea4262e2ca033cad721d..cbcda7488fbd207a59d0a04d0a37dbccf38448ca 100644 (file)
@@ -1,4 +1,10 @@
 
+Thu Sep 6 15:38:00 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * x86/x86-codegen.h: added x86_rdtsc() and fixes.
+       * x86/tramp.c: create trampolines to call pinvoke methods.
+       * x86/Makefile.am: create a libmonoarch convenience library.
+
 Mon Aug 27 09:29:00 CEST 2001 Paolo Molaro <lupus@ximian.com>
 
        * x86/x86-codegen.h: fix x86_call_code (). x86_mov_regp_reg () added.
diff --git a/mono/arch/Makefile.am b/mono/arch/Makefile.am
new file mode 100644 (file)
index 0000000..d76d6c7
--- /dev/null
@@ -0,0 +1,3 @@
+# conditional compilation support here
+
+SUBDIRS = x86
diff --git a/mono/arch/x86/Makefile.am b/mono/arch/x86/Makefile.am
new file mode 100644 (file)
index 0000000..2b4e0b1
--- /dev/null
@@ -0,0 +1,6 @@
+INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir)
+
+lib_LIBRARIES = libmonoarch.a
+
+libmonoarch_a_SOURCES = tramp.c x86-codegen.h
+
diff --git a/mono/arch/x86/tramp.c b/mono/arch/x86/tramp.c
new file mode 100644 (file)
index 0000000..e655c18
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Create trampolines to invoke arbitrary functions.
+ * 
+ * Copyright (C) Ximian Inc.
+ * 
+ * Author: Paolo Molaro (lupus@ximian.com)
+ * 
+ */
+
+#include "x86-codegen.h"
+#include "mono/metadata/class.h"
+#include "mono/interpreter/interp.h"
+
+/*
+ * The resulting function takes the form:
+ * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
+ */
+#define FUNC_ADDR_POS  8
+#define RETVAL_POS     12
+#define THIS_POS       16
+#define ARGP_POS       20
+#define LOC_POS        -4
+
+#define ARG_SIZE       sizeof (stackval)
+
+static char *
+mono_get_ansi_string (MonoObject *o)
+{
+       MonoStringObject *s = (MonoStringObject *)o;
+       char *as, *vector;
+       int i;
+
+       g_assert (o != NULL);
+
+       if (!s->length)
+               return g_strdup ("");
+
+       vector = s->c_str->vector;
+
+       g_assert (vector != NULL);
+
+       as = g_malloc (s->length + 1);
+
+       /* fixme: replace with a real unicode/ansi conversion */
+       for (i = 0; i < s->length; i++) {
+               as [i] = vector [i*2];
+       }
+
+       as [i] = '\0';
+
+       return as;
+}
+
+MonoPIFunc
+mono_create_trampoline (MonoMethod *method)
+{
+       MonoMethodSignature *sig;
+       unsigned char *p, *code_buffer;
+       guint32 local_size = 0, stack_size = 0, code_size = 30;
+       guint32 arg_pos;
+       int i, stringp;
+
+       sig = method->signature;
+       
+       if (sig->hasthis) {
+               stack_size += sizeof (gpointer);
+               code_size += 5;
+       }
+       
+       for (i = 0; i < sig->param_count; ++i) {
+               if (sig->params [i]->byref) {
+                       stack_size += sizeof (gpointer);
+                       code_size += i < 10 ? 5 : 8;
+                       continue;
+               }
+               switch (sig->params [i]->type) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_R4:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:
+                       stack_size += 4;
+                       code_size += i < 10 ? 5 : 8;
+                       break;
+               case MONO_TYPE_STRING:
+                       stack_size += 4;
+                       code_size += 20;
+                       local_size++;
+                       break;
+               case MONO_TYPE_I8:
+                       stack_size += 8;
+                       code_size += i < 10 ? 5 : 8;
+                       break;
+               case MONO_TYPE_R8:
+                       stack_size += 8;
+                       code_size += i < 10 ? 7 : 10;
+                       break;
+               default:
+                       g_error ("Can't trampoline 0x%x", sig->params [i]->type);
+               }
+       }
+       /*
+        * FIXME: take into account large return values.
+        */
+
+       code_buffer = p = alloca (code_size);
+
+       /*
+        * Standard function prolog.
+        */
+       x86_push_reg (p, X86_EBP);
+       x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
+       /*
+        * We store some local vars here to handle string pointers.
+        */
+       if (local_size)
+               x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
+
+       /*
+        * We'll need to align to at least 8 bytes boudary... (16 may be better)
+        * x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
+        */
+
+       /*
+        * EDX has the pointer to the args.
+        */
+       x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
+
+       /*
+        * Push arguments in reverse order.
+        */
+       stringp = 0;
+       for (i = sig->param_count; i; --i) {
+               arg_pos = ARG_SIZE * (i - 1);
+               if (sig->params [i - 1]->byref) {
+                       x86_push_membase (p, X86_EDX, arg_pos);
+                       continue;
+               }
+               switch (sig->params [i - 1]->type) {
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_R4:
+                       x86_push_membase (p, X86_EDX, arg_pos);
+                       break;
+               case MONO_TYPE_R8:
+                       x86_alu_reg_imm (p, X86_SUB, X86_ESP, 8);
+                       x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
+                       x86_fst_membase (p, X86_ESP, 0, TRUE, TRUE);
+                       break;
+               case MONO_TYPE_STRING:
+                       /*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
+                       x86_push_membase (p, X86_EDX, arg_pos);
+                       x86_mov_reg_imm (p, X86_EDX, mono_get_ansi_string);
+                       x86_call_reg (p, X86_EDX);
+                       x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
+                       x86_push_reg (p, X86_EAX);
+                       /*
+                        * Store the pointer in a local we'll free later.
+                        */
+                       stringp++;
+                       x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
+                       /*
+                        * we didn't save the reg: restore it here.
+                        */
+                       x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
+                       break;
+               case MONO_TYPE_I8:
+                       x86_push_membase (p, X86_EDX, arg_pos + 4);
+                       x86_push_membase (p, X86_EDX, arg_pos);
+                       break;
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               default:
+                       g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
+               }
+       }
+
+       if (sig->hasthis) {
+               if (sig->call_convention != MONO_CALL_THISCALL) {
+                       x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
+                       x86_push_reg (p, X86_EDX);
+               } else {
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
+               }
+       }
+
+       /* 
+        * Insert call to function 
+        */
+       x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
+       x86_call_reg (p, X86_EDX);
+
+       /*
+        * Handle retval.
+        * Small integer and pointer values are in EAX.
+        * Long integers are in EAX:EDX.
+        * FP values are on the FP stack.
+        */
+       if (sig->ret->byref) {
+               x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
+               x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
+       } else {
+               switch (sig->ret->type) {
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_OBJECT:
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
+                       x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
+                       break;
+               case MONO_TYPE_R4:
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
+                       x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
+                       break;
+               case MONO_TYPE_R8:
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
+                       x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
+                       break;
+               case MONO_TYPE_I8:
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
+                       x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
+                       x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
+                       break;
+               case MONO_TYPE_VOID:
+                       break;
+               default:
+                       g_error ("Can't handle as return value 0x%x", sig->ret->type);
+               }
+       }
+
+       /*
+        * free the allocated strings.
+        */
+       if (local_size)
+               x86_mov_reg_imm (p, X86_EDX, g_free);
+       for (i = 1; i <= local_size; ++i) {
+               x86_push_membase (p, X86_EBP, LOC_POS * i);
+               x86_call_reg (p, X86_EDX);
+       }
+       /*
+        * Standard epilog.
+        */
+       x86_leave (p);
+       x86_ret (p);
+
+       return g_memdup (code_buffer, p - code_buffer);
+}
+
index f671ceefeb6599411a7ea39f2ba578cd0ab767c6..d320f41bde36e88f32eba6d8b50f0e7def8ddb4b 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C)  2000 Intel Corporation.  All rights reserved.
    Copyright (C)  2001 Ximian, Inc. 
 //
-// $Header: /home/miguel/third-conversion/public/mono/mono/arch/x86/x86-codegen.h,v 1.5 2001/08/27 03:43:09 lupus Exp $
+// $Header: /home/miguel/third-conversion/public/mono/mono/arch/x86/x86-codegen.h,v 1.6 2001/09/06 09:46:03 lupus Exp $
 */
 
 #ifndef X86_H
@@ -238,6 +238,12 @@ typedef union {
 
 #define x86_prefix(inst,p) do { *(inst)++ =(unsigned char) (p); } while (0)
 
+#define x86_rdtsc(inst) \
+       do {    \
+               *(inst)++ = 0x0f;       \
+               *(inst)++ = 0x31;       \
+       } while (0)
+
 #define x86_cmpxchg_reg_reg(inst,dreg,reg)     \
        do {    \
                *(inst)++ = (unsigned char)0x0f;        \
@@ -719,7 +725,7 @@ typedef union {
                        *(inst)++ = (unsigned char)0xc6;        \
                        x86_mem_emit ((inst), 0, (mem));        \
                        x86_imm_emit8 ((inst), (imm));  \
-               } else if ((size) == 4) {       \
+               } else if ((size) == 2) {       \
                        *(inst)++ = (unsigned char)0x66;        \
                        *(inst)++ = (unsigned char)0xc7;        \
                        x86_mem_emit ((inst), 0, (mem));        \
index 653f680f70cb1964af56b9d5046a68a3915f40e3..7fc3be7e43e6ead40c781c0664979ed974e88170 100644 (file)
@@ -1,3 +1,10 @@
+
+Thu Sep 6 15:41:24 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * Makefile.am: link to libmonoarch.
+       * interp.h, interp.c: use mono_create_trampoline ().
+       Pass the command line arguments to Main (String[]) methods.
+
 2001-08-30  Dietmar Maurer  <dietmar@ximian.com>
 
        * interp.c (ves_pinvoke_method): removed the libffi dependency
index cbf7e74649ddf3f2d458d5144e704db5ae6c6541..f9a69919a2fee3d9e98d447d9615094a8bd06955 100644 (file)
@@ -12,6 +12,7 @@ mint_SOURCES =                \
        interp.c        
 
 mint_LDADD =                           \
+       ../arch/x86/libmonoarch.a       \
        ../metadata/libmetadata.a       \
        $(GLIB_LIBS)                    \
        $(GMODULE_LIBS)                 \
index d3822100c420613e075c539503f9135e2ed9a3aa..39f1738ddfd3b9cbc402ec5626931b21bc20df57 100644 (file)
@@ -364,6 +364,8 @@ stackval_from_data (MonoType *type, stackval *result, const char *data)
                return;
        }
        switch (type->type) {
+       case MONO_TYPE_VOID:
+               return;
        case MONO_TYPE_I1:
                result->type = VAL_I32;
                result->data.i = *(gint8*)data;
@@ -550,172 +552,13 @@ ves_array_get (MonoInvocation *frame)
        stackval_from_data (mt, frame->retval, ea);
 }
 
-static char *
-mono_get_ansi_string (MonoObject *o)
-{
-       MonoStringObject *s = (MonoStringObject *)o;
-       char *as, *vector;
-       int i;
-
-       g_assert (o != NULL);
-
-       if (!s->length)
-               return g_strdup ("");
-
-       vector = s->c_str->vector;
-
-       g_assert (vector != NULL);
-
-       as = g_malloc (s->length + 1);
-
-       /* fixme: replace with a real unicode/ansi conversion */
-       for (i = 0; i < s->length; i++) {
-               as [i] = vector [i*2];
-       }
-
-       as [i] = '\0';
-
-       return as;
-}
-
 static void 
 ves_pinvoke_method (MonoInvocation *frame)
 {
-       MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)frame->method;
-       MonoMethodSignature *sig = frame->method->signature;
-       stackval *sp = frame->stack_args;
-       int hasthis = sig->hasthis;
-       char *tmp_string;
-       int i, acount;
-       GSList *t, *l = NULL;
-       guint8 *p;
-       acount = sig->param_count;
-
-       (gpointer)piinfo->code = p = alloca ((acount+hasthis)*32);
-
-       x86_enter (p, 0);
-
-       /* fixme: only works on little endian machines */
-
-       for (i = acount - 1; i >= 0; i--) {
-
-               switch (sig->params [i]->type) {
-
-               case MONO_TYPE_I1:
-               case MONO_TYPE_U1:
-               case MONO_TYPE_BOOLEAN:
-               case MONO_TYPE_I2:
-               case MONO_TYPE_U2:
-               case MONO_TYPE_CHAR:
-               case MONO_TYPE_I4:
-               case MONO_TYPE_U4:
-               case MONO_TYPE_I: /* FIXME: not 64 bit clean */
-               case MONO_TYPE_U:
-               case MONO_TYPE_PTR:
-                       x86_push_imm (p, sp [i].data.i);
-                       break;
-               case MONO_TYPE_R4:
-                       x86_fld (p, &sp [i].data.f, FALSE);
-                       x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
-                       x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE);
-                       break;
-               case MONO_TYPE_R8:
-                       x86_fld (p, &sp [i].data.f, TRUE);
-                       x86_alu_reg_imm (p, X86_SUB, X86_ESP, 8);
-                       x86_fst_membase (p, X86_ESP, 0, TRUE, TRUE);
-                       break;
-               case MONO_TYPE_I8:
-                       x86_push_imm (p, sp [i].data.i);
-                       x86_push_imm (p, *(&sp [i].data.i+1));
-                       break;
-               case MONO_TYPE_STRING:
-                       g_assert (sp [i].type == VAL_OBJ);
-
-                       if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI && sp [i].data.p) {
-                               tmp_string = mono_get_ansi_string (sp [i].data.p);
-                               l = g_slist_prepend (l, tmp_string);
-                               x86_push_imm (p, tmp_string);
-                       } else {
-                               x86_push_imm (p, sp [i].data.p);
-                       }
-                       
-                       break;
-               case MONO_TYPE_OBJECT:
-               case MONO_TYPE_CLASS:
-               case MONO_TYPE_SZARRAY:
-                       x86_push_imm (p, sp [i].data.p);
-                       break;
-               default:
-                       g_warning ("not implemented %02x", sig->params [i]->type);
-                       g_assert_not_reached ();
-               }
-
-       }
-
-       if (hasthis) 
-               x86_push_imm (p, frame->obj);
-
-       x86_call_code (p, (unsigned char*)frame->method->addr);
-
-       switch (sig->ret->type) {
-
-       case MONO_TYPE_I1:
-       case MONO_TYPE_U1:
-       case MONO_TYPE_BOOLEAN:
-       case MONO_TYPE_I2:
-       case MONO_TYPE_U2:
-       case MONO_TYPE_CHAR:
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-       case MONO_TYPE_I: /* FIXME: not 64 bit clean */
-       case MONO_TYPE_U:
-               frame->retval->type = VAL_I32;
-               x86_mov_reg_imm (p, X86_EDX, &frame->retval->data.p);
-               x86_mov_regp_reg (p, X86_EDX, X86_EAX, 4);
-               break;
-       case MONO_TYPE_I8:
-               frame->retval->type = VAL_I64;
-               x86_mov_mem_reg (p, &frame->retval->data.i, X86_EAX, 4);
-               x86_mov_mem_reg (p, &frame->retval->data.i + 1, X86_EDX, 4);
-               break;
-       case MONO_TYPE_R4:
-               frame->retval->type = VAL_DOUBLE;
-               x86_mov_reg_imm (p, X86_EDX, &frame->retval->data.p);
-               x86_fst_membase (p, X86_EDX, 0, FALSE, TRUE);
-               break;
-       case MONO_TYPE_R8:
-               frame->retval->type = VAL_DOUBLE;
-               x86_mov_reg_imm (p, X86_EDX, &frame->retval->data.p);
-               x86_fst_membase (p, X86_EDX, 0, TRUE, TRUE);
-               break;
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_OBJECT:
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_SZARRAY:
-               frame->retval->type = VAL_OBJ;
-               x86_mov_reg_imm (p, X86_EDX, &frame->retval->data.p);
-               x86_mov_regp_reg (p, X86_EDX, X86_EAX, 4);
-               break;
-       case MONO_TYPE_VOID:
-               break;
-       default:
-               g_warning ("not implemented %02x", sig->ret->type);
-               g_assert_not_reached ();
-       }
-
-       x86_leave (p);
-       x86_ret (p);
-
-       piinfo->code ();
-
-       t = l;
-       while (t) {
-               g_free (t->data);
-               t = t->next;
-       }
-
-       g_slist_free (l);
+       MonoPIFunc func = mono_create_trampoline (frame->method);
+       func (frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
+       stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
+       g_free (func);
 }
 
 static void
@@ -2898,18 +2741,16 @@ ves_exec (MonoAssembly *assembly, int argc, char *argv[])
        method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
 
        if (method->signature->param_count) {
-               g_warning ("Main () with arguments not yet supported");
-               exit (1);
-               /*
                int i;
                stackval argv_array;
-               MonoObject *arr = mono_new_szarray (mono_defaults.corlib, mono_defaults.string_token, argc);
+               MonoArrayObject *arr = (MonoArrayObject*)mono_new_szarray (mono_defaults.string_class, argc);
                argv_array.type = VAL_OBJ;
                argv_array.data.p = arr;
+               argv_array.data.vt.klass = NULL;
                for (i=0; i < argc; ++i) {
+                       ((gpointer *)arr->vector)[i] = mono_new_string (argv [i]);
                }
-               INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
-               */
+               INIT_FRAME (&call, NULL, NULL, &argv_array, &result, method);
        } else {
                INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
        }
@@ -2981,7 +2822,11 @@ main (int argc, char *argv [])
 #ifdef RUN_TEST
        test_load_class (assembly->image);
 #else
-       retval = ves_exec (assembly, argc, argv);
+       /*
+        * skip the program name from the args.
+        */
+       ++i;
+       retval = ves_exec (assembly, argc - i, argv + i);
 #endif
        mono_assembly_close (assembly);
 
index 97e8b680d07557dba02d6217e93c783523413aea..4fd6bfe66c3fc1d142a98593a0492d8101ec4758 100644 (file)
@@ -57,3 +57,10 @@ struct _MonoInvocation {
 
 void mono_init_icall (void);
 
+typedef void (*MonoFunc) ();
+typedef void (*MonoPIFunc) (MonoFunc callme, void *retval, void *obj_this, stackval *arguments);
+
+/*
+ * defined in an arch specific file.
+ */
+MonoPIFunc mono_create_trampoline (MonoMethod *method);