The interpreter.
authorPaolo Molaro <lupus@oddwiz.org>
Thu, 12 Jul 2001 21:31:37 +0000 (21:31 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Thu, 12 Jul 2001 21:31:37 +0000 (21:31 -0000)
svn path=/trunk/mono/; revision=99

configure.in
mono/Makefile.am
mono/interpreter/Makefile.am [new file with mode: 0644]
mono/interpreter/interp.c [new file with mode: 0644]
mono/interpreter/interp.h [new file with mode: 0644]

index f600abc61746eb33c39fdc475c3921fc22438394..e84609ef30bf43889ed3bafafbf7cb43f1ae1ded 100644 (file)
@@ -32,4 +32,5 @@ mono/Makefile
 mono/metadata/Makefile
 mono/dis/Makefile
 mono/cil/Makefile
+mono/interpreter/Makefile
 ])
index 625278a7e0f5f60dc0d9f5fe6590e8989354601b..dd16095408d3eb55d748c3613d06cf3048b9ab33 100644 (file)
@@ -1 +1 @@
-SUBDIRS = metadata cil dis 
\ No newline at end of file
+SUBDIRS = metadata cil dis interpreter
diff --git a/mono/interpreter/Makefile.am b/mono/interpreter/Makefile.am
new file mode 100644 (file)
index 0000000..e853bb2
--- /dev/null
@@ -0,0 +1,12 @@
+INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir)
+
+bin_PROGRAMS = mono-vm
+
+mono_vm_SOURCES =      \
+       interp.c        \
+       interp.h
+
+mono_vm_LDADD =        \
+       ../metadata/libmetadata.a       \
+       $(GLIB_LIBS)
+
diff --git a/mono/interpreter/interp.c b/mono/interpreter/interp.c
new file mode 100644 (file)
index 0000000..d12afae
--- /dev/null
@@ -0,0 +1,856 @@
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <alloca.h>
+
+#include "interp.h"
+/* trim excessive headers */
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/cil-coff.h>
+#include <mono/metadata/endian.h>
+#include <mono/metadata/typeattr.h>
+#include <mono/metadata/fieldattr.h>
+#include <mono/metadata/methodattr.h>
+#include <mono/metadata/eltype.h>
+#include <mono/metadata/blobsig.h>
+#include <mono/metadata/paramattr.h>
+
+#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
+       a = i,
+
+enum {
+#include "mono/cil/opcode.def"
+       LAST = 0xff
+};
+#undef OPDEF
+
+/* this needs to be metadata,token indexed, not only token */
+static GHashTable * method_cache = 0;
+
+/* FIXME: check in configure */
+typedef gint32 nati_t;
+
+#define GET_NATI(sp) ((guint32)(sp).data.i)
+
+static int count = 0;
+
+/* Attempt at using the goto label construct of GNU GCC:
+ * it turns out this does give some benefit: 5-15% speedup.
+ * Don't look at these macros, it hurts...
+*/
+#define GOTO_LABEL
+#ifdef GOTO_LABEL
+#define SWITCH(a) goto *goto_map[a];
+#define BREAK SWITCH(*ip)
+#define CASE(l)        l ## _LABEL:
+#define SUB_SWITCH \
+       CEE_PREFIX1_LABEL: \
+       CEE_ARGLIST_LABEL: \
+       CEE_CEQ_LABEL: \
+       CEE_CGT_LABEL: \
+       CEE_CGT_UN_LABEL: \
+       CEE_CLT_LABEL: \
+       CEE_CLT_UN_LABEL: \
+       CEE_LDFTN_LABEL: \
+       CEE_LDVIRTFTN_LABEL: \
+       CEE_UNUSED56_LABEL: \
+       CEE_LDARG_LABEL: \
+       CEE_LDARGA_LABEL: \
+       CEE_STARG_LABEL: \
+       CEE_LDLOC_LABEL: \
+       CEE_LDLOCA_LABEL: \
+       CEE_STLOC_LABEL: \
+       CEE_LOCALLOC_LABEL: \
+       CEE_UNUSED57_LABEL: \
+       CEE_ENDFILTER_LABEL: \
+       CEE_UNALIGNED__LABEL: \
+       CEE_VOLATILE__LABEL: \
+       CEE_TAIL__LABEL: \
+       CEE_INITOBJ_LABEL: \
+       CEE_UNUSED68_LABEL: \
+       CEE_CPBLK_LABEL: \
+       CEE_INITBLK_LABEL: \
+       CEE_UNUSED69_LABEL: \
+       CEE_RETHROW_LABEL: \
+       CEE_UNUSED_LABEL: \
+       CEE_SIZEOF_LABEL: \
+       CEE_REFANYTYPE_LABEL: \
+       CEE_UNUSED52_LABEL: \
+       CEE_UNUSED53_LABEL: \
+       CEE_UNUSED54_LABEL: \
+       CEE_UNUSED55_LABEL: \
+       CEE_UNUSED70_LABEL:
+#else
+#define SWITCH(a) switch(a)
+#define BREAK  break
+#define CASE(l)        case l:
+#define SUB_SWITCH case 0xFE:
+#endif
+
+/*
+ * Need to optimize ALU ops when natural int == int32 */
+/*
+ * Need to design how exceptions are supposed to work... */
+/*
+ * IDEA: if we maintain a stack of ip, sp to be checked
+ * in the return opcode, we could inline simple methods that don't
+ * use the stack or local variables....
+ * */
+/* The {,.S} versions of many opcodes can/should be merged to reduce code
+ * duplication.
+ * */
+void 
+ves_exec_method (cli_image_info_t *iinfo, MonoMetaMethodHeader *mh, stackval *args) {
+       /*
+        * with alloca we get the expected huge performance gain
+        * stackval *stack = g_new0(stackval, mh->max_stack);*/
+       stackval *stack = alloca(sizeof(stackval) * mh->max_stack);
+       register unsigned char *ip = mh->code;
+       unsigned char *end = ip+mh->code_size;
+       register stackval *sp = stack;
+       /* FIXME: remove this hack */
+       static int fake_field = 42;
+       /* need to figure out how many of these, too */
+       stackval locals [16];
+#ifdef GOTO_LABEL
+       const static void * const goto_map [] = {
+#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
+       && a ## _LABEL,
+#include "mono/cil/opcode.def"
+#undef OPDEF
+       &&START
+       };
+#endif
+
+       /* using while (ip < end) may result in a 15% performance drop, 
+        * but it may be useful for debug */
+       while (1) {
+               /*count++;*/
+#ifdef GOTO_LABEL
+               START:
+#endif
+               /*g_print ("0x%04x %02x\n", ip-(unsigned char*)mh->code, *ip);
+               if (sp > stack)
+                               printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
+               */
+               SWITCH (*ip) {
+               CASE (CEE_NOP) 
+                       ++ip;
+                       BREAK;
+               CASE (CEE_BREAK)
+                       ++ip;
+                       G_BREAKPOINT(); /* this is not portable... */
+                       BREAK;
+               CASE (CEE_LDARG_0)
+               CASE (CEE_LDARG_1)
+               CASE (CEE_LDARG_2)
+               CASE (CEE_LDARG_3)
+                       *sp = args[(*ip)-CEE_LDARG_0];
+                       ++sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_LDLOC_0)
+               CASE (CEE_LDLOC_1)
+               CASE (CEE_LDLOC_2)
+               CASE (CEE_LDLOC_3)
+                       *sp = locals [(*ip)-CEE_LDLOC_0];
+                       ++ip;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_STLOC_0)
+               CASE (CEE_STLOC_1)
+               CASE (CEE_STLOC_2)
+               CASE (CEE_STLOC_3)
+                       --sp;
+                       locals[(*ip)-CEE_STLOC_0] = *sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_LDARG_S)
+                       ++ip;
+                       *sp = args[*ip];
+                       ++sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_LDARGA_S)
+                       ++ip;
+                       sp->type = VAL_TP;
+                       sp->data.p = &(args[*ip]);
+                       ++sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_STARG_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDLOC_S)
+                       ++ip;
+                       *sp = locals[*ip];
+                       ++sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_LDLOCA_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_STLOC_S)
+                       ++ip;
+                       --sp;
+                       locals[*ip] = *sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_LDNULL) 
+                       ++ip;
+                       sp->type = VAL_OBJ;
+                       sp->data.p = NULL;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDC_I4_M1)
+                       ++ip;
+                       sp->type = VAL_I32;
+                       sp->data.i = -1;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDC_I4_0)
+               CASE (CEE_LDC_I4_1)
+               CASE (CEE_LDC_I4_2)
+               CASE (CEE_LDC_I4_3)
+               CASE (CEE_LDC_I4_4)
+               CASE (CEE_LDC_I4_5)
+               CASE (CEE_LDC_I4_6)
+               CASE (CEE_LDC_I4_7)
+               CASE (CEE_LDC_I4_8)
+                       sp->type = VAL_I32;
+                       sp->data.i = (*ip) - CEE_LDC_I4_0;
+                       ++sp;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_LDC_I4_S) 
+                       ++ip;
+                       sp->type = VAL_I32;
+                       sp->data.i = *ip; /* FIXME: signed? */
+                       ++ip;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDC_I4)
+                       ++ip;
+                       sp->type = VAL_I32;
+                       sp->data.i = read32(ip);
+                       ip += 4;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDC_I8)
+                       ++ip;
+                       sp->type = VAL_I64;
+                       sp->data.i = read64(ip);
+                       ip += 8;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDC_R4)
+                       ++ip;
+                       sp->type = VAL_DOUBLE;
+                       /* FIXME: ENOENDIAN */
+                       sp->data.f = *(float*)(ip);
+                       ip += sizeof(float);
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDC_R8) 
+                       ++ip;
+                       sp->type = VAL_DOUBLE;
+                       /* FIXME: ENOENDIAN */
+                       sp->data.f = *(double*)(ip);
+                       ip += sizeof(double);
+                       ++sp;
+                       BREAK;
+               CASE (CEE_UNUSED99) g_assert_not_reached(); BREAK;
+               CASE (CEE_DUP) 
+                       *sp = sp[-1]; 
+                       ++sp; 
+                       ++ip; 
+                       BREAK;
+               CASE (CEE_POP)
+                       ++ip;
+                       --sp;
+                       BREAK;
+               CASE (CEE_JMP) g_assert_not_reached(); BREAK;
+               CASE (CEE_CALL) {
+                       /* lookup mh, numargs, retval*/
+                       char *loc;
+                       gint32 entryp;
+                       guint32 token;
+                       MonoMetaMethodHeader *cmh;
+
+                       ++ip;
+                       token = read32(ip);
+                       ip += 4;
+                       if (!(cmh=g_hash_table_lookup(method_cache, GINT_TO_POINTER(token)))) {
+                               loc = mono_metadata_locate_token (&iinfo->cli_metadata, token);
+                               entryp = read32(loc);
+                               loc = cli_rva_map (iinfo, entryp);
+                               cmh = mono_metadata_parse_mh (loc);
+                               g_hash_table_insert (method_cache, GINT_TO_POINTER(token), cmh);
+                       }
+                       /* decrement by the actual number of args */
+                       sp--;
+                       /* we need to truncate according to the type of args ... */
+                       ves_exec_method (iinfo, cmh, sp);
+                       /* we assume we got a value here */
+                       sp++;
+                       BREAK;
+               }
+               CASE (CEE_CALLI) g_assert_not_reached(); BREAK;
+               CASE (CEE_RET)
+                       --sp;
+                       *args = *sp;
+                       if (sp != stack)
+                               g_warning ("more values on stack: %d", sp-stack);
+                       /*if (sp->type == VAL_DOUBLE)
+                                       g_print("%.9f\n", sp->data.f);*/
+                       /*g_free (stack);*/
+                       return;
+               CASE (CEE_BR_S)
+                       ++ip;
+                       ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               CASE (CEE_BRFALSE_S) {
+                       int result;
+                       ++ip;
+                       --sp;
+                       switch (sp->type) {
+                       case VAL_I32: result = sp->data.i == 0; break;
+                       case VAL_I64: result = sp->data.l == 0; break;
+                       case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
+                       default: result = sp->data.p == NULL; break;
+                       }
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BRTRUE_S) {
+                       int result;
+                       ++ip;
+                       --sp;
+                       switch (sp->type) {
+                       case VAL_I32: result = sp->data.i != 0; break;
+                       case VAL_I64: result = sp->data.l != 0; break;
+                       case VAL_DOUBLE: result = sp->data.f? 1 : 0; break;
+                       default: result = sp->data.p != NULL; break;
+                       }
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BEQ_S) {
+                       int result;
+                       ++ip;
+                       sp -= 2;
+                       if (sp->type == VAL_I32)
+                               result = sp[0].data.i == GET_NATI(sp[1]);
+                       else if (sp->type == VAL_I64)
+                               result = sp[0].data.l == sp[1].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               result = sp[0].data.f == sp[1].data.f;
+                       else
+                               result = GET_NATI(sp[0]) == GET_NATI(sp[1]);
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BGE_S) {
+                       int result;
+                       ++ip;
+                       sp -= 2;
+                       if (sp->type == VAL_I32)
+                               result = sp[0].data.i >= GET_NATI(sp[1]);
+                       else if (sp->type == VAL_I64)
+                               result = sp[0].data.l >= sp[1].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               result = sp[0].data.f >= sp[1].data.f;
+                       else
+                               result = GET_NATI(sp[0]) >= GET_NATI(sp[1]);
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BGT_S) {
+                       int result;
+                       ++ip;
+                       sp -= 2;
+                       if (sp->type == VAL_I32)
+                               result = sp[0].data.i > GET_NATI(sp[1]);
+                       else if (sp->type == VAL_I64)
+                               result = sp[0].data.l > sp[1].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               result = sp[0].data.f > sp[1].data.f;
+                       else
+                               result = GET_NATI(sp[0]) > GET_NATI(sp[1]);
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BLT_S) {
+                       int result;
+                       ++ip;
+                       sp -= 2;
+                       if (sp->type == VAL_I32)
+                               result = sp[0].data.i < GET_NATI(sp[1]);
+                       else if (sp->type == VAL_I64)
+                               result = sp[0].data.l < sp[1].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               result = sp[0].data.f < sp[1].data.f;
+                       else
+                               result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BLE_S) {
+                       int result;
+                       ++ip;
+                       sp -= 2;
+                       if (sp->type == VAL_I32)
+                               result = sp[0].data.i <= GET_NATI(sp[1]);
+                       else if (sp->type == VAL_I64)
+                               result = sp[0].data.l <= sp[1].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               result = sp[0].data.f <= sp[1].data.f;
+                       else /* FIXME: here and in other places GET_NATI on the left side 
+                             _will_ be wrong when we change the macro to work on 64 buts 
+                             systems.
+                             */
+                               result = GET_NATI(sp[0]) <= GET_NATI(sp[1]);
+                       if (result)
+                               ip += (signed char)*ip;
+                       ++ip;
+                       BREAK;
+               }
+               CASE (CEE_BNE_UN_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_BGE_UN_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_BGT_UN_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_BLE_UN_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_BLT_UN_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_BR) g_assert_not_reached(); BREAK;
+               CASE (CEE_BRFALSE) g_assert_not_reached(); BREAK;
+               CASE (CEE_BRTRUE) g_assert_not_reached(); BREAK;
+               CASE (CEE_BEQ) g_assert_not_reached(); BREAK;
+               CASE (CEE_BGE) g_assert_not_reached(); BREAK;
+               CASE (CEE_BGT) g_assert_not_reached(); BREAK;
+               CASE (CEE_BLE) g_assert_not_reached(); BREAK;
+               CASE (CEE_BLT) g_assert_not_reached(); BREAK;
+               CASE (CEE_BNE_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_BGE_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_BGT_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_BLE_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_BLT_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_SWITCH) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_I1) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_U1) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_I2) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_U2) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_I4) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_U4) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_I8) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_I) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_R4) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_R8) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDIND_REF) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_REF) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_I1) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_I2) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_I4) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_I8) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_R4) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_R8) g_assert_not_reached(); BREAK;
+               CASE (CEE_ADD)
+                       ++ip;
+                       --sp;
+                       /* should probably consider the pointers as unsigned */
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i += GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l += sp[0].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               sp[-1].data.f += sp[0].data.f;
+                       else
+                               (char*)sp[-1].data.p += GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_SUB)
+                       ++ip;
+                       --sp;
+                       /* should probably consider the pointers as unsigned */
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i -= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l -= sp[0].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               sp[-1].data.f -= sp[0].data.f;
+                       else
+                               (char*)sp[-1].data.p -= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_MUL)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i *= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l *= sp[0].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               sp[-1].data.f *= sp[0].data.f;
+                       BREAK;
+               CASE (CEE_DIV)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i /= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l /= sp[0].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               sp[-1].data.f /= sp[0].data.f;
+                       BREAK;
+               CASE (CEE_DIV_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_REM)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i %= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l %= sp[0].data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               /* FIXME: what do we actually fo here? */
+                               sp[-1].data.f = 0;
+                       else
+                               GET_NATI(sp[-1]) %= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_REM_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_AND)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i &= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l &= sp[0].data.l;
+                       else
+                               GET_NATI(sp[-1]) &= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_OR)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i |= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l |= sp[0].data.l;
+                       else
+                               GET_NATI(sp[-1]) |= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_XOR)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i ^= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l ^= sp[0].data.l;
+                       else
+                               GET_NATI(sp[-1]) ^= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_SHL)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i <<= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l <<= GET_NATI(sp[0]);
+                       else
+                               GET_NATI(sp[-1]) <<= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_SHR)
+                       ++ip;
+                       --sp;
+                       if (sp->type == VAL_I32)
+                               sp[-1].data.i >>= GET_NATI(sp[0]);
+                       else if (sp->type == VAL_I64)
+                               sp[-1].data.l >>= GET_NATI(sp[0]);
+                       else
+                               GET_NATI(sp[-1]) >>= GET_NATI(sp[0]);
+                       BREAK;
+               CASE (CEE_SHR_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_NEG)
+                       ++ip;
+                       if (sp->type == VAL_I32)
+                               sp->data.i = - sp->data.i;
+                       else if (sp->type == VAL_I64)
+                               sp->data.l = - sp->data.l;
+                       else if (sp->type == VAL_DOUBLE)
+                               sp->data.f = - sp->data.f;
+                       else if (sp->type == VAL_NATI)
+                               sp->data.p = (gpointer)(- (nati_t)sp->data.p);
+                       BREAK;
+               CASE (CEE_NOT)
+                       ++ip;
+                       if (sp->type == VAL_I32)
+                               sp->data.i = ~ sp->data.i;
+                       else if (sp->type == VAL_I64)
+                               sp->data.l = ~ sp->data.l;
+                       else if (sp->type == VAL_NATI)
+                               sp->data.p = (gpointer)(~ (nati_t)sp->data.p);
+                       BREAK;
+               CASE (CEE_CONV_I1) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_I2) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_I4) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_I8) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_R4) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_R8)
+                       ++ip;
+                       /* FIXME: handle other cases. what about sign? */
+                       sp[-1].data.f = (double)sp[-1].data.i;
+                       sp[-1].type = VAL_DOUBLE;
+                       BREAK;
+               CASE (CEE_CONV_U4) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_U8) g_assert_not_reached(); BREAK;
+               CASE (CEE_CALLVIRT) g_assert_not_reached(); BREAK;
+               CASE (CEE_CPOBJ) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDOBJ) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDSTR) g_assert_not_reached(); BREAK;
+               CASE (CEE_NEWOBJ) g_assert_not_reached(); BREAK;
+               CASE (CEE_CASTCLASS) g_assert_not_reached(); BREAK;
+               CASE (CEE_ISINST) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_R_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED58) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED1) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNBOX) g_assert_not_reached(); BREAK;
+               CASE (CEE_THROW) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDFLD) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDFLDA) g_assert_not_reached(); BREAK;
+               CASE (CEE_STFLD) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDSFLD)
+                       /* FIXME: get the real field here */
+                       ip += 5;
+                       sp->type = VAL_I32;
+                       sp->data.i = fake_field;
+                       ++sp;
+                       BREAK;
+               CASE (CEE_LDSFLDA) g_assert_not_reached(); BREAK;
+               CASE (CEE_STSFLD)
+                       /* FIXME: get the real field here */
+                       ip += 5;
+                       --sp;
+                       fake_field = sp->data.i;
+                       BREAK;
+               CASE (CEE_STOBJ) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I1_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I2_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I4_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I8_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U1_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U2_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U4_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U8_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_BOX) g_assert_not_reached(); BREAK;
+               CASE (CEE_NEWARR) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDLEN) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEMA) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_I1) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_U1) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_I2) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_U2) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_I4) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_U4) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_I8) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_I) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_R4) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_R8) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDELEM_REF) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_I) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_I1) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_I2) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_I4) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_I8) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_R4) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_R8) g_assert_not_reached(); BREAK;
+               CASE (CEE_STELEM_REF) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED2) 
+               CASE (CEE_UNUSED3) 
+               CASE (CEE_UNUSED4) 
+               CASE (CEE_UNUSED5) 
+               CASE (CEE_UNUSED6) 
+               CASE (CEE_UNUSED7) 
+               CASE (CEE_UNUSED8) 
+               CASE (CEE_UNUSED9) 
+               CASE (CEE_UNUSED10) 
+               CASE (CEE_UNUSED11) 
+               CASE (CEE_UNUSED12) 
+               CASE (CEE_UNUSED13) 
+               CASE (CEE_UNUSED14) 
+               CASE (CEE_UNUSED15) 
+               CASE (CEE_UNUSED16) 
+               CASE (CEE_UNUSED17) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I1) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U1) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I2) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U2) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I4) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U4) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I8) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U8) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED50) 
+               CASE (CEE_UNUSED18) 
+               CASE (CEE_UNUSED19) 
+               CASE (CEE_UNUSED20) 
+               CASE (CEE_UNUSED21) 
+               CASE (CEE_UNUSED22) 
+               CASE (CEE_UNUSED23) g_assert_not_reached(); BREAK;
+               CASE (CEE_REFANYVAL) g_assert_not_reached(); BREAK;
+               CASE (CEE_CKFINITE) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED24) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED25) g_assert_not_reached(); BREAK;
+               CASE (CEE_MKREFANY) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED59) 
+               CASE (CEE_UNUSED60) 
+               CASE (CEE_UNUSED61) 
+               CASE (CEE_UNUSED62) 
+               CASE (CEE_UNUSED63) 
+               CASE (CEE_UNUSED64) 
+               CASE (CEE_UNUSED65) 
+               CASE (CEE_UNUSED66) 
+               CASE (CEE_UNUSED67) g_assert_not_reached(); BREAK;
+               CASE (CEE_LDTOKEN) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_U2) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_U1) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_I) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_I) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_OVF_U) g_assert_not_reached(); BREAK;
+               CASE (CEE_ADD_OVF) g_assert_not_reached(); BREAK;
+               CASE (CEE_ADD_OVF_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_MUL_OVF) g_assert_not_reached(); BREAK;
+               CASE (CEE_MUL_OVF_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_SUB_OVF) g_assert_not_reached(); BREAK;
+               CASE (CEE_SUB_OVF_UN) g_assert_not_reached(); BREAK;
+               CASE (CEE_ENDFINALLY) g_assert_not_reached(); BREAK;
+               CASE (CEE_LEAVE) g_assert_not_reached(); BREAK;
+               CASE (CEE_LEAVE_S) g_assert_not_reached(); BREAK;
+               CASE (CEE_STIND_I) g_assert_not_reached(); BREAK;
+               CASE (CEE_CONV_U) g_assert_not_reached(); BREAK;
+               CASE (CEE_UNUSED26) 
+               CASE (CEE_UNUSED27) 
+               CASE (CEE_UNUSED28) 
+               CASE (CEE_UNUSED29) 
+               CASE (CEE_UNUSED30) 
+               CASE (CEE_UNUSED31) 
+               CASE (CEE_UNUSED32) 
+               CASE (CEE_UNUSED33) 
+               CASE (CEE_UNUSED34) 
+               CASE (CEE_UNUSED35) 
+               CASE (CEE_UNUSED36) 
+               CASE (CEE_UNUSED37) 
+               CASE (CEE_UNUSED38) 
+               CASE (CEE_UNUSED39) 
+               CASE (CEE_UNUSED40) 
+               CASE (CEE_UNUSED41) 
+               CASE (CEE_UNUSED42) 
+               CASE (CEE_UNUSED43) 
+               CASE (CEE_UNUSED44) 
+               CASE (CEE_UNUSED45) 
+               CASE (CEE_UNUSED46) 
+               CASE (CEE_UNUSED47) 
+               CASE (CEE_UNUSED48) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIX7) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIX6) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIX5) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIX4) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIX3) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIX2) g_assert_not_reached(); BREAK;
+               CASE (CEE_PREFIXREF) g_assert_not_reached(); BREAK;
+               SUB_SWITCH
+                       ++ip;
+                       switch (*ip) {
+                       case CEE_ARGLIST: g_assert_not_reached(); break;
+                       case CEE_CEQ: g_assert_not_reached(); break;
+                       case CEE_CGT: g_assert_not_reached(); break;
+                       case CEE_CGT_UN: g_assert_not_reached(); break;
+                       case CEE_CLT: g_assert_not_reached(); break;
+                       case CEE_CLT_UN: g_assert_not_reached(); break;
+                       case CEE_LDFTN: g_assert_not_reached(); break;
+                       case CEE_LDVIRTFTN: g_assert_not_reached(); break;
+                       case CEE_UNUSED56: g_assert_not_reached(); break;
+                       case CEE_LDARG: g_assert_not_reached(); break;
+                       case CEE_LDARGA: g_assert_not_reached(); break;
+                       case CEE_STARG: g_assert_not_reached(); break;
+                       case CEE_LDLOC: g_assert_not_reached(); break;
+                       case CEE_LDLOCA: g_assert_not_reached(); break;
+                       case CEE_STLOC: g_assert_not_reached(); break;
+                       case CEE_LOCALLOC: g_assert_not_reached(); break;
+                       case CEE_UNUSED57: g_assert_not_reached(); break;
+                       case CEE_ENDFILTER: g_assert_not_reached(); break;
+                       case CEE_UNALIGNED_: g_assert_not_reached(); break;
+                       case CEE_VOLATILE_: g_assert_not_reached(); break;
+                       case CEE_TAIL_: g_assert_not_reached(); break;
+                       case CEE_INITOBJ: g_assert_not_reached(); break;
+                       case CEE_UNUSED68: g_assert_not_reached(); break;
+                       case CEE_CPBLK: g_assert_not_reached(); break;
+                       case CEE_INITBLK: g_assert_not_reached(); break;
+                       case CEE_UNUSED69: g_assert_not_reached(); break;
+                       case CEE_RETHROW: g_assert_not_reached(); break;
+                       case CEE_UNUSED: g_assert_not_reached(); break;
+                       case CEE_SIZEOF: g_assert_not_reached(); break;
+                       case CEE_REFANYTYPE: g_assert_not_reached(); break;
+                       case CEE_UNUSED52: 
+                       case CEE_UNUSED53: 
+                       case CEE_UNUSED54: 
+                       case CEE_UNUSED55: 
+                       case CEE_UNUSED70: 
+                       default:
+#ifdef GOTO_LABEL
+                       CEE_ILLEGAL_LABEL:
+                       CEE_ENDMAC_LABEL:
+#endif
+                               g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-(unsigned char*)mh->code);
+                       }
+                       continue;
+#ifndef GOTO_LABEL
+               default:
+                       g_error ("Unimplemented opcode: %x at 0x%x\n", *ip, ip-(unsigned char*)mh->code);
+#endif
+               }
+       }
+       g_assert_not_reached();
+}
+
+int 
+ves_exec (cli_image_info_t *iinfo) {
+       gint32 entryp;
+       char * loc, *ptr;
+       stackval result;
+       MonoMetaMethodHeader *mh;
+
+       /* we need to exec the class and object constructors... */
+       method_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
+       ptr = loc = mono_metadata_locate_token (&iinfo->cli_metadata, iinfo->cli_cli_header.ch_entry_point);
+       entryp = read32(loc);
+       loc = cli_rva_map (iinfo, entryp);
+       mh = mono_metadata_parse_mh (loc);
+       ves_exec_method (iinfo, mh, &result);
+       mono_metadata_free_mh (mh);
+       fprintf (stderr, "result: %d\n", result.data.i);
+       return 0;
+}
+
+int 
+main (int argc, char *argv[]) {
+       cli_image_info_t *iinfo;
+       MonoAssembly *assembly;
+       int retval = 0;
+       char * file = argv[1];
+
+       assembly = mono_assembly_open (file, NULL);
+       if (!assembly){
+               fprintf (stderr, "Can not open assembly %s\n", file);
+               exit (1);
+       }
+       iinfo = assembly->image_info;
+       retval = ves_exec (iinfo);
+       mono_assembly_close (assembly);
+       printf("count: %d\n", count);
+       return retval;
+}
diff --git a/mono/interpreter/interp.h b/mono/interpreter/interp.h
new file mode 100644 (file)
index 0000000..584e058
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include <glib.h>
+
+enum {
+       VAL_I32,
+       VAL_I64,
+       VAL_DOUBLE,
+       VAL_NATI,
+       VAL_MP,
+       VAL_TP,
+       VAL_OBJ
+};
+
+typedef struct {
+       union {
+               gint32 i;
+               gint64 l;
+               double f;
+               /* native size integer and pointer types */
+               gpointer p;
+       } data;
+       int type;
+} stackval;
+