2001-08-28 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / interpreter / interp.c
1 /*
2  * PLEASE NOTE: This is a research prototype.
3  *
4  *
5  * interp.c: Interpreter for CIL byte codes
6  *
7  * Authors:
8  *   Paolo Molaro (lupus@ximian.com)
9  *   Miguel de Icaza (miguel@ximian.com)
10  *   Dietmar Maurer (dietmar@ximian.com)
11  *
12  * (C) 2001 Ximian, Inc.
13  */
14 #include <config.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <glib.h>
18 #include <ffi.h>
19
20
21 #ifdef HAVE_ALLOCA_H
22 #   include <alloca.h>
23 #else
24 #   ifdef __CYGWIN__
25 #      define alloca __builtin_alloca
26 #   endif
27 #endif
28
29 /* trim excessive headers */
30 #include <mono/metadata/image.h>
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/cil-coff.h>
33 #include <mono/metadata/endian.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/blob.h>
36 #include <mono/metadata/tokentype.h>
37 #include <mono/metadata/loader.h>
38 //#include <mono/cli/types.h>
39 #include "interp.h"
40 #include "hacks.h"
41
42
43 /* If true, then we output the opcodes as we interpret them */
44 static int tracing = 0;
45
46 static int debug_indent_level = 0;
47
48 /*
49  * Pull the list of opcodes
50  */
51 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
52         a = i,
53
54 enum {
55 #include "mono/cil/opcode.def"
56         LAST = 0xff
57 };
58 #undef OPDEF
59
60 /*
61  * Pull the opcode names
62  */
63 #define OPDEF(a,b,c,d,e,f,g,h,i,j)  b,
64 static char *opcode_names[] = {
65 #include "mono/cil/opcode.def"
66         NULL
67 };
68
69 #define GET_NATI(sp) ((guint32)(sp).data.i)
70 #define CSIZE(x) (sizeof (x) / 4)
71
72 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method)   \
73         do {    \
74                 (frame)->parent = (parent_frame);       \
75                 (frame)->obj = (obj_this);      \
76                 (frame)->stack_args = (method_args);    \
77                 (frame)->retval = (method_retval);      \
78                 (frame)->method = (mono_method);        \
79                 (frame)->ex_handler = NULL;     \
80                 (frame)->ex = NULL;     \
81                 (frame)->child = NULL;  \
82         } while (0)
83
84 static void ves_exec_method (MonoInvocation *frame);
85
86 typedef void (*ICallMethod) (MonoInvocation *frame);
87
88 static void
89 ves_real_abort (int line, MonoMethod *mh,
90                 const unsigned char *ip, stackval *stack, stackval *sp)
91 {
92         MonoMethodNormal *mm = (MonoMethodNormal *)mh;
93         fprintf (stderr, "Execution aborted in method: %s\n", mh->name);
94         fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
95                  ip-mm->header->code);
96         g_print ("0x%04x %02x\n",
97                  ip-mm->header->code, *ip);
98         if (sp > stack)
99                 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
100         exit (1);
101 }
102 #define ves_abort() ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp)
103
104 /*
105  * init_class:
106  * @klass: klass that needs to be initialized
107  *
108  * This routine calls the class constructor for @class if it needs it.
109  */
110 static void
111 init_class (MonoClass *klass)
112 {
113         MonoMethod *method;
114         MonoInvocation call;
115         int i;
116
117         if (!klass->metadata_inited)
118                 mono_class_metadata_init (klass);
119
120         if (klass->inited)
121                 return;
122         if (klass->parent && !klass->parent->inited)
123                 init_class (klass->parent);
124         
125         klass->inited = 1;
126
127         klass->data = g_malloc0 (klass->class_size);
128
129         for (i = 0; i < klass->method.count; ++i) {
130                 method = klass->methods [i];
131                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) {
132                         INIT_FRAME (&call, NULL, NULL, NULL, NULL, method);
133         
134                         ves_exec_method (&call);
135                         mono_free_method (call.method);
136                         return;
137                 }
138         }
139         /* No class constructor found */
140 }
141
142 /*
143  * newobj:
144  * @image: image where the object is being referenced
145  * @token: method token to invoke
146  *
147  * This routine creates a new object based on the class where the
148  * constructor lives.x
149  */
150 static MonoObject *
151 newobj (MonoImage *image, guint32 token)
152 {
153         MonoObject *result = NULL;
154         
155         switch (mono_metadata_token_code (token)){
156         case MONO_TOKEN_METHOD_DEF: {
157                 guint32 idx;
158
159                 idx = mono_metadata_typedef_from_method (image, token);
160
161                 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_DEF | idx);
162                 break;
163         }
164         case MONO_TOKEN_MEMBER_REF: {
165                 guint32 member_cols [MONO_MEMBERREF_SIZE];
166                 guint32 mpr_token, table, idx;
167                 
168                 mono_metadata_decode_row (
169                         &image->tables [MONO_TABLE_MEMBERREF],
170                         mono_metadata_token_index (token) - 1,
171                         member_cols, CSIZE (member_cols));
172                 mpr_token = member_cols [MONO_MEMBERREF_CLASS];
173                 table = mpr_token & 7;
174                 idx = mpr_token >> 3;
175                 
176                 if (strcmp (mono_metadata_string_heap (image, member_cols[1]), ".ctor"))
177                         g_error ("Unhandled: call to non constructor");
178
179                 switch (table){
180                 case 0: /* TypeDef */
181                         result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_DEF | idx);
182                         break;
183                 case 1: /* TypeRef */
184                         result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_REF | idx);
185                         break;
186                 case 2: /* ModuleRef */
187                         g_error ("Unhandled: ModuleRef");
188                         
189                 case 3: /* MethodDef */
190                         g_error ("Unhandled: MethodDef");
191                         
192                 case 4: /* TypeSpec */                  
193                         result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_SPEC | idx);
194                 }
195                 break;
196         }
197         default:
198                 g_warning ("dont know how to handle token %08x\n", token); 
199                 g_assert_not_reached ();
200         }
201         
202         if (result)
203                 init_class (result->klass);
204         return result;
205 }
206
207 #undef DEBUG_VM_DISPATCH
208
209 static MonoMethod*
210 get_virtual_method (MonoImage *image, guint32 token, stackval *args)
211 {
212         MonoMethod *m;
213         MonoObject *obj;
214         MonoClass *klass;
215         stackval *objs;
216         int i;
217         
218         switch (mono_metadata_token_table (token)) {
219         case MONO_TABLE_METHOD:
220         case MONO_TABLE_MEMBERREF:
221                 m = mono_get_method (image, token, NULL);
222                 objs = &args [-(m->signature->param_count + 1)];
223                 obj = objs->data.p;
224                 klass = objs->data.vt.klass ? objs->data.vt.klass: obj->klass;
225 #ifdef DEBUG_VM_DISPATCH
226                 g_print ("%s%smethod lookup %s.%s::%s (cast class %s; real class %s)\n", 
227                                         m->flags & METHOD_ATTRIBUTE_VIRTUAL ? "virtual ": "",
228                                         m->flags & METHOD_ATTRIBUTE_FINAL ? "final ": "",
229                                         m->klass->name_space, m->klass->name, m->name, klass->name, obj->klass->name);
230 #endif
231                 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
232                         return m;
233                 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
234                         klass = obj->klass;
235                 for (; klass && klass != m->klass; klass = klass->parent) {
236                         for (i = 0; i < klass->method.count; ++i) {
237                                 if (!klass->methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
238                                         continue;
239                                 if (!strcmp(m->name, klass->methods [i]->name) && mono_metadata_signature_equal (m->signature, klass->methods [i]->signature)) {
240 #ifdef DEBUG_VM_DISPATCH
241                                         g_print ("\tfound %s%s.%s::%s\n", klass->methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL ? "virtual ": "",
242                                                         klass->name_space, klass->name, klass->methods [i]->name);
243 #endif
244                                         return klass->methods [i];
245                                 }
246                         }
247                 }
248                 return m;
249         }
250         g_error ("got virtual method: 0x%x\n", token);
251         return NULL;
252 }
253
254 static MonoObject*
255 get_named_exception (const char *name)
256 {
257         MonoClass *klass;
258         MonoInvocation call;
259         MonoMethod *method = NULL;
260         MonoObject *o;
261         int i;
262
263         klass = mono_class_from_name (mono_defaults.corlib, "System", name);
264
265         o = mono_new_object (klass);
266         g_assert (o != NULL);
267
268         for (i = 0; i < klass->method.count; ++i) {
269                 if (!strcmp (".ctor", klass->methods [i]->name) &&
270                     klass->methods [i]->signature->param_count == 0) {
271                         method = klass->methods [i];
272                         break;
273                 }
274         }
275
276         call.obj = o;
277
278         g_assert (method);
279         INIT_FRAME (&call, NULL, o, NULL, NULL, method);
280
281         ves_exec_method (&call);
282         return o;
283 }
284
285 static MonoObject*
286 get_exception_divide_by_zero ()
287 {
288         static MonoObject *ex = NULL;
289         if (ex)
290                 return ex;
291         ex = get_named_exception ("DivideByZeroException");
292         return ex;
293 }
294
295 static MonoObject*
296 get_exception_security ()
297 {
298         static MonoObject *ex = NULL;
299         if (ex)
300                 return ex;
301         ex = get_named_exception ("SecurityException");
302         return ex;
303 }
304
305 static MonoObject*
306 get_exception_arithmetic ()
307 {
308         static MonoObject *ex = NULL;
309         if (ex)
310                 return ex;
311         ex = get_named_exception ("ArithmeticException");
312         return ex;
313 }
314
315 static MonoObject*
316 get_exception_overflow ()
317 {
318         static MonoObject *ex = NULL;
319         if (ex)
320                 return ex;
321         ex = get_named_exception ("OverflowException");
322         return ex;
323 }
324
325 static MonoObject*
326 get_exception_null_reference ()
327 {
328         static MonoObject *ex = NULL;
329         if (ex)
330                 return ex;
331         ex = get_named_exception ("NullReferenceException");
332         return ex;
333 }
334
335 static MonoObject*
336 get_exception_execution_engine ()
337 {
338         static MonoObject *ex = NULL;
339         if (ex)
340                 return ex;
341         ex = get_named_exception ("ExecutionEngineException");
342         return ex;
343 }
344
345 static MonoObject*
346 get_exception_invalid_cast ()
347 {
348         static MonoObject *ex = NULL;
349         if (ex)
350                 return ex;
351         ex = get_named_exception ("InvalidCastException");
352         return ex;
353 }
354
355 static void
356 stackval_from_data (MonoType *type, stackval *result, const char *data)
357 {
358         if (type->byref) {
359                 if (type->type == MONO_TYPE_VALUETYPE)
360                         result->type = VAL_VALUETA;
361                 else
362                         result->type = VAL_OBJ;
363                 result->data.p = *(gpointer*)data;
364                 return;
365         }
366         result->data.vt.klass = mono_class_from_mono_type (type);
367         switch (type->type) {
368         case MONO_TYPE_I1:
369                 result->type = VAL_I32;
370                 result->data.i = *(gint8*)data;
371                 return;
372         case MONO_TYPE_U1:
373         case MONO_TYPE_BOOLEAN:
374                 result->type = VAL_I32;
375                 result->data.i = *(guint8*)data;
376                 return;
377         case MONO_TYPE_I2:
378                 result->type = VAL_I32;
379                 result->data.i = *(gint16*)data;
380                 return;
381         case MONO_TYPE_U2:
382         case MONO_TYPE_CHAR:
383                 result->type = VAL_I32;
384                 result->data.i = *(guint16*)data;
385                 return;
386         case MONO_TYPE_I: /* FIXME: not 64 bit clean */
387         case MONO_TYPE_I4:
388                 result->type = VAL_I32;
389                 result->data.i = *(gint32*)data;
390                 return;
391         case MONO_TYPE_U: /* FIXME: not 64 bit clean */
392         case MONO_TYPE_U4:
393                 result->type = VAL_I32;
394                 result->data.i = *(guint32*)data;
395                 return;
396         case MONO_TYPE_R4:
397                 result->type = VAL_DOUBLE;
398                 result->data.f = *(float*)data;
399                 return;
400         case MONO_TYPE_I8:
401                 result->type = VAL_I64;
402                 result->data.l = *(gint64*)data;
403                 return;
404         case MONO_TYPE_R8:
405                 result->type = VAL_DOUBLE;
406                 result->data.f = *(double*)data;
407                 return;
408         case MONO_TYPE_STRING:
409         case MONO_TYPE_SZARRAY:
410         case MONO_TYPE_CLASS:
411         case MONO_TYPE_OBJECT:
412         case MONO_TYPE_ARRAY:
413         case MONO_TYPE_PTR:
414                 result->type = VAL_OBJ;
415                 result->data.p = *(gpointer*)data;
416                 return;
417         case MONO_TYPE_VALUETYPE:
418                 if (type->data.klass->enumtype) {
419                         result->type = VAL_I32;
420                         result->data.i = *(guint32*)data;
421                 } else {
422                         result->type = VAL_VALUET;
423                         result->data.vt.klass = type->data.klass;
424                         memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
425                 }
426                 return;
427         default:
428                 g_warning ("got type 0x%02x", type->type);
429                 g_assert_not_reached ();
430         }
431 }
432
433 static void
434 stackval_to_data (MonoType *type, stackval *val, char *data)
435 {
436         if (type->byref) {
437                 *(gpointer*)data = val->data.p;
438                 return;
439         }
440         switch (type->type) {
441         case MONO_TYPE_I1:
442         case MONO_TYPE_U1:
443                 *(guint8*)data = val->data.i;
444                 break;
445         case MONO_TYPE_BOOLEAN:
446                 *(guint8*)data = (val->data.i != 0);
447                 break;
448         case MONO_TYPE_I2:
449         case MONO_TYPE_U2:
450                 *(guint16*)data = val->data.i;
451                 break;
452         case MONO_TYPE_I: /* FIXME: not 64 bit clean */
453         case MONO_TYPE_U: /* FIXME: not 64 bit clean */
454         case MONO_TYPE_I4:
455         case MONO_TYPE_U4:
456                 *(gint32*)data = val->data.i;
457                 break;
458         case MONO_TYPE_I8:
459                 *(gint64*)data = val->data.l;
460                 break;
461         case MONO_TYPE_R4:
462                 *(float*)data = val->data.f;
463                 break;
464         case MONO_TYPE_R8:
465                 *(double*)data = val->data.f;
466                 break;
467         case MONO_TYPE_STRING:
468         case MONO_TYPE_SZARRAY:
469         case MONO_TYPE_CLASS:
470         case MONO_TYPE_OBJECT:
471         case MONO_TYPE_ARRAY:
472         case MONO_TYPE_PTR:
473                 *(gpointer*)data = val->data.p;
474                 break;
475         case MONO_TYPE_VALUETYPE:
476                 if (type->data.klass->enumtype) {
477                         *(gint32*)data = val->data.i;
478                 } else {
479                         memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
480                 }
481                 break;
482         default:
483                 g_warning ("got type %x", type->type);
484                 g_assert_not_reached ();
485         }
486 }
487
488 static char *
489 mono_get_ansi_string (MonoObject *o)
490 {
491         MonoStringObject *s = (MonoStringObject *)o;
492         char *as, *vector;
493         int i;
494
495         g_assert (o != NULL);
496
497         if (!s->length)
498                 return g_strdup ("");
499
500         vector = s->c_str->vector;
501
502         g_assert (vector != NULL);
503
504         as = g_malloc (s->length + 1);
505
506         /* fixme: replace with a real unicode/ansi conversion */
507         for (i = 0; i < s->length; i++) {
508                 as [i] = vector [i*2];
509         }
510
511         as [i] = '\0';
512
513         return as;
514 }
515
516 static void 
517 ves_pinvoke_method (MonoInvocation *frame)
518 {
519         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)frame->method;
520         MonoMethodSignature *sig = frame->method->signature;
521         gpointer *values;
522         float *tmp_float;
523         char **tmp_string;
524         int i, acount, rsize, align;
525         stackval *sp = frame->stack_args;
526         gpointer res = NULL; 
527         GSList *t, *l = NULL;
528
529         acount = sig->param_count;
530
531         values = alloca (sizeof (gpointer) * acount);
532
533         /* fixme: only works on little endian machines */
534
535         for (i = 0; i < acount; i++) {
536
537                 switch (sig->params [i]->type) {
538
539                 case MONO_TYPE_I1:
540                 case MONO_TYPE_U1:
541                 case MONO_TYPE_BOOLEAN:
542                 case MONO_TYPE_I2:
543                 case MONO_TYPE_U2:
544                 case MONO_TYPE_CHAR:
545                 case MONO_TYPE_I4:
546                 case MONO_TYPE_U4:
547                 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
548                 case MONO_TYPE_U:
549                 case MONO_TYPE_PTR:
550                         values[i] = &sp [i].data.i;
551                         break;
552                 case MONO_TYPE_R4:
553                         tmp_float = alloca (sizeof (float));
554                         *tmp_float = sp [i].data.f;
555                         values[i] = tmp_float;
556                         break;
557                 case MONO_TYPE_R8:
558                         values[i] = &sp [i].data.f;
559                         break;
560                 case MONO_TYPE_I8:
561                         values[i] = &sp [i].data.l;
562                         break;
563                 case MONO_TYPE_STRING:
564                         g_assert (sp [i].type == VAL_OBJ);
565
566                         if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI && sp [i].data.p) {
567                                 tmp_string = alloca (sizeof (char *));
568                                 *tmp_string = mono_get_ansi_string (sp [i].data.p);
569                                 l = g_slist_prepend (l, *tmp_string);
570                                 values[i] = tmp_string;                         
571                         } else {
572                                 /* 
573                                  * fixme: may we pass the object - I assume 
574                                  * that is wrong ?? 
575                                  */
576                                 values[i] = &sp [i].data.p;
577                         }
578                         
579                         break;
580                 default:
581                         g_warning ("not implemented %x", 
582                                    sig->params [i]->type);
583                         g_assert_not_reached ();
584                 }
585
586         }
587
588         if ((rsize = mono_type_size (sig->ret, &align)))
589                 res = alloca (rsize);
590
591         ffi_call (piinfo->cif, frame->method->addr, res, values);
592                 
593         t = l;
594         while (t) {
595                 g_free (t->data);
596                 t = t->next;
597         }
598
599         g_slist_free (l);
600
601         if (sig->ret->type != MONO_TYPE_VOID)
602                 stackval_from_data (sig->ret, frame->retval, res);
603 }
604
605 static void
606 dump_stack (stackval *stack, stackval *sp)
607 {
608         stackval *s = stack;
609         
610         if (sp == stack)
611                 return;
612         
613         while (s < sp) {
614                 switch (s->type) {
615                 case VAL_I32: g_print ("[%d] ", s->data.i); break;
616                 case VAL_I64: g_print ("[%lld] ", s->data.l); break;
617                 case VAL_DOUBLE: g_print ("[%0.5f] ", s->data.f); break;
618                 case VAL_VALUET: g_print ("[vt: %p] ", s->data.vt.vt); break;
619                 default: g_print ("[%p] ", s->data.p); break;
620                 }
621                 ++s;
622         }
623 }
624
625 #define DEBUG_INTERP 1
626 #if DEBUG_INTERP
627
628 static void
629 output_indent (void)
630 {
631         int h;
632
633         for (h = 0; h < debug_indent_level; h++)
634                 g_print ("  ");
635 }
636
637 #define DEBUG_ENTER()   \
638         if (tracing) {  \
639                 MonoClass *klass = frame->method->klass;        \
640                 debug_indent_level++;   \
641                 output_indent ();       \
642                 g_print ("Entering %s.%s::%s\n", klass->name_space, klass->name, frame->method->name);  \
643         } 
644 #define DEBUG_LEAVE()   \
645         if (tracing) {  \
646                 MonoClass *klass = frame->method->klass;        \
647                 output_indent ();       \
648                 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name);   \
649                 debug_indent_level--;   \
650         } 
651
652 #else
653
654 #define DEBUG_ENTER()
655 #define DEBUG_LEAVE()
656
657 #endif
658
659 #define LOCAL_POS(n)            (locals_pointers [(n)])
660 #define LOCAL_TYPE(header, n)   ((header)->locals [(n)])
661
662 #define ARG_POS(n)              (args_pointers [(n)])
663 #define ARG_TYPE(sig, n)        ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
664                                 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
665
666 #define THROW_EX(exception,ex_ip)       \
667                 do {\
668                         frame->ip = (ex_ip);            \
669                         frame->ex = (exception);        \
670                         goto handle_exception;  \
671                 } while (0)
672
673 typedef struct _vtallocation vtallocation;
674
675 struct _vtallocation {
676         vtallocation *next;
677         guint32 size;
678         char data [MONO_ZERO_LEN_ARRAY];
679 };
680
681 /*
682  * we don't use vtallocation->next, yet
683  */
684 #define vt_alloc(vtype,sp)      \
685         if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) {   \
686                 if (!(vtype)->byref) {  \
687                         int align;      \
688                         guint32 size = mono_class_value_size ((vtype)->data.klass, &align);     \
689                         if (!vtalloc || vtalloc->size < size) { \
690                                 vtalloc = alloca (sizeof (vtallocation) + size);        \
691                                 vtalloc->size = size;   \
692                         }       \
693                         (sp)->data.vt.vt = vtalloc->data;       \
694                         vtalloc = NULL; \
695                 } else {        \
696                         (sp)->data.vt.klass = (vtype)->data.klass;      \
697                 }       \
698         }
699
700 #define vt_free(sp)     \
701         do {    \
702                 if ((sp)->type == VAL_VALUET) { \
703                         vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data));    \
704                 }       \
705         } while (0)
706
707 /*
708  * Need to optimize ALU ops when natural int == int32 
709  *
710  * IDEA: if we maintain a stack of ip, sp to be checked
711  * in the return opcode, we could inline simple methods that don't
712  * use the stack or local variables....
713  * 
714  * The {,.S} versions of many opcodes can/should be merged to reduce code
715  * duplication.
716  * 
717  */
718 static void 
719 ves_exec_method (MonoInvocation *frame)
720 {
721         MonoInvocation child_frame;
722         MonoMethodHeader *header;
723         MonoMethodSignature *signature;
724         MonoImage *image;
725         const unsigned char *endfinally_ip;
726         register const unsigned char *ip;
727         register stackval *sp;
728         void **locals_pointers;
729         void **args_pointers;
730         unsigned char tail_recursion = 0;
731         unsigned char unaligned_address = 0;
732         unsigned char volatile_address = 0;
733         vtallocation *vtalloc = NULL;
734         GOTO_LABEL_VARS;
735
736         if (!frame->method->klass->inited)
737                 init_class (frame->method->klass);
738
739         DEBUG_ENTER ();
740
741         if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
742                 ICallMethod icall = frame->method->addr;
743                 icall (frame);
744                 DEBUG_LEAVE ();
745                 return;
746         } 
747
748         if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
749                 ves_pinvoke_method (frame);
750                 DEBUG_LEAVE ();
751                 return;
752         } 
753                 
754         header = ((MonoMethodNormal *)frame->method)->header;
755         signature = frame->method->signature;
756         image = frame->method->klass->image;
757
758         /*
759          * with alloca we get the expected huge performance gain
760          * stackval *stack = g_new0(stackval, header->max_stack);
761          */
762
763         sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
764
765         if (header->num_locals) {
766                 int i, align, size, offset = 0;
767
768                 frame->locals = alloca (header->locals_size);
769                 locals_pointers = alloca (sizeof(void*) * header->num_locals);
770                 /* 
771                  * yes, we do it unconditionally, because it needs to be done for
772                  * some cases anyway and checking for that would be even slower.
773                  */
774                 memset (frame->locals, 0, header->locals_size);
775                 for (i = 0; i < header->num_locals; ++i) {
776                         locals_pointers [i] = frame->locals + offset;
777                         size = mono_type_size (header->locals [i], &align);
778                         offset += offset % align;
779                         offset += size;
780                 }
781         }
782         /*
783          * Copy args from stack_args to args.
784          */
785         if (signature->params_size) {
786                 int i, align, size, offset = 0;
787                 int has_this = signature->hasthis;
788
789                 frame->args = alloca (signature->params_size);
790                 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
791                 if (has_this) {
792                         args_pointers [0] = frame->args;
793                         *(gpointer*) frame->args = frame->obj;
794                         offset += sizeof (gpointer);
795                 }
796                 for (i = 0; i < signature->param_count; ++i) {
797                         args_pointers [i + has_this] = frame->args + offset;
798                         stackval_to_data (signature->params [i], frame->stack_args + i, frame->args + offset);
799                         size = mono_type_size (signature->params [i], &align);
800                         offset += offset % align;
801                         offset += size;
802                 }
803         }
804
805         child_frame.parent = frame;
806         frame->child = &child_frame;
807         frame->ex = NULL;
808
809         /* ready to go */
810         ip = header->code;
811
812         /*
813          * using while (ip < end) may result in a 15% performance drop, 
814          * but it may be useful for debug
815          */
816         while (1) {
817         main_loop:
818                 /*g_assert (sp >= stack);*/
819 #if DEBUG_INTERP
820                 if (tracing){
821                         output_indent ();
822                         g_print ("stack: ");
823                         dump_stack (frame->stack, sp);
824                         g_print ("\n");
825                         output_indent ();
826                         g_print ("0x%04x: %s\n", ip-header->code,
827                                  *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
828                 }
829 #endif
830                 
831                 SWITCH (*ip) {
832                 CASE (CEE_NOP) 
833                         ++ip;
834                         BREAK;
835                 CASE (CEE_BREAK)
836                         ++ip;
837                         G_BREAKPOINT (); /* this is not portable... */
838                         BREAK;
839                 CASE (CEE_LDARG_0)
840                 CASE (CEE_LDARG_1)
841                 CASE (CEE_LDARG_2)
842                 CASE (CEE_LDARG_3) {
843                         int n = (*ip)-CEE_LDARG_0;
844                         ++ip;
845                         vt_alloc (ARG_TYPE (signature, n), sp);
846                         stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
847                         ++sp;
848                         BREAK;
849                 }
850                 CASE (CEE_LDLOC_0)
851                 CASE (CEE_LDLOC_1)
852                 CASE (CEE_LDLOC_2)
853                 CASE (CEE_LDLOC_3) {
854                         int n = (*ip)-CEE_LDLOC_0;
855                         ++ip;
856                         vt_alloc (LOCAL_TYPE (header, n), sp);
857                         stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
858                         ++sp;
859                         BREAK;
860                 }
861                 CASE (CEE_STLOC_0)
862                 CASE (CEE_STLOC_1)
863                 CASE (CEE_STLOC_2)
864                 CASE (CEE_STLOC_3) {
865                         int n = (*ip)-CEE_STLOC_0;
866                         ++ip;
867                         --sp;
868                         stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
869                         vt_free (sp);
870                         BREAK;
871                 }
872                 CASE (CEE_LDARG_S)
873                         ++ip;
874                         vt_alloc (ARG_TYPE (signature, *ip), sp);
875                         stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
876                         ++sp;
877                         ++ip;
878                         BREAK;
879                 CASE (CEE_LDARGA_S) {
880                         MonoType *t;
881                         MonoClass *c;
882
883                         ++ip;
884                         t = ARG_TYPE (signature, *ip);
885                         c = mono_class_from_mono_type (t);
886                         sp->data.vt.klass = c;
887                         sp->data.vt.vt = ARG_POS (*ip);
888
889                         if (c->valuetype)
890                                 sp->type = VAL_VALUETA;
891                         else
892                                 sp->type = VAL_TP;
893
894                         ++sp;
895                         ++ip;
896                         BREAK;
897                 }
898                 CASE (CEE_STARG_S)
899                         ++ip;
900                         --sp;
901                         stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
902                         vt_free (sp);
903                         ++ip;
904                         BREAK;
905                 CASE (CEE_LDLOC_S)
906                         ++ip;
907                         vt_alloc (LOCAL_TYPE (header, *ip), sp);
908                         stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
909                         ++ip;
910                         ++sp;
911                         BREAK;
912                 CASE (CEE_LDLOCA_S) {
913                         MonoType *t;
914                         MonoClass *c;
915
916                         ++ip;
917                         t = LOCAL_TYPE (header, *ip);
918                         c =  mono_class_from_mono_type (t);
919                         sp->data.vt.klass = c;
920                         sp->data.p = LOCAL_POS (*ip);
921
922                         if (c->valuetype)
923                                 sp->type = VAL_VALUETA;
924                         else 
925                                 sp->type = VAL_TP;
926
927                         ++sp;
928                         ++ip;
929                         BREAK;
930                 }
931                 CASE (CEE_STLOC_S)
932                         ++ip;
933                         --sp;
934                         stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
935                         vt_free (sp);
936                         ++ip;
937                         BREAK;
938                 CASE (CEE_LDNULL) 
939                         ++ip;
940                         sp->type = VAL_OBJ;
941                         sp->data.p = NULL;
942                         sp->data.vt.klass = NULL;
943                         ++sp;
944                         BREAK;
945                 CASE (CEE_LDC_I4_M1)
946                         ++ip;
947                         sp->type = VAL_I32;
948                         sp->data.i = -1;
949                         ++sp;
950                         BREAK;
951                 CASE (CEE_LDC_I4_0)
952                 CASE (CEE_LDC_I4_1)
953                 CASE (CEE_LDC_I4_2)
954                 CASE (CEE_LDC_I4_3)
955                 CASE (CEE_LDC_I4_4)
956                 CASE (CEE_LDC_I4_5)
957                 CASE (CEE_LDC_I4_6)
958                 CASE (CEE_LDC_I4_7)
959                 CASE (CEE_LDC_I4_8)
960                         sp->type = VAL_I32;
961                         sp->data.i = (*ip) - CEE_LDC_I4_0;
962                         ++sp;
963                         ++ip;
964                         BREAK;
965                 CASE (CEE_LDC_I4_S) 
966                         ++ip;
967                         sp->type = VAL_I32;
968                         sp->data.i = *ip; /* FIXME: signed? */
969                         ++ip;
970                         ++sp;
971                         BREAK;
972                 CASE (CEE_LDC_I4)
973                         ++ip;
974                         sp->type = VAL_I32;
975                         sp->data.i = read32 (ip);
976                         ip += 4;
977                         ++sp;
978                         BREAK;
979                 CASE (CEE_LDC_I8)
980                         ++ip;
981                         sp->type = VAL_I64;
982                         sp->data.i = read64 (ip);
983                         ip += 8;
984                         ++sp;
985                         BREAK;
986                 CASE (CEE_LDC_R4)
987                         ++ip;
988                         sp->type = VAL_DOUBLE;
989                         /* FIXME: ENOENDIAN */
990                         sp->data.f = *(float*)(ip);
991                         ip += sizeof (float);
992                         ++sp;
993                         BREAK;
994                 CASE (CEE_LDC_R8) 
995                         ++ip;
996                         sp->type = VAL_DOUBLE;
997                         /* FIXME: ENOENDIAN */
998                         sp->data.f = *(double*) (ip);
999                         ip += sizeof (double);
1000                         ++sp;
1001                         BREAK;
1002                 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1003                 CASE (CEE_DUP) 
1004                         if (sp [-1].type == VAL_VALUET) {
1005                                 /* kludge alert! */
1006                                 char *addr = sp [-1].data.vt.vt;
1007                                 MonoType t = sp [-1].data.vt.klass->this_arg;
1008                                 t.byref = 0;
1009                                 vt_alloc (&t, sp);
1010                                 stackval_from_data (&t, sp, addr);
1011                         } else {
1012                                 *sp = sp [-1]; 
1013                         }
1014                         ++sp; 
1015                         ++ip; 
1016                         BREAK;
1017                 CASE (CEE_POP)
1018                         ++ip;
1019                         --sp;
1020                         vt_free (sp);
1021                         BREAK;
1022                 CASE (CEE_JMP) ves_abort(); BREAK;
1023                 CASE (CEE_CALLVIRT) /* Fall through */
1024                 CASE (CEE_CALL) {
1025                         MonoMethodSignature *csignature;
1026                         stackval retval;
1027                         stackval *endsp = sp;
1028                         guint32 token;
1029                         int virtual = *ip == CEE_CALLVIRT;
1030
1031                         /*
1032                          * We ignore tail recursion for now.
1033                          */
1034                         tail_recursion = 0;
1035
1036                         frame->ip = ip;
1037                         
1038                         ++ip;
1039                         token = read32 (ip);
1040                         ip += 4;
1041                         if (virtual)
1042                                 child_frame.method = get_virtual_method (image, token, sp);
1043                         else
1044                                 child_frame.method = mono_get_method (image, token, NULL);
1045                         csignature = child_frame.method->signature;
1046                         g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1047                         /* decrement by the actual number of args */
1048                         if (csignature->param_count) {
1049                                 sp -= csignature->param_count;
1050                                 child_frame.stack_args = sp;
1051                         } else {
1052                                 child_frame.stack_args = NULL;
1053                         }
1054                         if (csignature->hasthis) {
1055                                 g_assert (sp >= frame->stack);
1056                                 --sp;
1057                                 g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1058                                 child_frame.obj = sp->data.p;
1059                         } else {
1060                                 child_frame.obj = NULL;
1061                         }
1062                         if (csignature->ret->type != MONO_TYPE_VOID) {
1063                                 vt_alloc (csignature->ret, &retval);
1064                                 child_frame.retval = &retval;
1065                         } else {
1066                                 child_frame.retval = NULL;
1067                         }
1068
1069                         child_frame.ex = NULL;
1070                         child_frame.ex_handler = NULL;
1071
1072                         ves_exec_method (&child_frame);
1073
1074                         while (endsp > sp) {
1075                                 --endsp;
1076                                 vt_free (endsp);
1077                         }
1078
1079                         if (child_frame.ex) {
1080                                 /*
1081                                  * An exception occurred, need to run finally, fault and catch handlers..
1082                                  */
1083                                 frame->ex = child_frame.ex;
1084                                 goto handle_finally;
1085                         }
1086
1087                         /* need to handle typedbyref ... */
1088                         if (csignature->ret->type != MONO_TYPE_VOID) {
1089                                 *sp = retval;
1090                                 sp++;
1091                         }
1092                         BREAK;
1093                 }
1094                 CASE (CEE_CALLI) ves_abort(); BREAK;
1095                 CASE (CEE_RET)
1096                         if (signature->ret->type != MONO_TYPE_VOID) {
1097                                 --sp;
1098                                 if (sp->type == VAL_VALUET) {
1099                                         /* the caller has already allocated the memory */
1100                                         stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1101                                         vt_free (sp);
1102                                 } else {
1103                                         *frame->retval = *sp;
1104                                 }
1105                         }
1106                         if (sp > frame->stack)
1107                                 g_warning ("more values on stack: %d", sp-frame->stack);
1108
1109                         DEBUG_LEAVE ();
1110                         return;
1111                 CASE (CEE_BR_S) /* Fall through */
1112                 CASE (CEE_BR)
1113                         if (*ip == CEE_BR) {
1114                                 ++ip;
1115                                 ip += (gint32) read32(ip);
1116                                 ip += 4;
1117                         } else {
1118                                 ++ip;
1119                                 ip += (signed char) *ip;
1120                                 ++ip;
1121                         }
1122                         BREAK;
1123                 CASE (CEE_BRFALSE) /* Fall through */
1124                 CASE (CEE_BRFALSE_S) {
1125                         int result;
1126                         int near_jump = *ip == CEE_BRFALSE_S;
1127                         ++ip;
1128                         --sp;
1129                         switch (sp->type) {
1130                         case VAL_I32: result = sp->data.i == 0; break;
1131                         case VAL_I64: result = sp->data.l == 0; break;
1132                         case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1133                         default: result = sp->data.p == NULL; break;
1134                         }
1135                         if (result) {
1136                                 if (near_jump)
1137                                         ip += (signed char)*ip;
1138                                 else
1139                                         ip += (gint32) read32 (ip);
1140                         }
1141                         ip += near_jump ? 1: 4;
1142                         BREAK;
1143                 }
1144                 CASE (CEE_BRTRUE) /* Fall through */
1145                 CASE (CEE_BRTRUE_S) {
1146                         int result;
1147                         int near_jump = *ip == CEE_BRTRUE_S;
1148                         ++ip;
1149                         --sp;
1150                         switch (sp->type) {
1151                         case VAL_I32: result = sp->data.i != 0; break;
1152                         case VAL_I64: result = sp->data.l != 0; break;
1153                         case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1154                         default: result = sp->data.p != NULL; break;
1155                         }
1156                         if (result) {
1157                                 if (near_jump)
1158                                         ip += (signed char)*ip;
1159                                 else
1160                                         ip += (gint32) read32 (ip);
1161                         }
1162                         ip += near_jump ? 1: 4;
1163                         BREAK;
1164                 }
1165                 CASE (CEE_BEQ) /* Fall through */
1166                 CASE (CEE_BEQ_S) {
1167                         int result;
1168                         int near_jump = *ip == CEE_BEQ_S;
1169                         ++ip;
1170                         sp -= 2;
1171                         if (sp->type == VAL_I32)
1172                                 result = sp [0].data.i == GET_NATI (sp [1]);
1173                         else if (sp->type == VAL_I64)
1174                                 result = sp [0].data.l == sp [1].data.l;
1175                         else if (sp->type == VAL_DOUBLE)
1176                                 result = sp [0].data.f == sp [1].data.f;
1177                         else
1178                                 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
1179                         if (result) {
1180                                 if (near_jump)
1181                                         ip += (signed char)*ip;
1182                                 else
1183                                         ip += (gint32) read32 (ip);
1184                         }
1185                         ip += near_jump ? 1: 4;
1186                         BREAK;
1187                 }
1188                 CASE (CEE_BGE) /* Fall through */
1189                 CASE (CEE_BGE_S) {
1190                         int result;
1191                         int near_jump = *ip == CEE_BGE_S;
1192                         ++ip;
1193                         sp -= 2;
1194                         if (sp->type == VAL_I32)
1195                                 result = sp [0].data.i >= GET_NATI (sp [1]);
1196                         else if (sp->type == VAL_I64)
1197                                 result = sp [0].data.l >= sp [1].data.l;
1198                         else if (sp->type == VAL_DOUBLE)
1199                                 result = sp [0].data.f >= sp [1].data.f;
1200                         else
1201                                 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1202                         if (result) {
1203                                 if (near_jump)
1204                                         ip += (signed char)*ip;
1205                                 else
1206                                         ip += (gint32) read32 (ip);
1207                         }
1208                         ip += near_jump ? 1: 4;
1209                         BREAK;
1210                 }
1211                 CASE (CEE_BGT) /* Fall through */
1212                 CASE (CEE_BGT_S) {
1213                         int result;
1214                         int near_jump = *ip == CEE_BGT_S;
1215                         ++ip;
1216                         sp -= 2;
1217                         if (sp->type == VAL_I32)
1218                                 result = sp [0].data.i > GET_NATI (sp [1]);
1219                         else if (sp->type == VAL_I64)
1220                                 result = sp [0].data.l > sp [1].data.l;
1221                         else if (sp->type == VAL_DOUBLE)
1222                                 result = sp [0].data.f > sp [1].data.f;
1223                         else
1224                                 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1225                         if (result) {
1226                                 if (near_jump)
1227                                         ip += (signed char)*ip;
1228                                 else
1229                                         ip += (gint32) read32 (ip);
1230                         }
1231                         ip += near_jump ? 1: 4;
1232                         BREAK;
1233                 }
1234                 CASE (CEE_BLT) /* Fall through */
1235                 CASE (CEE_BLT_S) {
1236                         int result;
1237                         int near_jump = *ip == CEE_BLT_S;
1238                         ++ip;
1239                         sp -= 2;
1240                         if (sp->type == VAL_I32)
1241                                 result = sp[0].data.i < GET_NATI(sp[1]);
1242                         else if (sp->type == VAL_I64)
1243                                 result = sp[0].data.l < sp[1].data.l;
1244                         else if (sp->type == VAL_DOUBLE)
1245                                 result = sp[0].data.f < sp[1].data.f;
1246                         else
1247                                 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1248                         if (result) {
1249                                 if (near_jump)
1250                                         ip += (signed char)*ip;
1251                                 else
1252                                         ip += (gint32) read32 (ip);
1253                         }
1254                         ip += near_jump ? 1: 4;
1255                         BREAK;
1256                 }
1257                 CASE (CEE_BLE) /* fall through */
1258                 CASE (CEE_BLE_S) {
1259                         int result;
1260                         int near_jump = *ip == CEE_BLE_S;
1261                         ++ip;
1262                         sp -= 2;
1263
1264                         if (sp->type == VAL_I32)
1265                                 result = sp [0].data.i <= GET_NATI (sp [1]);
1266                         else if (sp->type == VAL_I64)
1267                                 result = sp [0].data.l <= sp [1].data.l;
1268                         else if (sp->type == VAL_DOUBLE)
1269                                 result = sp [0].data.f <= sp [1].data.f;
1270                         else {
1271                                 /*
1272                                  * FIXME: here and in other places GET_NATI on the left side 
1273                                  * _will_ be wrong when we change the macro to work on 64 buts 
1274                                  * systems.
1275                                  */
1276                                 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1277                         }
1278                         if (result) {
1279                                 if (near_jump)
1280                                         ip += (signed char)*ip;
1281                                 else
1282                                         ip += (gint32) read32 (ip);
1283                         }
1284                         ip += near_jump ? 1: 4;
1285                         BREAK;
1286                 }
1287                 CASE (CEE_BNE_UN) /* Fall through */
1288                 CASE (CEE_BNE_UN_S) {
1289                         int result;
1290                         int near_jump = *ip == CEE_BNE_UN_S;
1291                         ++ip;
1292                         sp -= 2;
1293                         if (sp->type == VAL_I32)
1294                                 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1295                         else if (sp->type == VAL_I64)
1296                                 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1297                         else if (sp->type == VAL_DOUBLE)
1298                                 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1299                                         (sp [0].data.f != sp [1].data.f);
1300                         else
1301                                 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1302                         if (result) {
1303                                 if (near_jump)
1304                                         ip += (signed char)*ip;
1305                                 else
1306                                         ip += (gint32) read32 (ip);
1307                         }
1308                         ip += near_jump ? 1: 4;
1309                         BREAK;
1310                 }
1311                 CASE (CEE_BGE_UN) /* Fall through */
1312                 CASE (CEE_BGE_UN_S) {
1313                         int result;
1314                         int near_jump = *ip == CEE_BGE_UN_S;
1315                         ++ip;
1316                         sp -= 2;
1317                         if (sp->type == VAL_I32)
1318                                 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1319                         else if (sp->type == VAL_I64)
1320                                 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1321                         else if (sp->type == VAL_DOUBLE)
1322                                 result = !isless (sp [0].data.f,sp [1].data.f);
1323                         else
1324                                 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1325                         if (result) {
1326                                 if (near_jump)
1327                                         ip += (signed char)*ip;
1328                                 else
1329                                         ip += (gint32) read32 (ip);
1330                         }
1331                         ip += near_jump ? 1: 4;
1332                         BREAK;
1333                 }
1334                 CASE (CEE_BGT_UN) /* Fall through */
1335                 CASE (CEE_BGT_UN_S) {
1336                         int result;
1337                         int near_jump = *ip == CEE_BGT_UN_S;
1338                         ++ip;
1339                         sp -= 2;
1340                         if (sp->type == VAL_I32)
1341                                 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1342                         else if (sp->type == VAL_I64)
1343                                 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1344                         else if (sp->type == VAL_DOUBLE)
1345                                 result = isgreater (sp [0].data.f, sp [1].data.f);
1346                         else
1347                                 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1348                         if (result) {
1349                                 if (near_jump)
1350                                         ip += (signed char)*ip;
1351                                 else
1352                                         ip += (gint32) read32 (ip);
1353                         }
1354                         ip += near_jump ? 1: 4;
1355                         BREAK;
1356                 }
1357                 CASE (CEE_BLE_UN) /* Fall through */
1358                 CASE (CEE_BLE_UN_S) {
1359                         int result;
1360                         int near_jump = *ip == CEE_BLE_UN_S;
1361                         ++ip;
1362                         sp -= 2;
1363                         if (sp->type == VAL_I32)
1364                                 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1365                         else if (sp->type == VAL_I64)
1366                                 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1367                         else if (sp->type == VAL_DOUBLE)
1368                                 result = islessequal (sp [0].data.f, sp [1].data.f);
1369                         else
1370                                 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1371                         if (result) {
1372                                 if (near_jump)
1373                                         ip += (signed char)*ip;
1374                                 else
1375                                         ip += (gint32) read32 (ip);
1376                         }
1377                         ip += near_jump ? 1: 4;
1378                         BREAK;
1379                 }
1380                 CASE (CEE_BLT_UN) /* Fall through */
1381                 CASE (CEE_BLT_UN_S) {
1382                         int result;
1383                         int near_jump = *ip == CEE_BLT_UN_S;
1384                         ++ip;
1385                         sp -= 2;
1386                         if (sp->type == VAL_I32)
1387                                 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1388                         else if (sp->type == VAL_I64)
1389                                 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1390                         else if (sp->type == VAL_DOUBLE)
1391                                 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1392                                         (sp [0].data.f < sp [1].data.f);
1393                         else
1394                                 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1395                         if (result) {
1396                                 if (near_jump)
1397                                         ip += (signed char)*ip;
1398                                 else
1399                                         ip += (gint32) read32 (ip);
1400                         }
1401                         ip += near_jump ? 1: 4;
1402                         BREAK;
1403                 }
1404                 CASE (CEE_SWITCH) {
1405                         guint32 n;
1406                         const unsigned char *st;
1407                         ++ip;
1408                         n = read32 (ip);
1409                         ip += 4;
1410                         st = ip + sizeof (gint32) * n;
1411                         --sp;
1412                         if ((guint32)sp->data.i < n) {
1413                                 gint offset;
1414                                 ip += sizeof (gint32) * (guint32)sp->data.i;
1415                                 offset = read32 (ip);
1416                                 ip = st + offset;
1417                         } else {
1418                                 ip = st;
1419                         }
1420                         BREAK;
1421                 }
1422                 CASE (CEE_LDIND_I1)
1423                         ++ip;
1424                         sp[-1].type = VAL_I32;
1425                         sp[-1].data.i = *(gint8*)sp[-1].data.p;
1426                         BREAK;
1427                 CASE (CEE_LDIND_U1)
1428                         ++ip;
1429                         sp[-1].type = VAL_I32;
1430                         sp[-1].data.i = *(guint8*)sp[-1].data.p;
1431                         BREAK;
1432                 CASE (CEE_LDIND_I2)
1433                         ++ip;
1434                         sp[-1].type = VAL_I32;
1435                         sp[-1].data.i = *(gint16*)sp[-1].data.p;
1436                         BREAK;
1437                 CASE (CEE_LDIND_U2)
1438                         ++ip;
1439                         sp[-1].type = VAL_I32;
1440                         sp[-1].data.i = *(guint16*)sp[-1].data.p;
1441                         BREAK;
1442                 CASE (CEE_LDIND_I4) /* Fall through */
1443                 CASE (CEE_LDIND_U4)
1444                         ++ip;
1445                         sp[-1].type = VAL_I32;
1446                         sp[-1].data.i = *(gint32*)sp[-1].data.p;
1447                         BREAK;
1448                 CASE (CEE_LDIND_I8)
1449                         ++ip;
1450                         sp[-1].type = VAL_I64;
1451                         sp[-1].data.l = *(gint64*)sp[-1].data.p;
1452                         BREAK;
1453                 CASE (CEE_LDIND_I)
1454                         ++ip;
1455                         sp[-1].type = VAL_NATI;
1456                         sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1457                         BREAK;
1458                 CASE (CEE_LDIND_R4)
1459                         ++ip;
1460                         sp[-1].type = VAL_DOUBLE;
1461                         sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1462                         BREAK;
1463                 CASE (CEE_LDIND_R8)
1464                         ++ip;
1465                         sp[-1].type = VAL_DOUBLE;
1466                         sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1467                         BREAK;
1468                 CASE (CEE_LDIND_REF)
1469                         ++ip;
1470                         sp[-1].type = VAL_OBJ;
1471                         sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1472                         sp[-1].data.vt.klass = NULL;
1473                         BREAK;
1474                 CASE (CEE_STIND_REF)
1475                         ++ip;
1476                         sp -= 2;
1477                         *(gpointer*)sp->data.p = sp[1].data.p;
1478                         BREAK;
1479                 CASE (CEE_STIND_I1)
1480                         ++ip;
1481                         sp -= 2;
1482                         *(gint8*)sp->data.p = (gint8)sp[1].data.i;
1483                         BREAK;
1484                 CASE (CEE_STIND_I2)
1485                         ++ip;
1486                         sp -= 2;
1487                         *(gint16*)sp->data.p = (gint16)sp[1].data.i;
1488                         BREAK;
1489                 CASE (CEE_STIND_I4)
1490                         ++ip;
1491                         sp -= 2;
1492                         *(gint32*)sp->data.p = sp[1].data.i;
1493                         BREAK;
1494                 CASE (CEE_STIND_I)
1495                         ++ip;
1496                         sp -= 2;
1497                         *(gint64*)sp->data.p = sp[1].data.l;
1498                         BREAK;
1499                 CASE (CEE_STIND_I8)
1500                         ++ip;
1501                         sp -= 2;
1502                         *(gint64*)sp->data.p = sp[1].data.l;
1503                         BREAK;
1504                 CASE (CEE_STIND_R4)
1505                         ++ip;
1506                         sp -= 2;
1507                         *(gfloat*)sp->data.p = (gfloat)sp[1].data.f;
1508                         BREAK;
1509                 CASE (CEE_STIND_R8)
1510                         ++ip;
1511                         sp -= 2;
1512                         *(gdouble*)sp->data.p = sp[1].data.f;
1513                         BREAK;
1514                 CASE (CEE_ADD)
1515                         ++ip;
1516                         --sp;
1517                         /* should probably consider the pointers as unsigned */
1518                         if (sp->type == VAL_I32)
1519                                 sp [-1].data.i += GET_NATI (sp [0]);
1520                         else if (sp->type == VAL_I64)
1521                                 sp [-1].data.l += sp [0].data.l;
1522                         else if (sp->type == VAL_DOUBLE)
1523                                 sp [-1].data.f += sp [0].data.f;
1524                         else
1525                                 (char*)sp [-1].data.p += GET_NATI (sp [0]);
1526                         BREAK;
1527                 CASE (CEE_SUB)
1528                         ++ip;
1529                         --sp;
1530                         /* should probably consider the pointers as unsigned */
1531                         if (sp->type == VAL_I32)
1532                                 sp [-1].data.i -= GET_NATI (sp [0]);
1533                         else if (sp->type == VAL_I64)
1534                                 sp [-1].data.l -= sp [0].data.l;
1535                         else if (sp->type == VAL_DOUBLE)
1536                                 sp [-1].data.f -= sp [0].data.f;
1537                         else
1538                                 (char*)sp [-1].data.p -= GET_NATI (sp [0]);
1539                         BREAK;
1540                 CASE (CEE_MUL)
1541                         ++ip;
1542                         --sp;
1543                         if (sp->type == VAL_I32)
1544                                 sp [-1].data.i *= GET_NATI (sp [0]);
1545                         else if (sp->type == VAL_I64)
1546                                 sp [-1].data.l *= sp [0].data.l;
1547                         else if (sp->type == VAL_DOUBLE)
1548                                 sp [-1].data.f *= sp [0].data.f;
1549                         BREAK;
1550                 CASE (CEE_DIV)
1551                         ++ip;
1552                         --sp;
1553                         if (sp->type == VAL_I32) {
1554                                 if (GET_NATI (sp [0]) == 0)
1555                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1556                                 sp [-1].data.i /= GET_NATI (sp [0]);
1557                         } else if (sp->type == VAL_I64) {
1558                                 if (sp [0].data.l == 0)
1559                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1560                                 sp [-1].data.l /= sp [0].data.l;
1561                         } else if (sp->type == VAL_DOUBLE) {
1562                                 /* set NaN is divisor is 0.0 */
1563                                 sp [-1].data.f /= sp [0].data.f;
1564                         }
1565                         BREAK;
1566                 CASE (CEE_DIV_UN)
1567                         ++ip;
1568                         --sp;
1569                         if (sp->type == VAL_I32) {
1570                                 if (GET_NATI (sp [0]) == 0)
1571                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1572                                 (guint32)sp [-1].data.i /= (guint32)GET_NATI (sp [0]);
1573                         } else if (sp->type == VAL_I64) {
1574                                 if (sp [0].data.l == 0)
1575                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1576                                 (guint64)sp [-1].data.l /= (guint64)sp [0].data.l;
1577                         } else if (sp->type == VAL_NATI) {
1578                                 if (GET_NATI (sp [0]) == 0)
1579                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1580                                 (gulong)sp [-1].data.p /= (gulong)sp [0].data.p;
1581                         }
1582                         BREAK;
1583                 CASE (CEE_REM)
1584                         ++ip;
1585                         --sp;
1586                         if (sp->type == VAL_I32) {
1587                                 if (GET_NATI (sp [0]) == 0)
1588                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1589                                 sp [-1].data.i %= GET_NATI (sp [0]);
1590                         } else if (sp->type == VAL_I64) {
1591                                 if (sp [0].data.l == 0)
1592                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1593                                 sp [-1].data.l %= sp [0].data.l;
1594                         } else if (sp->type == VAL_DOUBLE) {
1595                                 /* FIXME: what do we actually do here? */
1596                                 sp [-1].data.f = 0;
1597                         } else {
1598                                 if (GET_NATI (sp [0]) == 0)
1599                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1600                                 GET_NATI (sp [-1]) %= GET_NATI (sp [0]);
1601                         }
1602                         BREAK;
1603                 CASE (CEE_REM_UN) ves_abort(); BREAK;
1604                 CASE (CEE_AND)
1605                         ++ip;
1606                         --sp;
1607                         if (sp->type == VAL_I32)
1608                                 sp [-1].data.i &= GET_NATI (sp [0]);
1609                         else if (sp->type == VAL_I64)
1610                                 sp [-1].data.l &= sp [0].data.l;
1611                         else
1612                                 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1613                         BREAK;
1614                 CASE (CEE_OR)
1615                         ++ip;
1616                         --sp;
1617                         if (sp->type == VAL_I32)
1618                                 sp [-1].data.i |= GET_NATI (sp [0]);
1619                         else if (sp->type == VAL_I64)
1620                                 sp [-1].data.l |= sp [0].data.l;
1621                         else
1622                                 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1623                         BREAK;
1624                 CASE (CEE_XOR)
1625                         ++ip;
1626                         --sp;
1627                         if (sp->type == VAL_I32)
1628                                 sp [-1].data.i ^= GET_NATI (sp [0]);
1629                         else if (sp->type == VAL_I64)
1630                                 sp [-1].data.l ^= sp [0].data.l;
1631                         else
1632                                 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1633                         BREAK;
1634                 CASE (CEE_SHL)
1635                         ++ip;
1636                         --sp;
1637                         if (sp->type == VAL_I32)
1638                                 sp [-1].data.i <<= GET_NATI (sp [0]);
1639                         else if (sp->type == VAL_I64)
1640                                 sp [-1].data.l <<= GET_NATI (sp [0]);
1641                         else
1642                                 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1643                         BREAK;
1644                 CASE (CEE_SHR)
1645                         ++ip;
1646                         --sp;
1647                         if (sp->type == VAL_I32)
1648                                 sp [-1].data.i >>= GET_NATI (sp [0]);
1649                         else if (sp->type == VAL_I64)
1650                                 sp [-1].data.l >>= GET_NATI (sp [0]);
1651                         else
1652                                 GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1653                         BREAK;
1654                 CASE (CEE_SHR_UN) ves_abort(); BREAK;
1655                 CASE (CEE_NEG)
1656                         ++ip;
1657                         if (sp->type == VAL_I32)
1658                                 sp->data.i = - sp->data.i;
1659                         else if (sp->type == VAL_I64)
1660                                 sp->data.l = - sp->data.l;
1661                         else if (sp->type == VAL_DOUBLE)
1662                                 sp->data.f = - sp->data.f;
1663                         else if (sp->type == VAL_NATI)
1664                                 sp->data.p = (gpointer)(- (int)sp->data.p);
1665                         BREAK;
1666                 CASE (CEE_NOT)
1667                         ++ip;
1668                         if (sp->type == VAL_I32)
1669                                 sp->data.i = ~ sp->data.i;
1670                         else if (sp->type == VAL_I64)
1671                                 sp->data.l = ~ sp->data.l;
1672                         else if (sp->type == VAL_NATI)
1673                                 sp->data.p = (gpointer)(~ (int)sp->data.p);
1674                         BREAK;
1675                 CASE (CEE_CONV_U1) // fall through
1676                 CASE (CEE_CONV_I1) {
1677                         ++ip;
1678                         switch (sp [-1].type) {
1679                         case VAL_DOUBLE:
1680                                 sp [-1].data.i = (gint8)sp [-1].data.f;
1681                                 break;
1682                         case VAL_I64:
1683                                 sp [-1].data.i = (gint8)sp [-1].data.l;
1684                                 break;
1685                         case VAL_VALUET:
1686                                 ves_abort();
1687                         case VAL_I32:
1688                                 sp [-1].data.i = (gint8)sp [-1].data.i;
1689                                 break;
1690                         default:
1691                                 sp [-1].data.i = (gint8)sp [-1].data.nati;
1692                                 break;
1693                         }
1694                         sp [-1].type = VAL_I32;
1695                         BREAK;
1696                 }
1697                 CASE (CEE_CONV_U2) // fall through
1698                 CASE (CEE_CONV_I2) {
1699                         ++ip;
1700                         switch (sp [-1].type) {
1701                         case VAL_DOUBLE:
1702                                 sp [-1].data.i = (gint16)sp [-1].data.f;
1703                                 break;
1704                         case VAL_I64:
1705                                 sp [-1].data.i = (gint16)sp [-1].data.l;
1706                                 break;
1707                         case VAL_VALUET:
1708                                 ves_abort();
1709                         case VAL_I32:
1710                                 sp [-1].data.i = (gint16)sp [-1].data.i;
1711                                 break;
1712                         default:
1713                                 sp [-1].data.i = (gint16)sp [-1].data.nati;
1714                                 break;
1715                         }
1716                         sp [-1].type = VAL_I32;
1717                         BREAK;
1718                 }
1719                 CASE (CEE_CONV_U4) /* Fall through */
1720                 CASE (CEE_CONV_I) /* Fall through: FIXME: not 64 bit clean */
1721                 CASE (CEE_CONV_I4) {
1722                         ++ip;
1723                         switch (sp [-1].type) {
1724                         case VAL_DOUBLE:
1725                                 sp [-1].data.i = (gint32)sp [-1].data.f;
1726                                 break;
1727                         case VAL_I64:
1728                                 sp [-1].data.i = (gint32)sp [-1].data.l;
1729                                 break;
1730                         case VAL_VALUET:
1731                                 ves_abort();
1732                         case VAL_I32:
1733                                 break;
1734                         default:
1735                                 sp [-1].data.i = (gint32)sp [-1].data.p;
1736                                 break;
1737                         }
1738                         sp [-1].type = VAL_I32;
1739                         BREAK;
1740                 }
1741                 CASE (CEE_CONV_I8)
1742                         ++ip;
1743                         switch (sp [-1].type) {
1744                         case VAL_DOUBLE:
1745                                 sp [-1].data.l = (gint64)sp [-1].data.f;
1746                                 break;
1747                         case VAL_I64:
1748                                 break;
1749                         case VAL_VALUET:
1750                                 ves_abort();
1751                         case VAL_I32:
1752                                 sp [-1].data.l = (gint64)sp [-1].data.i;
1753                                 break;
1754                         default:
1755                                 sp [-1].data.l = (gint64)sp [-1].data.nati;
1756                                 break;
1757                         }
1758                         sp [-1].type = VAL_I64;
1759                         BREAK;
1760                 CASE (CEE_CONV_R4) /* Fall through */
1761                 CASE (CEE_CONV_R8) {
1762                         ++ip;
1763                         switch (sp [-1].type) {
1764                         case VAL_DOUBLE:
1765                                 sp [-1].data.f = (double)sp [-1].data.f;
1766                                 break;
1767                         case VAL_I64:
1768                                 sp [-1].data.f = (double)sp [-1].data.l;
1769                                 break;
1770                         case VAL_VALUET:
1771                                 ves_abort();
1772                         case VAL_I32:
1773                                 sp [-1].data.f = (double)sp [-1].data.i;
1774                                 break;
1775                         default:
1776                                 sp [-1].data.f = (double)sp [-1].data.nati;
1777                                 break;
1778                         }
1779                         sp [-1].type = VAL_DOUBLE;
1780                         BREAK;
1781                 }
1782                 CASE (CEE_CONV_U) 
1783                         ++ip;
1784                         /* FIXME: handle other cases */
1785                         if (sp [-1].type == VAL_I32) {
1786                                 /* defined as NOP */
1787                         } else {
1788                                 ves_abort();
1789                         }
1790                         BREAK;
1791                 CASE (CEE_CONV_U8) ves_abort(); BREAK;
1792                 CASE (CEE_CPOBJ) ves_abort(); BREAK;
1793                 CASE (CEE_LDOBJ) {
1794                         guint32 token;
1795                         MonoClass *c;
1796                         MonoType t;
1797                         char *addr;
1798
1799                         ++ip;
1800                         token = read32 (ip);
1801                         ip += 4;
1802                         c = mono_class_get (image, token);
1803                         addr = sp [-1].data.vt.vt;
1804                         /* kludge alert! */
1805                         t = c->this_arg;
1806                         t.byref = 0;
1807                         vt_alloc (&t, &sp [-1]);
1808                         stackval_from_data (&t, &sp [-1], addr);
1809                         BREAK;
1810                 }
1811                 CASE (CEE_LDSTR) {
1812                         MonoObject *o;
1813                         const char *name;
1814                         int len;
1815                         guint32 index;
1816
1817                         ip++;
1818                         index = mono_metadata_token_index (read32 (ip));
1819                         ip += 4;
1820
1821                         name = mono_metadata_user_string (image, index);
1822                         len = mono_metadata_decode_blob_size (name, &name);
1823
1824                         o = mono_new_utf16_string (name, len >> 1);
1825                         sp->type = VAL_OBJ;
1826                         sp->data.p = o;
1827                         sp->data.vt.klass = NULL;
1828
1829                         ++sp;
1830                         BREAK;
1831                 }
1832                 CASE (CEE_NEWOBJ) {
1833                         MonoObject *o;
1834                         MonoMethodSignature *csig;
1835                         stackval *endsp = sp;
1836                         guint32 token;
1837
1838                         frame->ip = ip;
1839
1840                         ip++;
1841                         token = read32 (ip);
1842                         o = newobj (image, token);
1843                         ip += 4;
1844                         
1845                         /* call the contructor */
1846                         child_frame.method = mono_get_method (image, token, o->klass);
1847                         csig = child_frame.method->signature;
1848
1849                         /*
1850                          * First arg is the object.
1851                          */
1852                         child_frame.obj = o;
1853
1854                         if (csig->param_count) {
1855                                 sp -= csig->param_count;
1856                                 child_frame.stack_args = sp;
1857                         } else {
1858                                 child_frame.stack_args = NULL;
1859                         }
1860
1861                         g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1862
1863                         child_frame.ex = NULL;
1864                         child_frame.ex_handler = NULL;
1865
1866                         ves_exec_method (&child_frame);
1867
1868                         while (endsp > sp) {
1869                                 --endsp;
1870                                 vt_free (endsp);
1871                         }
1872
1873                         if (child_frame.ex) {
1874                                 /*
1875                                  * An exception occurred, need to run finally, fault and catch handlers..
1876                                  */
1877                                 frame->ex = child_frame.ex;
1878                                 goto handle_finally;
1879                         }
1880                         /*
1881                          * a constructor returns void, but we need to return the object we created
1882                          */
1883                         sp->type = VAL_OBJ;
1884                         sp->data.p = o;
1885                         sp->data.vt.klass = o->klass;
1886                         ++sp;
1887                         BREAK;
1888                 }
1889                 CASE (CEE_CASTCLASS) /* Fall through */
1890                 CASE (CEE_ISINST) {
1891                         MonoObject *o;
1892                         MonoClass *c , *oclass;
1893                         guint32 token;
1894                         int do_isinst = *ip == CEE_ISINST;
1895                         gboolean found = FALSE;
1896
1897                         ++ip;
1898                         token = read32 (ip);
1899                         c = mono_class_get (image, token);
1900
1901                         g_assert (sp [-1].type == VAL_OBJ);
1902
1903                         if ((o = sp [-1].data.p)) {
1904                                 /* 
1905                                  * fixme: this only works for class casts, but not for 
1906                                  * interface casts. 
1907                                  */
1908                                 oclass = o->klass;
1909                                 while (oclass) {
1910                                         if (c == oclass) {
1911                                                 sp [-1].data.vt.klass = oclass;
1912                                                 found = TRUE;
1913                                                 break;
1914                                         }
1915                                         oclass = oclass->parent;
1916                                 }
1917                                 if (!found) {
1918                                         if (do_isinst) {
1919                                                 sp [-1].data.p = NULL;
1920                                                 sp [-1].data.vt.klass = NULL;
1921                                         } else
1922                                                 THROW_EX (get_exception_invalid_cast (), ip - 1);
1923                                 }
1924                         }
1925                         ip += 4;
1926                         BREAK;
1927                 }
1928                 CASE (CEE_CONV_R_UN) ves_abort(); BREAK;
1929                 CASE (CEE_UNUSED58)
1930                 CASE (CEE_UNUSED1) ves_abort(); BREAK;
1931                 CASE (CEE_UNBOX) {
1932                         MonoObject *o;
1933                         MonoClass *c;
1934                         guint32 token;
1935
1936                         ++ip;
1937                         token = read32 (ip);
1938                         
1939                         c = mono_class_get (image, token);
1940                         
1941                         o = sp [-1].data.p;
1942
1943                         g_assert (o->klass->type_token == c->type_token);
1944
1945                         sp [-1].type = VAL_MP;
1946                         sp [-1].data.p = (char *)o + sizeof (MonoObject);
1947
1948                         ip += 4;
1949                         BREAK;
1950                 }
1951                 CASE (CEE_THROW)
1952                         --sp;
1953                         THROW_EX (sp->data.p, ip);
1954                         BREAK;
1955                 CASE (CEE_LDFLDA) /* Fall through */
1956                 CASE (CEE_LDFLD) {
1957                         MonoObject *obj;
1958                         MonoClassField *field;
1959                         guint32 token, offset;
1960                         int load_addr = *ip == CEE_LDFLDA;
1961
1962                         ++ip;
1963                         token = read32 (ip);
1964                         ip += 4;
1965                         
1966                         if (sp [-1].type == VAL_OBJ) {
1967                                 obj = sp [-1].data.p;
1968                                 field = mono_class_get_field (obj->klass, token);
1969                                 offset = field->offset;
1970                         } else { /* valuetype */
1971                                 //g_assert (sp [-1].type == VAL_VALUETA);
1972                                 obj = sp [-1].data.vt.vt;
1973                                 field = mono_class_get_field (sp [-1].data.vt.klass, token);
1974                                 offset = field->offset - sizeof (MonoObject);
1975                         }
1976                         if (load_addr) {
1977                                 sp [-1].type = VAL_TP;
1978                                 sp [-1].data.p = (char*)obj + offset;
1979                                 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
1980                         } else {
1981                                 vt_alloc (field->type, &sp [-1]);
1982                                 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
1983                                 
1984                         }
1985                         BREAK;
1986                 }
1987                 CASE (CEE_STFLD) {
1988                         MonoObject *obj;
1989                         MonoClassField *field;
1990                         guint32 token, offset;
1991
1992                         ++ip;
1993                         token = read32 (ip);
1994                         ip += 4;
1995                         
1996                         sp -= 2;
1997                         
1998                         if (sp [0].type == VAL_OBJ) {
1999                                 obj = sp [0].data.p;
2000                                 field = mono_class_get_field (obj->klass, token);
2001                                 offset = field->offset;
2002                         } else { /* valuetype */
2003                                 //g_assert (sp->type == VAL_VALUETA);
2004                                 obj = sp [0].data.vt.vt;
2005                                 field = mono_class_get_field (sp [0].data.vt.klass, token);
2006                                 offset = field->offset - sizeof (MonoObject);
2007                         }
2008
2009                         stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2010                         vt_free (&sp [1]);
2011                         BREAK;
2012                 }
2013                 CASE (CEE_LDSFLD) /* Fall through */
2014                 CASE (CEE_LDSFLDA) {
2015                         MonoClass *klass;
2016                         MonoClassField *field;
2017                         guint32 token;
2018                         int load_addr = *ip == CEE_LDSFLDA;
2019
2020                         ++ip;
2021                         token = read32 (ip);
2022                         ip += 4;
2023                         
2024                         /* need to handle fieldrefs */
2025                         klass = mono_class_get (image, 
2026                                 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2027                         if (!klass->inited)
2028                                 init_class (klass);
2029                         field = mono_class_get_field (klass, token);
2030                         g_assert (field);
2031                         if (load_addr) {
2032                                 sp->type = VAL_TP;
2033                                 sp->data.p = MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
2034                                 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2035                         } else {
2036                                 vt_alloc (field->type, sp);
2037                                 stackval_from_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2038                         }
2039                         ++sp;
2040                         BREAK;
2041                 }
2042                 CASE (CEE_STSFLD) {
2043                         MonoClass *klass;
2044                         MonoClassField *field;
2045                         guint32 token;
2046
2047                         ++ip;
2048                         token = read32 (ip);
2049                         ip += 4;
2050                         --sp;
2051
2052                         /* need to handle fieldrefs */
2053                         klass = mono_class_get (image, 
2054                                 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2055                         if (!klass->inited)
2056                                 init_class (klass);
2057                         field = mono_class_get_field (klass, token);
2058                         g_assert (field);
2059                         stackval_to_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2060                         vt_free (sp);
2061                         BREAK;
2062                 }
2063                 CASE (CEE_STOBJ) ves_abort(); BREAK;
2064                 CASE (CEE_CONV_OVF_I1_UN) ves_abort(); BREAK;
2065                 CASE (CEE_CONV_OVF_I2_UN) ves_abort(); BREAK;
2066                 CASE (CEE_CONV_OVF_I4_UN) ves_abort(); BREAK;
2067                 CASE (CEE_CONV_OVF_I8_UN) ves_abort(); BREAK;
2068                 CASE (CEE_CONV_OVF_U1_UN) ves_abort(); BREAK;
2069                 CASE (CEE_CONV_OVF_U2_UN) ves_abort(); BREAK;
2070                 CASE (CEE_CONV_OVF_U4_UN) ves_abort(); BREAK;
2071                 CASE (CEE_CONV_OVF_U8_UN) ves_abort(); BREAK;
2072                 CASE (CEE_CONV_OVF_I_UN) ves_abort(); BREAK;
2073                 CASE (CEE_CONV_OVF_U_UN) ves_abort(); BREAK;
2074                 CASE (CEE_BOX) {
2075                         guint32 token;
2076                         MonoClass *class;
2077
2078                         ip++;
2079                         token = read32 (ip);
2080
2081                         class = mono_class_get (image, token);
2082                         g_assert (class != NULL);
2083
2084                         sp [-1].type = VAL_OBJ;
2085                         sp [-1].data.p = mono_value_box (class, &sp [-1]);
2086                         /* need to vt_free (sp); */
2087
2088                         ip += 4;
2089
2090                         BREAK;
2091                 }
2092                 CASE (CEE_NEWARR) {
2093                         MonoClass *class;
2094                         MonoObject *o;
2095                         guint32 token;
2096
2097                         ip++;
2098                         token = read32 (ip);
2099                         class = mono_class_get (image, token);
2100                         o = mono_new_szarray (class, sp [-1].data.i);
2101                         ip += 4;
2102
2103                         sp [-1].type = VAL_OBJ;
2104                         sp [-1].data.p = o;
2105
2106                         BREAK;
2107                 }
2108                 CASE (CEE_LDLEN) {
2109                         MonoArrayObject *o;
2110
2111                         ip++;
2112
2113                         g_assert (sp [-1].type == VAL_OBJ);
2114
2115                         o = sp [-1].data.p;
2116                         g_assert (o != NULL);
2117                         
2118                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2119
2120                         sp [-1].type = VAL_I32;
2121                         sp [-1].data.i = o->bounds [0].length;
2122
2123                         BREAK;
2124                 }
2125                 CASE (CEE_LDELEMA) {
2126                         MonoArrayObject *o;
2127                         guint32 esize, token;
2128                         
2129                         ++ip;
2130                         token = read32 (ip);
2131                         ip += 4;
2132                         sp -= 2;
2133
2134                         g_assert (sp [0].type == VAL_OBJ);
2135                         o = sp [0].data.p;
2136
2137                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2138                         
2139                         g_assert (sp [1].data.i >= 0);
2140                         g_assert (sp [1].data.i < o->bounds [0].length);
2141
2142                         /* check the array element corresponds to token */
2143                         esize = mono_array_element_size ((MonoArrayClass *)o->obj.klass);
2144                         
2145                         sp->type = VAL_MP;
2146                         sp->data.p = ((MonoArrayObject *)o)->vector + (sp [1].data.i * esize);
2147                         sp->data.vt.klass = ((MonoArrayClass *)o->obj.klass)->element_class;
2148                         ++sp;
2149                         BREAK;
2150                 }
2151                 CASE (CEE_LDELEM_I1) /* fall through */
2152                 CASE (CEE_LDELEM_U1) /* fall through */
2153                 CASE (CEE_LDELEM_I2) /* fall through */
2154                 CASE (CEE_LDELEM_U2) /* fall through */
2155                 CASE (CEE_LDELEM_I4) /* fall through */
2156                 CASE (CEE_LDELEM_U4) /* fall through */
2157                 CASE (CEE_LDELEM_I8)  /* fall through */
2158                 CASE (CEE_LDELEM_I)  /* fall through */
2159                 CASE (CEE_LDELEM_R4) /* fall through */
2160                 CASE (CEE_LDELEM_R8) /* fall through */
2161                 CASE (CEE_LDELEM_REF) {
2162                         MonoArrayObject *o;
2163
2164                         sp -= 2;
2165
2166                         g_assert (sp [0].type == VAL_OBJ);
2167                         o = sp [0].data.p;
2168
2169                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2170                         
2171                         g_assert (sp [1].data.i >= 0);
2172                         g_assert (sp [1].data.i < o->bounds [0].length);
2173                         
2174                         switch (*ip) {
2175                         case CEE_LDELEM_I1:
2176                                 sp [0].data.i = ((gint8 *)o->vector)[sp [1].data.i]; 
2177                                 sp [0].type = VAL_I32;
2178                                 break;
2179                         case CEE_LDELEM_U1:
2180                                 sp [0].data.i = ((guint8 *)o->vector)[sp [1].data.i]; 
2181                                 sp [0].type = VAL_I32;
2182                                 break;
2183                         case CEE_LDELEM_I2:
2184                                 sp [0].data.i = ((gint16 *)o->vector)[sp [1].data.i]; 
2185                                 sp [0].type = VAL_I32;
2186                                 break;
2187                         case CEE_LDELEM_U2:
2188                                 sp [0].data.i = ((guint16 *)o->vector)[sp [1].data.i]; 
2189                                 sp [0].type = VAL_I32;
2190                                 break;
2191                         case CEE_LDELEM_I:
2192                                 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i]; 
2193                                 sp [0].type = VAL_NATI;
2194                                 break;
2195                         case CEE_LDELEM_I4:
2196                                 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i]; 
2197                                 sp [0].type = VAL_I32;
2198                                 break;
2199                         case CEE_LDELEM_U4:
2200                                 sp [0].data.i = ((guint32 *)o->vector)[sp [1].data.i]; 
2201                                 sp [0].type = VAL_I32;
2202                                 break;
2203                         case CEE_LDELEM_I8:
2204                                 sp [0].data.l = ((gint64 *)o->vector)[sp [1].data.i]; 
2205                                 sp [0].type = VAL_I64;
2206                                 break;
2207                         case CEE_LDELEM_R4:
2208                                 sp [0].data.f = ((float *)o->vector)[sp [1].data.i]; 
2209                                 sp [0].type = VAL_DOUBLE;
2210                                 break;
2211                         case CEE_LDELEM_R8:
2212                                 sp [0].data.i = ((double *)o->vector)[sp [1].data.i]; 
2213                                 sp [0].type = VAL_DOUBLE;
2214                                 break;
2215                         case CEE_LDELEM_REF:
2216                                 sp [0].data.p = ((gpointer *)o->vector)[sp [1].data.i]; 
2217                                 sp [0].data.vt.klass = NULL;
2218                                 sp [0].type = VAL_OBJ;
2219                                 break;
2220                         default:
2221                                 ves_abort();
2222                         }
2223
2224                         ++ip;
2225                         ++sp;
2226
2227                         BREAK;
2228                 }
2229                 CASE (CEE_STELEM_I)  /* fall through */
2230                 CASE (CEE_STELEM_I1) /* fall through */ 
2231                 CASE (CEE_STELEM_I2) /* fall through */
2232                 CASE (CEE_STELEM_I4) /* fall through */
2233                 CASE (CEE_STELEM_I8) /* fall through */
2234                 CASE (CEE_STELEM_R4) /* fall through */
2235                 CASE (CEE_STELEM_R8) /* fall through */
2236                 CASE (CEE_STELEM_REF) {
2237                         MonoArrayObject *o;
2238                         MonoArrayClass *ac;
2239                         MonoObject *v;
2240
2241                         sp -= 3;
2242
2243                         g_assert (sp [0].type == VAL_OBJ);
2244                         o = sp [0].data.p;
2245
2246                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2247                         ac = (MonoArrayClass *)o->obj.klass;
2248                     
2249                         g_assert (sp [1].data.i >= 0);
2250                         g_assert (sp [1].data.i < o->bounds [0].length);
2251
2252                         switch (*ip) {
2253                         case CEE_STELEM_I:
2254                                 ((gint32 *)o->vector)[sp [1].data.i] = 
2255                                         sp [2].data.i;
2256                                 break;
2257                         case CEE_STELEM_I1:
2258                                 ((gint8 *)o->vector)[sp [1].data.i] = 
2259                                         sp [2].data.i;
2260                                 break;
2261                         case CEE_STELEM_I2:
2262                                 ((gint16 *)o->vector)[sp [1].data.i] = 
2263                                         sp [2].data.i;
2264                                 break;
2265                         case CEE_STELEM_I4:
2266                                 ((gint32 *)o->vector)[sp [1].data.i] = 
2267                                         sp [2].data.i;
2268                                 break;
2269                         case CEE_STELEM_I8:
2270                                 ((gint64 *)o->vector)[sp [1].data.i] = 
2271                                         sp [2].data.l;
2272                                 break;
2273                         case CEE_STELEM_R4:
2274                                 ((float *)o->vector)[sp [1].data.i] = 
2275                                         sp [2].data.f;
2276                                 break;
2277                         case CEE_STELEM_R8:
2278                                 ((double *)o->vector)[sp [1].data.i] = 
2279                                         sp [2].data.f;
2280                                 break;
2281                         case CEE_STELEM_REF:
2282                                 g_assert (sp [2].type == VAL_OBJ);
2283                         
2284                                 v = sp [2].data.p;
2285
2286                                 //fixme: what about type conversions ?
2287                                 g_assert (v->klass == ac->element_class);
2288
2289                                 ((gpointer *)o->vector)[sp [1].data.i] = 
2290                                         sp [2].data.p;
2291                                 break;
2292                         default:
2293                                 ves_abort();
2294                         }
2295
2296                         ++ip;
2297
2298                         BREAK;
2299                 }
2300                 CASE (CEE_UNUSED2) 
2301                 CASE (CEE_UNUSED3) 
2302                 CASE (CEE_UNUSED4) 
2303                 CASE (CEE_UNUSED5) 
2304                 CASE (CEE_UNUSED6) 
2305                 CASE (CEE_UNUSED7) 
2306                 CASE (CEE_UNUSED8) 
2307                 CASE (CEE_UNUSED9) 
2308                 CASE (CEE_UNUSED10) 
2309                 CASE (CEE_UNUSED11) 
2310                 CASE (CEE_UNUSED12) 
2311                 CASE (CEE_UNUSED13) 
2312                 CASE (CEE_UNUSED14) 
2313                 CASE (CEE_UNUSED15) 
2314                 CASE (CEE_UNUSED16) 
2315                 CASE (CEE_UNUSED17) ves_abort(); BREAK;
2316                 CASE (CEE_CONV_OVF_I1) ves_abort(); BREAK;
2317                 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
2318                 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
2319                 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
2320                 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
2321                 CASE (CEE_CONV_OVF_U4)
2322                         ++ip;
2323                         /* FIXME: handle other cases */
2324                         if (sp [-1].type == VAL_I32) {
2325                                 /* defined as NOP */
2326                         } else {
2327                                 ves_abort();
2328                         }
2329                         BREAK;
2330                 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2331                 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
2332                 CASE (CEE_UNUSED50) 
2333                 CASE (CEE_UNUSED18) 
2334                 CASE (CEE_UNUSED19) 
2335                 CASE (CEE_UNUSED20) 
2336                 CASE (CEE_UNUSED21) 
2337                 CASE (CEE_UNUSED22) 
2338                 CASE (CEE_UNUSED23) ves_abort(); BREAK;
2339                 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
2340                 CASE (CEE_CKFINITE) ves_abort(); BREAK;
2341                 CASE (CEE_UNUSED24) ves_abort(); BREAK;
2342                 CASE (CEE_UNUSED25) ves_abort(); BREAK;
2343                 CASE (CEE_MKREFANY) ves_abort(); BREAK;
2344                 CASE (CEE_UNUSED59) 
2345                 CASE (CEE_UNUSED60) 
2346                 CASE (CEE_UNUSED61) 
2347                 CASE (CEE_UNUSED62) 
2348                 CASE (CEE_UNUSED63) 
2349                 CASE (CEE_UNUSED64) 
2350                 CASE (CEE_UNUSED65) 
2351                 CASE (CEE_UNUSED66) 
2352                 CASE (CEE_UNUSED67) ves_abort(); BREAK;
2353                 CASE (CEE_LDTOKEN)
2354                 //CASE (CEE_CONV_I) ves_abort(); BREAK;
2355                 CASE (CEE_CONV_OVF_I) ves_abort(); BREAK;
2356                 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
2357                 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
2358                 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
2359                 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
2360                 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
2361                 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
2362                 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
2363                 CASE (CEE_ENDFINALLY)
2364                         if (frame->ex)
2365                                 goto handle_fault;
2366                         /*
2367                          * There was no exception, we continue normally at the target address.
2368                          */
2369                         ip = endfinally_ip;
2370                         BREAK;
2371                 CASE (CEE_LEAVE) /* Fall through */
2372                 CASE (CEE_LEAVE_S)
2373                         if (*ip == CEE_LEAVE_S) {
2374                                 ++ip;
2375                                 ip += (signed char) *ip;
2376                                 ++ip;
2377                         } else {
2378                                 ++ip;
2379                                 ip += (gint32) read32 (ip);
2380                                 ip += 4;
2381                         }
2382                         /*
2383                          * We may be either inside a try block or inside an handler.
2384                          * In the first case there was no exception and we go on
2385                          * executing the finally handlers and after that resume control
2386                          * at endfinally_ip.
2387                          * In the second case we need to clear the exception and
2388                          * continue directly at the target ip.
2389                          */
2390                         if (frame->ex) {
2391                                 frame->ex = NULL;
2392                                 frame->ex_handler = NULL;
2393                         } else {
2394                                 endfinally_ip = ip;
2395                                 goto handle_finally;
2396                         }
2397                         BREAK;
2398                 CASE (CEE_UNUSED26) 
2399                 CASE (CEE_UNUSED27) 
2400                 CASE (CEE_UNUSED28) 
2401                 CASE (CEE_UNUSED29) 
2402                 CASE (CEE_UNUSED30) 
2403                 CASE (CEE_UNUSED31) 
2404                 CASE (CEE_UNUSED32) 
2405                 CASE (CEE_UNUSED33) 
2406                 CASE (CEE_UNUSED34) 
2407                 CASE (CEE_UNUSED35) 
2408                 CASE (CEE_UNUSED36) 
2409                 CASE (CEE_UNUSED37) 
2410                 CASE (CEE_UNUSED38) 
2411                 CASE (CEE_UNUSED39) 
2412                 CASE (CEE_UNUSED40) 
2413                 CASE (CEE_UNUSED41) 
2414                 CASE (CEE_UNUSED42) 
2415                 CASE (CEE_UNUSED43) 
2416                 CASE (CEE_UNUSED44) 
2417                 CASE (CEE_UNUSED45) 
2418                 CASE (CEE_UNUSED46) 
2419                 CASE (CEE_UNUSED47) 
2420                 CASE (CEE_UNUSED48)
2421                 CASE (CEE_PREFIX7)
2422                 CASE (CEE_PREFIX6)
2423                 CASE (CEE_PREFIX5)
2424                 CASE (CEE_PREFIX4)
2425                 CASE (CEE_PREFIX3)
2426                 CASE (CEE_PREFIX2)
2427                 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
2428                 /*
2429                  * Note: Exceptions thrown when executing a prefixed opcode need
2430                  * to take into account the number of prefix bytes (usually the
2431                  * throw point is just (ip - n_prefix_bytes).
2432                  */
2433                 SUB_SWITCH
2434                         ++ip;
2435                         switch (*ip) {
2436                         case CEE_ARGLIST: ves_abort(); break;
2437                         case CEE_CEQ: {
2438                                 gint32 result;
2439                                 ++ip;
2440                                 sp -= 2;
2441
2442                                 if (sp->type == VAL_I32)
2443                                         result = sp [0].data.i == GET_NATI (sp [1]);
2444                                 else if (sp->type == VAL_I64)
2445                                         result = sp [0].data.l == sp [1].data.l;
2446                                 else if (sp->type == VAL_DOUBLE)
2447                                         result = sp [0].data.f == sp [1].data.f;
2448                                 else
2449                                         result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
2450                                 sp->type = VAL_I32;
2451                                 sp->data.i = result;
2452
2453                                 sp++;
2454                                                 
2455                                 break;
2456                         }
2457                         case CEE_CGT: ves_abort(); break;
2458                         case CEE_CGT_UN: ves_abort(); break;
2459                         case CEE_CLT: ves_abort(); break;
2460                         case CEE_CLT_UN: ves_abort(); break;
2461                         case CEE_LDFTN: ves_abort(); break;
2462                         case CEE_LDVIRTFTN: ves_abort(); break;
2463                         case CEE_UNUSED56: ves_abort(); break;
2464                         case CEE_LDARG: {
2465                                 guint32 arg_pos;
2466                                 ++ip;
2467                                 arg_pos = read32 (ip);
2468                                 ip += 4;
2469                                 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
2470                                 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2471                                 ++sp;
2472                                 break;
2473                         }
2474                         case CEE_LDARGA: ves_abort(); break;
2475                         case CEE_STARG: {
2476                                 guint32 arg_pos;
2477                                 ++ip;
2478                                 arg_pos = read32 (ip);
2479                                 ip += 4;
2480                                 --sp;
2481                                 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2482                                 vt_free (sp);
2483                                 break;
2484                         }
2485                         case CEE_LDLOC: {
2486                                 guint32 loc_pos;
2487                                 ++ip;
2488                                 loc_pos = read32 (ip);
2489                                 ip += 4;
2490                                 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
2491                                 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2492                                 ++sp;
2493                                 break;
2494                         }
2495                         case CEE_LDLOCA: {
2496                                 MonoType *t;
2497                                 MonoClass *c;
2498                                 guint32 loc_pos;
2499
2500                                 ++ip;
2501                                 loc_pos = read32 (ip);
2502                                 ip += 4;
2503                                 t = LOCAL_TYPE (header, loc_pos);
2504                                 c =  mono_class_from_mono_type (t);
2505                                 sp->data.vt.vt = LOCAL_POS (loc_pos);
2506                                 sp->data.vt.klass = c;
2507
2508                                 if (c->valuetype) 
2509                                         sp->type = VAL_VALUETA;
2510                                 else
2511                                         sp->type = VAL_TP;
2512
2513                                 ++sp;
2514                                 break;
2515                         }
2516                         case CEE_STLOC: {
2517                                 guint32 loc_pos;
2518                                 ++ip;
2519                                 loc_pos = read32 (ip);
2520                                 ip += 4;
2521                                 --sp;
2522                                 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2523                                 vt_free (sp);
2524                                 break;
2525                         }
2526                         case CEE_LOCALLOC:
2527                                 if (sp != frame->stack)
2528                                         THROW_EX (get_exception_execution_engine (), ip - 1);
2529                                 ++ip;
2530                                 sp->data.p = alloca (sp->data.i);
2531                                 sp->type = VAL_TP;
2532                                 break;
2533                         case CEE_UNUSED57: ves_abort(); break;
2534                         case CEE_ENDFILTER: ves_abort(); break;
2535                         case CEE_UNALIGNED_:
2536                                 ++ip;
2537                                 unaligned_address = 1;
2538                                 break;
2539                         case CEE_VOLATILE_:
2540                                 ++ip;
2541                                 volatile_address = 1;
2542                                 break;
2543                         case CEE_TAIL_:
2544                                 ++ip;
2545                                 tail_recursion = 1;
2546                                 break;
2547                         case CEE_INITOBJ: {
2548                                 guint32 token;
2549                                 ++ip;
2550                                 token = read32 (ip);
2551                                 ip += 4;
2552                                 /*
2553                                  * we ignore the value of token (I think we can as unspecified
2554                                  * behavior described in Partition II, 3.5).
2555                                  */
2556                                 --sp;
2557                                 g_assert (sp->type = VAL_VALUETA);
2558                                 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
2559                                 break;
2560                         }
2561                         case CEE_UNUSED68: ves_abort(); break;
2562                         case CEE_CPBLK:
2563                                 sp -= 3;
2564                                 if (!sp [0].data.p || !sp [1].data.p)
2565                                         THROW_EX (get_exception_null_reference(), ip - 1);
2566                                 ++ip;
2567                                 /* FIXME: value and size may be int64... */
2568                                 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
2569                                 break;
2570                         case CEE_INITBLK:
2571                                 sp -= 3;
2572                                 if (!sp [0].data.p)
2573                                         THROW_EX (get_exception_null_reference(), ip - 1);
2574                                 ++ip;
2575                                 /* FIXME: value and size may be int64... */
2576                                 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
2577                                 break;
2578                         case CEE_UNUSED69: ves_abort(); break;
2579                         case CEE_RETHROW:
2580                                 /* 
2581                                  * need to clarify what this should actually do:
2582                                  * start the search from the last found handler in
2583                                  * this method or continue in the caller or what.
2584                                  * Also, do we need to run finally/fault handlers after a retrow?
2585                                  * Well, this implementation will follow the usual search
2586                                  * for an handler, considering the current ip as throw spot.
2587                                  * We need to NULL frame->ex_handler for the later code to
2588                                  * actually run the new found handler.
2589                                  */
2590                                 frame->ex_handler = NULL;
2591                                 THROW_EX (frame->ex, ip - 1);
2592                                 break;
2593                         case CEE_UNUSED: ves_abort(); break;
2594                         case CEE_SIZEOF: {
2595                                 guint32 token;
2596                                 MonoClass *c;
2597                                 ++ip;
2598                                 token = read32 (ip);
2599                                 ip += 4;
2600                                 c = mono_class_get (image, token);
2601                                 sp->type = VAL_I32;
2602                                 sp->data.i = mono_class_value_size (c, NULL);
2603                                 ++sp;
2604                                 break;
2605                         }
2606                         case CEE_REFANYTYPE: ves_abort(); break;
2607                         case CEE_UNUSED52: 
2608                         case CEE_UNUSED53: 
2609                         case CEE_UNUSED54: 
2610                         case CEE_UNUSED55: 
2611                         case CEE_UNUSED70: 
2612                         default:
2613                                 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
2614                         }
2615                         continue;
2616                 DEFAULT;
2617                 }
2618         }
2619
2620         g_assert_not_reached ();
2621         /*
2622          * Exception handling code.
2623          * The exception object is stored in frame->ex.
2624          */
2625 #define OFFSET_IN_CLAUSE(clause,offset) \
2626         ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
2627
2628         handle_exception:
2629         {
2630                 int i;
2631                 guint32 ip_offset;
2632                 MonoInvocation *inv;
2633                 MonoMethodHeader *hd;
2634                 MonoExceptionClause *clause;
2635                 
2636                 for (inv = frame; inv; inv = inv->parent) {
2637                         hd = ((MonoMethodNormal*)inv->method)->header;
2638                         ip_offset = inv->ip - hd->code;
2639                         for (i = 0; i < hd->num_clauses; ++i) {
2640                                 clause = &hd->clauses [i];
2641                                 if (clause->flags <= 1 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2642                                         if (!clause->flags) {
2643                                                         if (mono_object_isinst (frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
2644                                                                 /* 
2645                                                                  * OK, we found an handler, now we need to execute the finally
2646                                                                  * and fault blocks before branching to the handler code.
2647                                                                  */
2648                                                                 inv->ex_handler = clause;
2649                                                                 goto handle_finally;
2650                                                         }
2651                                         } else {
2652                                                 /* FIXME: handle filter clauses */
2653                                                 g_assert (0);
2654                                         }
2655                                 }
2656                         }
2657                 }
2658                 /*
2659                  * If we get here, no handler was found: print a stack trace.
2660                  */
2661                 g_print ("Unhandled exception %s.%s.\n", frame->ex->klass->name_space, frame->ex->klass->name);
2662                 for (inv = frame, i = 0; inv; inv = inv->parent, ++i) {
2663                         MonoClass *k = inv->method->klass;
2664                         MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
2665                         /*
2666                          * FIXME: print out also the arguments passed to the func.
2667                          */
2668                         g_print ("#%d: 0x%05x in %s.%s::%s (", i, inv->ip - hd->code, 
2669                                                         k->name_space, k->name, inv->method->name);
2670                         dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
2671                         g_print (")\n");
2672                 }
2673                 exit (1);
2674         }
2675         handle_finally:
2676         {
2677                 int i;
2678                 guint32 ip_offset;
2679                 MonoExceptionClause *clause;
2680                 
2681                 ip_offset = frame->ip - header->code;
2682                 for (i = 0; i < header->num_clauses; ++i) {
2683                         clause = &header->clauses [i];
2684                         if (clause->flags == 2 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2685                                 ip = header->code + clause->handler_offset;
2686                                 goto main_loop;
2687                         }
2688                 }
2689                 /*
2690                  * If an exception is set, we need to execute the fault handler, too,
2691                  * otherwise, we continue normally.
2692                  */
2693                 if (frame->ex)
2694                         goto handle_fault;
2695                 ip = endfinally_ip;
2696                 goto main_loop;
2697         }
2698         handle_fault:
2699         {
2700                 int i;
2701                 guint32 ip_offset;
2702                 MonoExceptionClause *clause;
2703                 
2704                 ip_offset = frame->ip - header->code;
2705                 for (i = 0; i < header->num_clauses; ++i) {
2706                         clause = &header->clauses [i];
2707                         if (clause->flags == 3 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2708                                 ip = header->code + clause->handler_offset;
2709                                 goto main_loop;
2710                         }
2711                 }
2712                 /*
2713                  * If the handler for the exception was found in this method, we jump
2714                  * to it right away, otherwise we return and let the caller run
2715                  * the finally, fault and catch blocks.
2716                  * This same code should be present in the endfault opcode, but it
2717                  * is corrently not assigned in the ECMA specs: LAMESPEC.
2718                  */
2719                 if (frame->ex_handler) {
2720                         ip = header->code + frame->ex_handler->handler_offset;
2721                         sp = frame->stack;
2722                         sp->type = VAL_OBJ;
2723                         sp->data.p = frame->ex;
2724                         ++sp;
2725                         goto main_loop;
2726                 }
2727                 DEBUG_LEAVE ();
2728                 return;
2729         }
2730         
2731 }
2732
2733 static int 
2734 ves_exec (MonoAssembly *assembly, int argc, char *argv[])
2735 {
2736         MonoImage *image = assembly->image;
2737         MonoCLIImageInfo *iinfo;
2738         stackval result;
2739         MonoInvocation call;
2740         MonoMethod *method;
2741
2742         iinfo = image->image_info;
2743         method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
2744
2745         if (method->signature->param_count) {
2746                 g_warning ("Main () with arguments not yet supported");
2747                 exit (1);
2748                 /*
2749                 int i;
2750                 stackval argv_array;
2751                 MonoObject *arr = mono_new_szarray (mono_defaults.corlib, mono_defaults.string_token, argc);
2752                 argv_array.type = VAL_OBJ;
2753                 argv_array.data.p = arr;
2754                 for (i=0; i < argc; ++i) {
2755                 }
2756                 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
2757                 */
2758         } else {
2759                 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
2760         }
2761         
2762         ves_exec_method (&call);
2763         mono_free_method (call.method);
2764
2765         return result.data.i;
2766 }
2767
2768 static void
2769 usage (void)
2770 {
2771         fprintf (stderr,
2772                  "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
2773                  "Usage is: mint [options] executable args...\n", VERSION);
2774         fprintf (stderr,
2775                  "Valid Options are:\n"
2776                  "--trace\n");
2777         exit (1);
2778 }
2779
2780 #ifdef RUN_TEST
2781 static void
2782 test_load_class (MonoImage* image)
2783 {
2784         MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEDEF];
2785         MonoClass *klass;
2786         int i;
2787
2788         for (i = 1; i <= t->rows; ++i) {
2789                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
2790                 mono_class_metadata_init (klass);
2791         }
2792 }
2793 #endif
2794
2795 int 
2796 main (int argc, char *argv [])
2797 {
2798         MonoAssembly *assembly;
2799         int retval = 0, i;
2800         char *file;
2801
2802         if (argc < 2)
2803                 usage ();
2804
2805         for (i = 1; argv [i][0] == '-'; i++){
2806                 if (strcmp (argv [i], "--trace") == 0)
2807                         tracing = 1;
2808         }
2809         
2810         file = argv [i];
2811
2812         mono_init ();
2813         mono_init_icall ();
2814
2815         assembly = mono_assembly_open (file, NULL, NULL);
2816         if (!assembly){
2817                 fprintf (stderr, "Can not open image %s\n", file);
2818                 exit (1);
2819         }
2820
2821 #ifdef RUN_TEST
2822         test_load_class (assembly->image);
2823 #else
2824         retval = ves_exec (assembly, argc, argv);
2825 #endif
2826         mono_assembly_close (assembly);
2827
2828         return retval;
2829 }
2830
2831
2832