Mon Nov 19 11:37:14 CET 2001 Paolo Molaro <lupus@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 <stdlib.h>
18 #include <glib.h>
19 #include <setjmp.h>
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/mono-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/metadata/threads.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/arch/x86/x86-codegen.h>
41 #include <mono/io-layer/io-layer.h>
42 /*#include <mono/cli/types.h>*/
43 #include "interp.h"
44 #include "hacks.h"
45
46
47 /* If true, then we output the opcodes as we interpret them */
48 static int tracing = 0;
49
50 static int debug_indent_level = 0;
51
52 /*
53  * Pull the list of opcodes
54  */
55 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
56         a = i,
57
58 enum {
59 #include "mono/cil/opcode.def"
60         LAST = 0xff
61 };
62 #undef OPDEF
63
64 /*
65  * Pull the opcode names
66  */
67 #define OPDEF(a,b,c,d,e,f,g,h,i,j)  b,
68 static char *opcode_names[] = {
69 #include "mono/cil/opcode.def"
70         NULL
71 };
72
73 #define GET_NATI(sp) ((sp).data.nati)
74 #define CSIZE(x) (sizeof (x) / 4)
75
76 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method)   \
77         do {    \
78                 (frame)->parent = (parent_frame);       \
79                 (frame)->obj = (obj_this);      \
80                 (frame)->stack_args = (method_args);    \
81                 (frame)->retval = (method_retval);      \
82                 (frame)->method = (mono_method);        \
83                 (frame)->ex_handler = NULL;     \
84                 (frame)->ex = NULL;     \
85                 (frame)->child = NULL;  \
86         } while (0)
87
88 void ves_exec_method (MonoInvocation *frame);
89
90 typedef void (*ICallMethod) (MonoInvocation *frame);
91
92 static guint32 frame_thread_id = 0;
93
94 static void
95 interp_ex_handler (MonoException *ex) {
96         MonoInvocation *frame = TlsGetValue (frame_thread_id);
97         frame->ex = ex;
98         longjmp (*(jmp_buf*)frame->locals, 1);
99 }
100
101 static void
102 ves_real_abort (int line, MonoMethod *mh,
103                 const unsigned char *ip, stackval *stack, stackval *sp)
104 {
105         MonoMethodNormal *mm = (MonoMethodNormal *)mh;
106         fprintf (stderr, "Execution aborted in method: %s\n", mh->name);
107         fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
108                  ip-mm->header->code);
109         g_print ("0x%04x %02x\n",
110                  ip-mm->header->code, *ip);
111         if (sp > stack)
112                 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
113 }
114 #define ves_abort() do {ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp); THROW_EX (get_exception_execution_engine (), ip);} while (0);
115
116 /*
117  * init_class:
118  * @klass: klass that needs to be initialized
119  *
120  * This routine calls the class constructor for @class if it needs it.
121  */
122 static void
123 init_class (MonoClass *klass)
124 {
125         MonoMethod *method;
126         MonoInvocation call;
127         int i;
128
129         if (!klass->metadata_inited)
130                 mono_class_metadata_init (klass);
131
132         if (klass->inited)
133                 return;
134
135         if (klass->parent && !klass->parent->inited)
136                 init_class (klass->parent);
137         
138         klass->inited = 1;
139
140         for (i = 0; i < klass->method.count; ++i) {
141                 method = klass->methods [i];
142                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) {
143                         INIT_FRAME (&call, NULL, NULL, NULL, NULL, method);
144         
145                         ves_exec_method (&call);
146                         return;
147                 }
148         }
149         /* No class constructor found */
150 }
151
152 static MonoMethod*
153 get_virtual_method (MonoMethod *m, stackval *objs)
154 {
155         MonoObject *obj;
156         MonoClass *klass;
157         MonoMethod **vtable;
158
159         if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
160                         return m;
161
162         g_assert (m->klass->metadata_inited);
163
164         obj = objs->data.p;
165         klass = obj->klass;
166         vtable = (MonoMethod **)klass->vtable;
167
168         if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
169                 return *(MonoMethod**)(klass->interface_offsets [m->klass->interface_id] + (m->slot<<2));
170
171         return vtable [m->slot];
172 }
173
174 static MonoObject*
175 get_named_exception (const char *name)
176 {
177         MonoClass *klass;
178         MonoInvocation call;
179         MonoMethod *method = NULL;
180         MonoObject *o;
181         int i;
182
183         klass = mono_class_from_name (mono_defaults.corlib, "System", name);
184
185         o = mono_object_new (klass);
186         g_assert (o != NULL);
187
188         for (i = 0; i < klass->method.count; ++i) {
189                 if (!strcmp (".ctor", klass->methods [i]->name) &&
190                     klass->methods [i]->signature->param_count == 0) {
191                         method = klass->methods [i];
192                         break;
193                 }
194         }
195
196         call.obj = o;
197
198         g_assert (method);
199         INIT_FRAME (&call, NULL, o, NULL, NULL, method);
200
201         ves_exec_method (&call);
202         return o;
203 }
204
205 static MonoObject*
206 get_exception_divide_by_zero ()
207 {
208         static MonoObject *ex = NULL;
209         if (ex)
210                 return ex;
211         ex = get_named_exception ("DivideByZeroException");
212         return ex;
213 }
214
215 static MonoObject*
216 get_exception_security ()
217 {
218         static MonoObject *ex = NULL;
219         if (ex)
220                 return ex;
221         ex = get_named_exception ("SecurityException");
222         return ex;
223 }
224
225 static MonoObject*
226 get_exception_arithmetic ()
227 {
228         static MonoObject *ex = NULL;
229         if (ex)
230                 return ex;
231         ex = get_named_exception ("ArithmeticException");
232         return ex;
233 }
234
235 static MonoObject*
236 get_exception_overflow ()
237 {
238         static MonoObject *ex = NULL;
239         if (ex)
240                 return ex;
241         ex = get_named_exception ("OverflowException");
242         return ex;
243 }
244
245 static MonoObject*
246 get_exception_null_reference ()
247 {
248         static MonoObject *ex = NULL;
249         if (ex)
250                 return ex;
251         ex = get_named_exception ("NullReferenceException");
252         return ex;
253 }
254
255 static MonoObject*
256 get_exception_execution_engine ()
257 {
258         static MonoObject *ex = NULL;
259         if (ex)
260                 return ex;
261         ex = get_named_exception ("ExecutionEngineException");
262         return ex;
263 }
264
265 static MonoObject*
266 get_exception_invalid_cast ()
267 {
268         static MonoObject *ex = NULL;
269         if (ex)
270                 return ex;
271         ex = get_named_exception ("InvalidCastException");
272         return ex;
273 }
274
275 static MonoObject*
276 get_exception_index_out_of_range ()
277 {
278         static MonoObject *ex = NULL;
279         if (ex)
280                 return ex;
281         ex = get_named_exception ("IndexOutOfRangeException");
282         return ex;
283 }
284
285 static MonoObject*
286 get_exception_array_type_mismatch ()
287 {
288         static MonoObject *ex = NULL;
289         if (ex)
290                 return ex;
291         ex = get_named_exception ("ArrayTypeMismatchException");
292         return ex;
293 }
294
295 static MonoObject*
296 get_exception_missing_method ()
297 {
298         static MonoObject *ex = NULL;
299         if (ex)
300                 return ex;
301         ex = get_named_exception ("MissingMethodException");
302         return ex;
303 }
304
305 void inline
306 stackval_from_data (MonoType *type, stackval *result, const char *data)
307 {
308         if (type->byref) {
309                 switch (type->type) {
310                 case MONO_TYPE_OBJECT:
311                 case MONO_TYPE_CLASS:
312                 case MONO_TYPE_STRING:
313                 case MONO_TYPE_ARRAY:
314                 case MONO_TYPE_SZARRAY:
315                         result->type = VAL_OBJ;
316                         break;
317                 default:
318                         result->type = VAL_VALUETA;
319                         break;
320                 }
321                 result->data.p = *(gpointer*)data;
322                 result->data.vt.klass = mono_class_from_mono_type (type);
323                 return;
324         }
325         switch (type->type) {
326         case MONO_TYPE_VOID:
327                 return;
328         case MONO_TYPE_I1:
329                 result->type = VAL_I32;
330                 result->data.i = *(gint8*)data;
331                 return;
332         case MONO_TYPE_U1:
333         case MONO_TYPE_BOOLEAN:
334                 result->type = VAL_I32;
335                 result->data.i = *(guint8*)data;
336                 return;
337         case MONO_TYPE_I2:
338                 result->type = VAL_I32;
339                 result->data.i = *(gint16*)data;
340                 return;
341         case MONO_TYPE_U2:
342         case MONO_TYPE_CHAR:
343                 result->type = VAL_I32;
344                 result->data.i = *(guint16*)data;
345                 return;
346         case MONO_TYPE_I4:
347                 result->type = VAL_I32;
348                 result->data.i = *(gint32*)data;
349                 return;
350         case MONO_TYPE_U:
351         case MONO_TYPE_I:
352                 result->type = VAL_TP;
353                 result->data.p = *(gpointer*)data;
354                 return;
355         case MONO_TYPE_U4:
356                 result->type = VAL_I32;
357                 result->data.i = *(guint32*)data;
358                 return;
359         case MONO_TYPE_R4:
360                 result->type = VAL_DOUBLE;
361                 result->data.f = *(float*)data;
362                 return;
363         case MONO_TYPE_I8:
364         case MONO_TYPE_U8:
365                 result->type = VAL_I64;
366                 result->data.l = *(gint64*)data;
367                 return;
368         case MONO_TYPE_R8:
369                 result->type = VAL_DOUBLE;
370                 result->data.f = *(double*)data;
371                 return;
372         case MONO_TYPE_STRING:
373         case MONO_TYPE_SZARRAY:
374         case MONO_TYPE_CLASS:
375         case MONO_TYPE_OBJECT:
376         case MONO_TYPE_ARRAY:
377         case MONO_TYPE_PTR:
378                 result->type = VAL_OBJ;
379                 result->data.p = *(gpointer*)data;
380                 result->data.vt.klass = mono_class_from_mono_type (type);
381                 return;
382         case MONO_TYPE_VALUETYPE:
383                 if (type->data.klass->enumtype) {
384                         return stackval_from_data (type->data.klass->enum_basetype, result, data);
385                 } else {
386                         result->type = VAL_VALUET;
387                         result->data.vt.klass = type->data.klass;
388                         memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
389                 }
390                 return;
391         default:
392                 g_warning ("got type 0x%02x", type->type);
393                 g_assert_not_reached ();
394         }
395 }
396
397 static void inline
398 stackval_to_data (MonoType *type, stackval *val, char *data)
399 {
400         if (type->byref) {
401                 gpointer *p = (gpointer*)data;
402                 *p = val->data.p;
403                 return;
404         }
405         switch (type->type) {
406         case MONO_TYPE_I1:
407         case MONO_TYPE_U1: {
408                 guint8 *p = (guint8*)data;
409                 *p = val->data.i;
410                 return;
411         }
412         case MONO_TYPE_BOOLEAN: {
413                 guint8 *p = (guint8*)data;
414                 *p = (val->data.i != 0);
415                 return;
416         }
417         case MONO_TYPE_I2:
418         case MONO_TYPE_U2:
419         case MONO_TYPE_CHAR: {
420                 guint16 *p = (guint16*)data;
421                 *p = val->data.i;
422                 return;
423         }
424 #if SIZEOF_VOID_P == 4
425         case MONO_TYPE_I:
426         case MONO_TYPE_U:
427 #endif
428         case MONO_TYPE_I4:
429         case MONO_TYPE_U4: {
430                 gint32 *p = (gint32*)data;
431                 *p = val->data.i;
432                 return;
433         }
434 #if SIZEOF_VOID_P == 8
435         case MONO_TYPE_I:
436         case MONO_TYPE_U:
437 #endif
438         case MONO_TYPE_I8:
439         case MONO_TYPE_U8: {
440                 gint64 *p = (gint64*)data;
441                 *p = val->data.l;
442                 return;
443         }
444         case MONO_TYPE_R4: {
445                 float *p = (float*)data;
446                 *p = val->data.f;
447                 return;
448         }
449         case MONO_TYPE_R8: {
450                 double *p = (double*)data;
451                 *p = val->data.f;
452                 return;
453         }
454         case MONO_TYPE_STRING:
455         case MONO_TYPE_SZARRAY:
456         case MONO_TYPE_CLASS:
457         case MONO_TYPE_OBJECT:
458         case MONO_TYPE_ARRAY:
459         case MONO_TYPE_PTR: {
460                 gpointer *p = (gpointer*)data;
461                 *p = val->data.p;
462                 return;
463         }
464         case MONO_TYPE_VALUETYPE:
465                 if (type->data.klass->enumtype) {
466                         return stackval_to_data (type->data.klass->enum_basetype, val, data);
467                 } else {
468                         memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
469                 }
470                 return;
471         default:
472                 g_warning ("got type %x", type->type);
473                 g_assert_not_reached ();
474         }
475 }
476
477 static MonoObject*
478 ves_array_create (MonoClass *klass, MonoMethodSignature *sig, stackval *values)
479 {
480         guint32 *lengths;
481         guint32 *lower_bounds;
482         int i;
483
484         lengths = alloca (sizeof (guint32) * klass->rank * 2);
485         for (i = 0; i < sig->param_count; ++i) {
486                 lengths [i] = values->data.i;
487                 values ++;
488         }
489         if (klass->rank == sig->param_count) {
490                 /* Only lengths provided. */
491                 lower_bounds = NULL;
492         } else {
493                 /* lower bounds are first. */
494                 lower_bounds = lengths;
495                 lengths += klass->rank;
496         }
497         return (MonoObject*)mono_array_new_full (klass, lengths, lower_bounds);
498 }
499
500 static void 
501 ves_array_set (MonoInvocation *frame)
502 {
503         stackval *sp = frame->stack_args;
504         MonoObject *o;
505         MonoArray *ao;
506         MonoClass *ac;
507         gint32 i, t, pos, esize;
508         gpointer ea;
509         MonoType *mt;
510
511         o = frame->obj;
512         ao = (MonoArray *)o;
513         ac = o->klass;
514
515         g_assert (ac->rank >= 1);
516
517         pos = sp [0].data.i - ao->bounds [0].lower_bound;
518         for (i = 1; i < ac->rank; i++) {
519                 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
520                     ao->bounds [i].length) {
521                         g_warning ("wrong array index");
522                         g_assert_not_reached ();
523                 }
524                 pos = pos*ao->bounds [i].length + sp [i].data.i - 
525                         ao->bounds [i].lower_bound;
526         }
527
528         esize = mono_array_element_size (ac);
529         ea = mono_array_addr_with_size (ao, esize, pos);
530
531         mt = frame->method->signature->params [ac->rank];
532         stackval_to_data (mt, &sp [ac->rank], ea);
533 }
534
535 static void 
536 ves_array_get (MonoInvocation *frame)
537 {
538         stackval *sp = frame->stack_args;
539         MonoObject *o;
540         MonoArray *ao;
541         MonoClass *ac;
542         gint32 i, pos, esize;
543         gpointer ea;
544         MonoType *mt;
545
546         o = frame->obj;
547         ao = (MonoArray *)o;
548         ac = o->klass;
549
550         g_assert (ac->rank >= 1);
551
552         pos = sp [0].data.i - ao->bounds [0].lower_bound;
553         for (i = 1; i < ac->rank; i++)
554                 pos = pos*ao->bounds [i].length + sp [i].data.i - 
555                         ao->bounds [i].lower_bound;
556
557         esize = mono_array_element_size (ac);
558         ea = mono_array_addr_with_size (ao, esize, pos);
559
560         mt = frame->method->signature->ret;
561         stackval_from_data (mt, frame->retval, ea);
562 }
563
564 static void 
565 ves_pinvoke_method (MonoInvocation *frame)
566 {
567         jmp_buf env;
568         volatile MonoPIFunc func = mono_create_trampoline (frame->method);
569         if (setjmp(env)) {
570                 g_free ((void*)func);
571                 return;
572         }
573         /* 
574          * frame->locals and args are unused for P/Invoke methods, so we reuse them. 
575          * locals will point to the jmp_buf, while args will point to the previous
576          * MonoInvocation frame: this is needed to make exception searching work across
577          * managed/unmanaged boundaries.
578          */
579         frame->locals = (char*)&env;
580         frame->args = (char*)TlsGetValue (frame_thread_id);
581         TlsSetValue (frame_thread_id, frame);
582
583         func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
584         stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
585         g_free ((void*)func);
586 }
587
588 /*
589  * From the spec:
590  * runtime specifies that the implementation of the method is automatically
591  * provided by the runtime and is primarily used for the methods of delegates.
592  */
593 static void
594 ves_runtime_method (MonoInvocation *frame)
595 {
596         const char *name = frame->method->name;
597         MonoObject *obj = (MonoObject*)frame->obj;
598         MonoDelegate *delegate = (MonoDelegate*)frame->obj;
599
600         init_class(mono_defaults.delegate_class);
601         
602         if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
603                         mono_object_isinst (obj, mono_defaults.delegate_class)) {
604                 delegate->target = frame->stack_args[0].data.p;
605                 delegate->method_ptr = frame->stack_args[1].data.p;
606                 return;
607         }
608         if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
609                         mono_object_isinst (obj, mono_defaults.delegate_class)) {
610                 MonoPIFunc func = mono_create_trampoline (frame->method);
611                 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
612                 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, delegate->target, frame->stack_args);
613                 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
614                 g_free ((void*)func);
615                 return;
616         }
617         g_error ("Don't know how to exec runtime method %s.%s::%s", 
618                         frame->method->klass->name_space, frame->method->klass->name,
619                         frame->method->name);
620 }
621
622 static void
623 dump_stack (stackval *stack, stackval *sp)
624 {
625         stackval *s = stack;
626         
627         if (sp == stack)
628                 return;
629         
630         while (s < sp) {
631                 switch (s->type) {
632                 case VAL_I32: printf ("[%d] ", s->data.i); break;
633                 case VAL_I64: printf ("[%lld] ", s->data.l); break;
634                 case VAL_DOUBLE: printf ("[%0.5f] ", s->data.f); break;
635                 case VAL_VALUET: printf ("[vt: %p] ", s->data.vt.vt); break;
636 #if 0
637                 case VAL_OBJ: {
638                         MonoObject *obj =  s->data.p;
639                         if (obj && obj->klass == mono_defaults.string_class) {
640                                 char *str = mono_string_to_utf8 ((MonoString*)obj);
641                                 printf ("\"%s\" ", str);
642                                 g_free (str);
643                                 break;
644                         }
645                 }
646 #endif
647                 default: printf ("[%p] ", s->data.p); break;
648                 }
649                 ++s;
650         }
651 }
652
653 static void
654 dump_frame (MonoInvocation *inv)
655 {
656         int i;
657         for (i = 0; inv; inv = inv->parent, ++i) {
658                 MonoClass *k = inv->method->klass;
659                 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
660                 g_print ("#%d: 0x%05x in %s.%s::%s (", i, inv->ip - hd->code, 
661                                                 k->name_space, k->name, inv->method->name);
662                 dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
663                 g_print (")\n");
664         }
665 }
666
667 #define DEBUG_INTERP 1
668 #if DEBUG_INTERP
669
670 static unsigned long opcode_count = 0;
671 static unsigned long fcall_count = 0;
672 static int break_on_method = 0;
673 static GList *db_methods = NULL;
674
675 static void
676 output_indent (void)
677 {
678         int h;
679
680         for (h = 0; h < debug_indent_level; h++)
681                 g_print ("  ");
682 }
683
684 static void
685 db_match_method (gpointer data, gpointer user_data)
686 {
687         /*
688          * Make this function smarter (accept Class:method...)
689          */
690         if (strcmp((char*)data, (char*)user_data) == 0)
691                 break_on_method = 1;
692 }
693
694 #define DEBUG_ENTER()   \
695         fcall_count++;  \
696         g_list_foreach (db_methods, db_match_method, (gpointer)frame->method->name);    \
697         if (break_on_method) G_BREAKPOINT ();   \
698         break_on_method = 0;    \
699         if (tracing) {  \
700                 MonoClass *klass = frame->method->klass;        \
701                 debug_indent_level++;   \
702                 output_indent ();       \
703                 g_print ("Entering %s.%s::%s\n", klass->name_space, klass->name, frame->method->name);  \
704         } 
705 #define DEBUG_LEAVE()   \
706         if (tracing) {  \
707                 MonoClass *klass = frame->method->klass;        \
708                 output_indent ();       \
709                 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name);   \
710                 debug_indent_level--;   \
711         } 
712
713 #else
714
715 #define DEBUG_ENTER()
716 #define DEBUG_LEAVE()
717
718 #endif
719
720 #define LOCAL_POS(n)            (locals_pointers [(n)])
721 #define LOCAL_TYPE(header, n)   ((header)->locals [(n)])
722
723 #define ARG_POS(n)              (args_pointers [(n)])
724 #define ARG_TYPE(sig, n)        ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
725                                 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
726
727 #define THROW_EX(exception,ex_ip)       \
728                 do {\
729                         frame->ip = (ex_ip);            \
730                         frame->ex = (MonoException*)(exception);        \
731                         goto handle_exception;  \
732                 } while (0)
733
734 typedef struct _vtallocation vtallocation;
735
736 struct _vtallocation {
737         vtallocation *next;
738         guint32 size;
739         char data [MONO_ZERO_LEN_ARRAY];
740 };
741
742 /*
743  * we don't use vtallocation->next, yet
744  */
745 #define vt_alloc(vtype,sp)      \
746         if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) {   \
747                 if (!(vtype)->byref) {  \
748                         guint32 align;  \
749                         guint32 size = mono_class_value_size ((vtype)->data.klass, &align);     \
750                         if (!vtalloc || vtalloc->size < size) { \
751                                 vtalloc = alloca (sizeof (vtallocation) + size);        \
752                                 vtalloc->size = size;   \
753                         }       \
754                         (sp)->data.vt.vt = vtalloc->data;       \
755                         vtalloc = NULL; \
756                 } else {        \
757                         (sp)->data.vt.klass = (vtype)->data.klass;      \
758                 }       \
759         }
760
761 #define vt_free(sp)     \
762         do {    \
763                 if ((sp)->type == VAL_VALUET) { \
764                         vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data));    \
765                 }       \
766         } while (0)
767
768 /*
769  * Need to optimize ALU ops when natural int == int32 
770  *
771  * IDEA: if we maintain a stack of ip, sp to be checked
772  * in the return opcode, we could inline simple methods that don't
773  * use the stack or local variables....
774  * 
775  * The {,.S} versions of many opcodes can/should be merged to reduce code
776  * duplication.
777  * 
778  */
779 void 
780 ves_exec_method (MonoInvocation *frame)
781 {
782         MonoInvocation child_frame;
783         MonoMethodHeader *header;
784         MonoMethodSignature *signature;
785         MonoImage *image;
786         const unsigned char *endfinally_ip;
787         register const unsigned char *ip;
788         register stackval *sp;
789         void **locals_pointers;
790         void **args_pointers;
791         unsigned char tail_recursion = 0;
792         unsigned char unaligned_address = 0;
793         unsigned char volatile_address = 0;
794         vtallocation *vtalloc = NULL;
795         GOTO_LABEL_VARS;
796
797         if (!frame->method->klass->inited)
798                 init_class (frame->method->klass);
799
800         DEBUG_ENTER ();
801
802         if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
803                 if (!frame->method->addr) {
804                         frame->ex = (MonoException*)get_exception_missing_method ();
805                         DEBUG_LEAVE ();
806                         return;
807                 }
808                 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
809                         ves_pinvoke_method (frame);
810                 } else {
811                         ICallMethod icall = (ICallMethod)frame->method->addr;
812                         icall (frame);
813                 }
814                 DEBUG_LEAVE ();
815                 return;
816         } 
817
818         if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
819                 if (!frame->method->addr) {
820                         frame->ex = (MonoException*)get_exception_missing_method ();
821                         DEBUG_LEAVE ();
822                         return;
823                 }
824                 ves_pinvoke_method (frame);
825                 DEBUG_LEAVE ();
826                 return;
827         } 
828
829         if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
830                 ves_runtime_method (frame);
831                 DEBUG_LEAVE ();
832                 return;
833         } 
834
835         header = ((MonoMethodNormal *)frame->method)->header;
836         signature = frame->method->signature;
837         image = frame->method->klass->image;
838
839         /*
840          * with alloca we get the expected huge performance gain
841          * stackval *stack = g_new0(stackval, header->max_stack);
842          */
843
844         sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
845
846         if (header->num_locals) {
847                 int i, align, size, offset = 0;
848
849                 frame->locals = alloca (header->locals_size);
850                 locals_pointers = alloca (sizeof(void*) * header->num_locals);
851                 /* 
852                  * yes, we do it unconditionally, because it needs to be done for
853                  * some cases anyway and checking for that would be even slower.
854                  */
855                 memset (frame->locals, 0, header->locals_size);
856                 for (i = 0; i < header->num_locals; ++i) {
857                         locals_pointers [i] = frame->locals + offset;
858                         size = mono_type_size (header->locals [i], &align);
859                         offset += align - 1;
860                         offset &= ~(align - 1);
861                         offset += size;
862                 }
863         }
864         /*
865          * Copy args from stack_args to args.
866          */
867         if (signature->params_size) {
868                 int i, align, size, offset = 0;
869                 int has_this = signature->hasthis;
870
871                 frame->args = alloca (signature->params_size);
872                 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
873                 if (has_this) {
874                         gpointer *this_arg;
875                         this_arg = args_pointers [0] = frame->args;
876                         *this_arg = frame->obj;
877                         offset += sizeof (gpointer);
878                 }
879                 for (i = 0; i < signature->param_count; ++i) {
880                         args_pointers [i + has_this] = frame->args + offset;
881                         stackval_to_data (signature->params [i], frame->stack_args + i, frame->args + offset);
882                         size = mono_type_size (signature->params [i], &align);
883                         offset += align - 1;
884                         offset &= ~(align - 1);
885                         offset += size;
886                 }
887         }
888
889         child_frame.parent = frame;
890         frame->child = &child_frame;
891         frame->ex = NULL;
892
893         /* ready to go */
894         ip = header->code;
895
896         /*
897          * using while (ip < end) may result in a 15% performance drop, 
898          * but it may be useful for debug
899          */
900         while (1) {
901         main_loop:
902                 /*g_assert (sp >= stack);*/
903 #if DEBUG_INTERP
904                 opcode_count++;
905                 if (tracing){
906                         output_indent ();
907                         g_print ("stack: ");
908                         dump_stack (frame->stack, sp);
909                         g_print ("\n");
910                         output_indent ();
911                         g_print ("0x%04x: %s\n", ip-header->code,
912                                  *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
913                 }
914 #endif
915                 
916                 SWITCH (*ip) {
917                 CASE (CEE_NOP) 
918                         ++ip;
919                         BREAK;
920                 CASE (CEE_BREAK)
921                         ++ip;
922                         G_BREAKPOINT (); /* this is not portable... */
923                         BREAK;
924                 CASE (CEE_LDARG_0)
925                 CASE (CEE_LDARG_1)
926                 CASE (CEE_LDARG_2)
927                 CASE (CEE_LDARG_3) {
928                         int n = (*ip)-CEE_LDARG_0;
929                         ++ip;
930                         vt_alloc (ARG_TYPE (signature, n), sp);
931                         stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
932                         ++sp;
933                         BREAK;
934                 }
935                 CASE (CEE_LDLOC_0)
936                 CASE (CEE_LDLOC_1)
937                 CASE (CEE_LDLOC_2)
938                 CASE (CEE_LDLOC_3) {
939                         int n = (*ip)-CEE_LDLOC_0;
940                         ++ip;
941                         if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
942                                 sp->type = VAL_I32;
943                                 sp->data.i = *(gint32*) LOCAL_POS (n);
944                                 ++sp;
945                                 BREAK;
946                         } else {
947                                 vt_alloc (LOCAL_TYPE (header, n), sp);
948                                 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
949                         }
950                         ++sp;
951                         BREAK;
952                 }
953                 CASE (CEE_STLOC_0)
954                 CASE (CEE_STLOC_1)
955                 CASE (CEE_STLOC_2)
956                 CASE (CEE_STLOC_3) {
957                         int n = (*ip)-CEE_STLOC_0;
958                         ++ip;
959                         --sp;
960                         if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
961                                 gint32 *p = (gint32*)LOCAL_POS (n);
962                                 *p = sp->data.i;
963                                 BREAK;
964                         } else {
965                                 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
966                                 vt_free (sp);
967                                 BREAK;
968                         }
969                 }
970                 CASE (CEE_LDARG_S)
971                         ++ip;
972                         vt_alloc (ARG_TYPE (signature, *ip), sp);
973                         stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
974                         ++sp;
975                         ++ip;
976                         BREAK;
977                 CASE (CEE_LDARGA_S) {
978                         MonoType *t;
979                         MonoClass *c;
980
981                         ++ip;
982                         t = ARG_TYPE (signature, *ip);
983                         c = mono_class_from_mono_type (t);
984                         sp->data.vt.klass = c;
985                         sp->data.vt.vt = ARG_POS (*ip);
986
987                         if (c->valuetype)
988                                 sp->type = VAL_VALUETA;
989                         else
990                                 sp->type = VAL_TP;
991
992                         ++sp;
993                         ++ip;
994                         BREAK;
995                 }
996                 CASE (CEE_STARG_S)
997                         ++ip;
998                         --sp;
999                         stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1000                         vt_free (sp);
1001                         ++ip;
1002                         BREAK;
1003                 CASE (CEE_LDLOC_S)
1004                         ++ip;
1005                         vt_alloc (LOCAL_TYPE (header, *ip), sp);
1006                         stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1007                         ++ip;
1008                         ++sp;
1009                         BREAK;
1010                 CASE (CEE_LDLOCA_S) {
1011                         MonoType *t;
1012                         MonoClass *c;
1013
1014                         ++ip;
1015                         t = LOCAL_TYPE (header, *ip);
1016                         c =  mono_class_from_mono_type (t);
1017                         sp->data.vt.klass = c;
1018                         sp->data.p = LOCAL_POS (*ip);
1019
1020                         if (c->valuetype)
1021                                 sp->type = VAL_VALUETA;
1022                         else 
1023                                 sp->type = VAL_TP;
1024
1025                         ++sp;
1026                         ++ip;
1027                         BREAK;
1028                 }
1029                 CASE (CEE_STLOC_S)
1030                         ++ip;
1031                         --sp;
1032                         stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1033                         vt_free (sp);
1034                         ++ip;
1035                         BREAK;
1036                 CASE (CEE_LDNULL) 
1037                         ++ip;
1038                         sp->type = VAL_OBJ;
1039                         sp->data.p = NULL;
1040                         sp->data.vt.klass = NULL;
1041                         ++sp;
1042                         BREAK;
1043                 CASE (CEE_LDC_I4_M1)
1044                         ++ip;
1045                         sp->type = VAL_I32;
1046                         sp->data.i = -1;
1047                         ++sp;
1048                         BREAK;
1049                 CASE (CEE_LDC_I4_0)
1050                 CASE (CEE_LDC_I4_1)
1051                 CASE (CEE_LDC_I4_2)
1052                 CASE (CEE_LDC_I4_3)
1053                 CASE (CEE_LDC_I4_4)
1054                 CASE (CEE_LDC_I4_5)
1055                 CASE (CEE_LDC_I4_6)
1056                 CASE (CEE_LDC_I4_7)
1057                 CASE (CEE_LDC_I4_8)
1058                         sp->type = VAL_I32;
1059                         sp->data.i = (*ip) - CEE_LDC_I4_0;
1060                         ++sp;
1061                         ++ip;
1062                         BREAK;
1063                 CASE (CEE_LDC_I4_S) 
1064                         ++ip;
1065                         sp->type = VAL_I32;
1066                         sp->data.i = *(gint8 *)ip;
1067                         ++ip;
1068                         ++sp;
1069                         BREAK;
1070                 CASE (CEE_LDC_I4)
1071                         ++ip;
1072                         sp->type = VAL_I32;
1073                         sp->data.i = read32 (ip);
1074                         ip += 4;
1075                         ++sp;
1076                         BREAK;
1077                 CASE (CEE_LDC_I8)
1078                         ++ip;
1079                         sp->type = VAL_I64;
1080                         sp->data.i = read64 (ip);
1081                         ip += 8;
1082                         ++sp;
1083                         BREAK;
1084                 CASE (CEE_LDC_R4) {
1085                         float val;
1086                         ++ip;
1087                         sp->type = VAL_DOUBLE;
1088                         readr4 (ip, &val);
1089                         sp->data.f = val;
1090                         ip += 4;
1091                         ++sp;
1092                         BREAK;
1093                 }
1094                 CASE (CEE_LDC_R8) 
1095                         ++ip;
1096                         sp->type = VAL_DOUBLE;
1097                         readr8(ip, &sp->data.f);
1098                         ip += 8;
1099                         ++sp;
1100                         BREAK;
1101                 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1102                 CASE (CEE_DUP) 
1103                         if (sp [-1].type == VAL_VALUET) {
1104                                 MonoClass *c = sp [-1].data.vt.klass;
1105                                 vt_alloc (&c->byval_arg, sp);
1106                                 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1107                         } else {
1108                                 *sp = sp [-1]; 
1109                         }
1110                         ++sp; 
1111                         ++ip; 
1112                         BREAK;
1113                 CASE (CEE_POP)
1114                         ++ip;
1115                         --sp;
1116                         vt_free (sp);
1117                         BREAK;
1118                 CASE (CEE_JMP) ves_abort(); BREAK;
1119                 CASE (CEE_CALLVIRT) /* Fall through */
1120                 CASE (CEE_CALLI)    /* Fall through */
1121                 CASE (CEE_CALL) {
1122                         MonoMethodSignature *csignature;
1123                         stackval retval;
1124                         stackval *endsp = sp;
1125                         guint32 token;
1126                         int virtual = *ip == CEE_CALLVIRT;
1127                         int calli = *ip == CEE_CALLI;
1128
1129                         /*
1130                          * We ignore tail recursion for now.
1131                          */
1132                         tail_recursion = 0;
1133
1134                         frame->ip = ip;
1135                         
1136                         ++ip;
1137                         token = read32 (ip);
1138                         ip += 4;
1139                         if (calli) {
1140                                 unsigned char *code;
1141                                 --sp;
1142                                 code = sp->data.p;
1143                                 /* check the signature we put in mono_create_method_pointer () */
1144                                 g_assert (code [2] == 'M' && code [3] == 'o');
1145                                 child_frame.method = *(gpointer*)(code + sizeof (gpointer));
1146                                 csignature = child_frame.method->signature;
1147                         } else {
1148                                 child_frame.method = mono_get_method (image, token, NULL);
1149                                 if (!child_frame.method)
1150                                         THROW_EX (get_exception_missing_method (), ip -5);
1151                                 csignature = child_frame.method->signature;
1152                                 if (virtual) {
1153                                         stackval *this_arg = &sp [-csignature->param_count-1];
1154                                         if (!this_arg->data.p)
1155                                                 THROW_EX (get_exception_null_reference(), ip - 5);
1156                                         child_frame.method = get_virtual_method (child_frame.method, this_arg);
1157                                 }
1158                         }
1159                         g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1160                         /* decrement by the actual number of args */
1161                         if (csignature->param_count) {
1162                                 sp -= csignature->param_count;
1163                                 child_frame.stack_args = sp;
1164                         } else {
1165                                 child_frame.stack_args = NULL;
1166                         }
1167                         if (csignature->hasthis) {
1168                                 g_assert (sp >= frame->stack);
1169                                 --sp;
1170                                 /*
1171                                  * It may also be a TP from LD(S)FLDA
1172                                  * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1173                                  */
1174                                 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1175                                         child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1176                                 else
1177                                         child_frame.obj = sp->data.p;
1178                         } else {
1179                                 child_frame.obj = NULL;
1180                         }
1181                         if (csignature->ret->type != MONO_TYPE_VOID) {
1182                                 vt_alloc (csignature->ret, &retval);
1183                                 child_frame.retval = &retval;
1184                         } else {
1185                                 child_frame.retval = NULL;
1186                         }
1187
1188                         child_frame.ex = NULL;
1189                         child_frame.ex_handler = NULL;
1190
1191                         ves_exec_method (&child_frame);
1192
1193                         while (endsp > sp) {
1194                                 --endsp;
1195                                 vt_free (endsp);
1196                         }
1197
1198                         if (child_frame.ex) {
1199                                 /*
1200                                  * An exception occurred, need to run finally, fault and catch handlers..
1201                                  */
1202                                 frame->ex = child_frame.ex;
1203                                 goto handle_finally;
1204                         }
1205
1206                         /* need to handle typedbyref ... */
1207                         if (csignature->ret->type != MONO_TYPE_VOID) {
1208                                 *sp = retval;
1209                                 sp++;
1210                         }
1211                         BREAK;
1212                 }
1213                 CASE (CEE_RET)
1214                         if (signature->ret->type != MONO_TYPE_VOID) {
1215                                 --sp;
1216                                 if (sp->type == VAL_VALUET) {
1217                                         /* the caller has already allocated the memory */
1218                                         stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1219                                         vt_free (sp);
1220                                 } else {
1221                                         *frame->retval = *sp;
1222                                 }
1223                         }
1224                         if (sp > frame->stack)
1225                                 g_warning ("more values on stack: %d", sp-frame->stack);
1226
1227                         DEBUG_LEAVE ();
1228                         return;
1229                 CASE (CEE_BR_S) /* Fall through */
1230                 CASE (CEE_BR)
1231                         if (*ip == CEE_BR) {
1232                                 ++ip;
1233                                 ip += (gint32) read32(ip);
1234                                 ip += 4;
1235                         } else {
1236                                 ++ip;
1237                                 ip += (signed char) *ip;
1238                                 ++ip;
1239                         }
1240                         BREAK;
1241                 CASE (CEE_BRFALSE) /* Fall through */
1242                 CASE (CEE_BRFALSE_S) {
1243                         int result;
1244                         int near_jump = *ip == CEE_BRFALSE_S;
1245                         ++ip;
1246                         --sp;
1247                         switch (sp->type) {
1248                         case VAL_I32: result = sp->data.i == 0; break;
1249                         case VAL_I64: result = sp->data.l == 0; break;
1250                         case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1251                         default: result = sp->data.p == NULL; break;
1252                         }
1253                         if (result) {
1254                                 if (near_jump)
1255                                         ip += (signed char)*ip;
1256                                 else
1257                                         ip += (gint32) read32 (ip);
1258                         }
1259                         ip += near_jump ? 1: 4;
1260                         BREAK;
1261                 }
1262                 CASE (CEE_BRTRUE) /* Fall through */
1263                 CASE (CEE_BRTRUE_S) {
1264                         int result;
1265                         int near_jump = *ip == CEE_BRTRUE_S;
1266                         ++ip;
1267                         --sp;
1268                         switch (sp->type) {
1269                         case VAL_I32: result = sp->data.i != 0; break;
1270                         case VAL_I64: result = sp->data.l != 0; break;
1271                         case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1272                         default: result = sp->data.p != NULL; break;
1273                         }
1274                         if (result) {
1275                                 if (near_jump)
1276                                         ip += (signed char)*ip;
1277                                 else
1278                                         ip += (gint32) read32 (ip);
1279                         }
1280                         ip += near_jump ? 1: 4;
1281                         BREAK;
1282                 }
1283                 CASE (CEE_BEQ) /* Fall through */
1284                 CASE (CEE_BEQ_S) {
1285                         int result;
1286                         int near_jump = *ip == CEE_BEQ_S;
1287                         ++ip;
1288                         sp -= 2;
1289                         if (sp->type == VAL_I32)
1290                                 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1291                         else if (sp->type == VAL_I64)
1292                                 result = sp [0].data.l == sp [1].data.l;
1293                         else if (sp->type == VAL_DOUBLE)
1294                                 result = sp [0].data.f == sp [1].data.f;
1295                         else
1296                                 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1297                         if (result) {
1298                                 if (near_jump)
1299                                         ip += (signed char)*ip;
1300                                 else
1301                                         ip += (gint32) read32 (ip);
1302                         }
1303                         ip += near_jump ? 1: 4;
1304                         BREAK;
1305                 }
1306                 CASE (CEE_BGE) /* Fall through */
1307                 CASE (CEE_BGE_S) {
1308                         int result;
1309                         int near_jump = *ip == CEE_BGE_S;
1310                         ++ip;
1311                         sp -= 2;
1312                         if (sp->type == VAL_I32)
1313                                 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1314                         else if (sp->type == VAL_I64)
1315                                 result = sp [0].data.l >= sp [1].data.l;
1316                         else if (sp->type == VAL_DOUBLE)
1317                                 result = sp [0].data.f >= sp [1].data.f;
1318                         else
1319                                 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1320                         if (result) {
1321                                 if (near_jump)
1322                                         ip += (signed char)*ip;
1323                                 else
1324                                         ip += (gint32) read32 (ip);
1325                         }
1326                         ip += near_jump ? 1: 4;
1327                         BREAK;
1328                 }
1329                 CASE (CEE_BGT) /* Fall through */
1330                 CASE (CEE_BGT_S) {
1331                         int result;
1332                         int near_jump = *ip == CEE_BGT_S;
1333                         ++ip;
1334                         sp -= 2;
1335                         if (sp->type == VAL_I32)
1336                                 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1337                         else if (sp->type == VAL_I64)
1338                                 result = sp [0].data.l > sp [1].data.l;
1339                         else if (sp->type == VAL_DOUBLE)
1340                                 result = sp [0].data.f > sp [1].data.f;
1341                         else
1342                                 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1343                         if (result) {
1344                                 if (near_jump)
1345                                         ip += (signed char)*ip;
1346                                 else
1347                                         ip += (gint32) read32 (ip);
1348                         }
1349                         ip += near_jump ? 1: 4;
1350                         BREAK;
1351                 }
1352                 CASE (CEE_BLT) /* Fall through */
1353                 CASE (CEE_BLT_S) {
1354                         int result;
1355                         int near_jump = *ip == CEE_BLT_S;
1356                         ++ip;
1357                         sp -= 2;
1358                         if (sp->type == VAL_I32)
1359                                 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1360                         else if (sp->type == VAL_I64)
1361                                 result = sp[0].data.l < sp[1].data.l;
1362                         else if (sp->type == VAL_DOUBLE)
1363                                 result = sp[0].data.f < sp[1].data.f;
1364                         else
1365                                 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1366                         if (result) {
1367                                 if (near_jump)
1368                                         ip += 1 + (signed char)*ip;
1369                                 else
1370                                         ip += 4 + (gint32) read32 (ip);
1371                                 BREAK;
1372                         } else {
1373                                 ip += near_jump ? 1: 4;
1374                                 BREAK;
1375                         }
1376                 }
1377                 CASE (CEE_BLE) /* fall through */
1378                 CASE (CEE_BLE_S) {
1379                         int result;
1380                         int near_jump = *ip == CEE_BLE_S;
1381                         ++ip;
1382                         sp -= 2;
1383
1384                         if (sp->type == VAL_I32)
1385                                 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1386                         else if (sp->type == VAL_I64)
1387                                 result = sp [0].data.l <= sp [1].data.l;
1388                         else if (sp->type == VAL_DOUBLE)
1389                                 result = sp [0].data.f <= sp [1].data.f;
1390                         else {
1391                                 /*
1392                                  * FIXME: here and in other places GET_NATI on the left side 
1393                                  * _will_ be wrong when we change the macro to work on 64 bits 
1394                                  * systems.
1395                                  */
1396                                 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1397                         }
1398                         if (result) {
1399                                 if (near_jump)
1400                                         ip += (signed char)*ip;
1401                                 else
1402                                         ip += (gint32) read32 (ip);
1403                         }
1404                         ip += near_jump ? 1: 4;
1405                         BREAK;
1406                 }
1407                 CASE (CEE_BNE_UN) /* Fall through */
1408                 CASE (CEE_BNE_UN_S) {
1409                         int result;
1410                         int near_jump = *ip == CEE_BNE_UN_S;
1411                         ++ip;
1412                         sp -= 2;
1413                         if (sp->type == VAL_I32)
1414                                 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1415                         else if (sp->type == VAL_I64)
1416                                 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1417                         else if (sp->type == VAL_DOUBLE)
1418                                 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1419                                         (sp [0].data.f != sp [1].data.f);
1420                         else
1421                                 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1422                         if (result) {
1423                                 if (near_jump)
1424                                         ip += (signed char)*ip;
1425                                 else
1426                                         ip += (gint32) read32 (ip);
1427                         }
1428                         ip += near_jump ? 1: 4;
1429                         BREAK;
1430                 }
1431                 CASE (CEE_BGE_UN) /* Fall through */
1432                 CASE (CEE_BGE_UN_S) {
1433                         int result;
1434                         int near_jump = *ip == CEE_BGE_UN_S;
1435                         ++ip;
1436                         sp -= 2;
1437                         if (sp->type == VAL_I32)
1438                                 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1439                         else if (sp->type == VAL_I64)
1440                                 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1441                         else if (sp->type == VAL_DOUBLE)
1442                                 result = !isless (sp [0].data.f,sp [1].data.f);
1443                         else
1444                                 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1445                         if (result) {
1446                                 if (near_jump)
1447                                         ip += (signed char)*ip;
1448                                 else
1449                                         ip += (gint32) read32 (ip);
1450                         }
1451                         ip += near_jump ? 1: 4;
1452                         BREAK;
1453                 }
1454                 CASE (CEE_BGT_UN) /* Fall through */
1455                 CASE (CEE_BGT_UN_S) {
1456                         int result;
1457                         int near_jump = *ip == CEE_BGT_UN_S;
1458                         ++ip;
1459                         sp -= 2;
1460                         if (sp->type == VAL_I32)
1461                                 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1462                         else if (sp->type == VAL_I64)
1463                                 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1464                         else if (sp->type == VAL_DOUBLE)
1465                                 result = isgreater (sp [0].data.f, sp [1].data.f);
1466                         else
1467                                 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1468                         if (result) {
1469                                 if (near_jump)
1470                                         ip += (signed char)*ip;
1471                                 else
1472                                         ip += (gint32) read32 (ip);
1473                         }
1474                         ip += near_jump ? 1: 4;
1475                         BREAK;
1476                 }
1477                 CASE (CEE_BLE_UN) /* Fall through */
1478                 CASE (CEE_BLE_UN_S) {
1479                         int result;
1480                         int near_jump = *ip == CEE_BLE_UN_S;
1481                         ++ip;
1482                         sp -= 2;
1483                         if (sp->type == VAL_I32)
1484                                 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1485                         else if (sp->type == VAL_I64)
1486                                 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1487                         else if (sp->type == VAL_DOUBLE)
1488                                 result = islessequal (sp [0].data.f, sp [1].data.f);
1489                         else
1490                                 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1491                         if (result) {
1492                                 if (near_jump)
1493                                         ip += (signed char)*ip;
1494                                 else
1495                                         ip += (gint32) read32 (ip);
1496                         }
1497                         ip += near_jump ? 1: 4;
1498                         BREAK;
1499                 }
1500                 CASE (CEE_BLT_UN) /* Fall through */
1501                 CASE (CEE_BLT_UN_S) {
1502                         int result;
1503                         int near_jump = *ip == CEE_BLT_UN_S;
1504                         ++ip;
1505                         sp -= 2;
1506                         if (sp->type == VAL_I32)
1507                                 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1508                         else if (sp->type == VAL_I64)
1509                                 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1510                         else if (sp->type == VAL_DOUBLE)
1511                                 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1512                                         (sp [0].data.f < sp [1].data.f);
1513                         else
1514                                 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1515                         if (result) {
1516                                 if (near_jump)
1517                                         ip += (signed char)*ip;
1518                                 else
1519                                         ip += (gint32) read32 (ip);
1520                         }
1521                         ip += near_jump ? 1: 4;
1522                         BREAK;
1523                 }
1524                 CASE (CEE_SWITCH) {
1525                         guint32 n;
1526                         const unsigned char *st;
1527                         ++ip;
1528                         n = read32 (ip);
1529                         ip += 4;
1530                         st = ip + sizeof (gint32) * n;
1531                         --sp;
1532                         if ((guint32)sp->data.i < n) {
1533                                 gint offset;
1534                                 ip += sizeof (gint32) * (guint32)sp->data.i;
1535                                 offset = read32 (ip);
1536                                 ip = st + offset;
1537                         } else {
1538                                 ip = st;
1539                         }
1540                         BREAK;
1541                 }
1542                 CASE (CEE_LDIND_I1)
1543                         ++ip;
1544                         sp[-1].type = VAL_I32;
1545                         sp[-1].data.i = *(gint8*)sp[-1].data.p;
1546                         BREAK;
1547                 CASE (CEE_LDIND_U1)
1548                         ++ip;
1549                         sp[-1].type = VAL_I32;
1550                         sp[-1].data.i = *(guint8*)sp[-1].data.p;
1551                         BREAK;
1552                 CASE (CEE_LDIND_I2)
1553                         ++ip;
1554                         sp[-1].type = VAL_I32;
1555                         sp[-1].data.i = *(gint16*)sp[-1].data.p;
1556                         BREAK;
1557                 CASE (CEE_LDIND_U2)
1558                         ++ip;
1559                         sp[-1].type = VAL_I32;
1560                         sp[-1].data.i = *(guint16*)sp[-1].data.p;
1561                         BREAK;
1562                 CASE (CEE_LDIND_I4) /* Fall through */
1563                 CASE (CEE_LDIND_U4)
1564                         ++ip;
1565                         sp[-1].type = VAL_I32;
1566                         sp[-1].data.i = *(gint32*)sp[-1].data.p;
1567                         BREAK;
1568                 CASE (CEE_LDIND_I8)
1569                         ++ip;
1570                         sp[-1].type = VAL_I64;
1571                         sp[-1].data.l = *(gint64*)sp[-1].data.p;
1572                         BREAK;
1573                 CASE (CEE_LDIND_I)
1574                         ++ip;
1575                         sp[-1].type = VAL_NATI;
1576                         sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1577                         BREAK;
1578                 CASE (CEE_LDIND_R4)
1579                         ++ip;
1580                         sp[-1].type = VAL_DOUBLE;
1581                         sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1582                         BREAK;
1583                 CASE (CEE_LDIND_R8)
1584                         ++ip;
1585                         sp[-1].type = VAL_DOUBLE;
1586                         sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1587                         BREAK;
1588                 CASE (CEE_LDIND_REF)
1589                         ++ip;
1590                         sp[-1].type = VAL_OBJ;
1591                         sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1592                         sp[-1].data.vt.klass = NULL;
1593                         BREAK;
1594                 CASE (CEE_STIND_REF) {
1595                         gpointer *p;
1596                         ++ip;
1597                         sp -= 2;
1598                         p = sp->data.p;
1599                         *p = sp[1].data.p;
1600                         BREAK;
1601                 }
1602                 CASE (CEE_STIND_I1) {
1603                         gint8 *p;
1604                         ++ip;
1605                         sp -= 2;
1606                         p = sp->data.p;
1607                         *p = (gint8)sp[1].data.i;
1608                         BREAK;
1609                 }
1610                 CASE (CEE_STIND_I2) {
1611                         gint16 *p;
1612                         ++ip;
1613                         sp -= 2;
1614                         p = sp->data.p;
1615                         *p = (gint16)sp[1].data.i;
1616                         BREAK;
1617                 }
1618                 CASE (CEE_STIND_I4) {
1619                         gint32 *p;
1620                         ++ip;
1621                         sp -= 2;
1622                         p = sp->data.p;
1623                         *p = sp[1].data.i;
1624                         BREAK;
1625                 }
1626                 CASE (CEE_STIND_I) {
1627                         mono_i *p;
1628                         ++ip;
1629                         sp -= 2;
1630                         p = sp->data.p;
1631                         *p = (mono_i)sp[1].data.p;
1632                         BREAK;
1633                 }
1634                 CASE (CEE_STIND_I8) {
1635                         gint64 *p;
1636                         ++ip;
1637                         sp -= 2;
1638                         p = sp->data.p;
1639                         *p = sp[1].data.l;
1640                         BREAK;
1641                 }
1642                 CASE (CEE_STIND_R4) {
1643                         float *p;
1644                         ++ip;
1645                         sp -= 2;
1646                         p = sp->data.p;
1647                         *p = (gfloat)sp[1].data.f;
1648                         BREAK;
1649                 }
1650                 CASE (CEE_STIND_R8) {
1651                         double *p;
1652                         ++ip;
1653                         sp -= 2;
1654                         p = sp->data.p;
1655                         *p = sp[1].data.f;
1656                         BREAK;
1657                 }
1658                 CASE (CEE_ADD)
1659                         ++ip;
1660                         --sp;
1661                         /* should probably consider the pointers as unsigned */
1662                         if (sp->type == VAL_I32)
1663                                 sp [-1].data.i += GET_NATI (sp [0]);
1664                         else if (sp->type == VAL_I64)
1665                                 sp [-1].data.l += sp [0].data.l;
1666                         else if (sp->type == VAL_DOUBLE)
1667                                 sp [-1].data.f += sp [0].data.f;
1668                         else {
1669                                 char *p = sp [-1].data.p;
1670                                 p += GET_NATI (sp [0]);
1671                                 sp [-1].data.p = p;
1672                         }
1673                         BREAK;
1674                 CASE (CEE_SUB)
1675                         ++ip;
1676                         --sp;
1677                         /* should probably consider the pointers as unsigned */
1678                         if (sp->type == VAL_I32)
1679                                 sp [-1].data.i -= GET_NATI (sp [0]);
1680                         else if (sp->type == VAL_I64)
1681                                 sp [-1].data.l -= sp [0].data.l;
1682                         else if (sp->type == VAL_DOUBLE)
1683                                 sp [-1].data.f -= sp [0].data.f;
1684                         else {
1685                                 char *p = sp [-1].data.p;
1686                                 p -= GET_NATI (sp [0]);
1687                                 sp [-1].data.p = p;
1688                         }
1689                         BREAK;
1690                 CASE (CEE_MUL)
1691                         ++ip;
1692                         --sp;
1693                         if (sp->type == VAL_I32)
1694                                 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
1695                         else if (sp->type == VAL_I64)
1696                                 sp [-1].data.l *= sp [0].data.l;
1697                         else if (sp->type == VAL_DOUBLE)
1698                                 sp [-1].data.f *= sp [0].data.f;
1699                         BREAK;
1700                 CASE (CEE_DIV)
1701                         ++ip;
1702                         --sp;
1703                         if (sp->type == VAL_I32) {
1704                                 if (GET_NATI (sp [0]) == 0)
1705                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1706                                 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
1707                         } else if (sp->type == VAL_I64) {
1708                                 if (sp [0].data.l == 0)
1709                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1710                                 sp [-1].data.l /= sp [0].data.l;
1711                         } else if (sp->type == VAL_DOUBLE) {
1712                                 /* set NaN is divisor is 0.0 */
1713                                 sp [-1].data.f /= sp [0].data.f;
1714                         }
1715                         BREAK;
1716                 CASE (CEE_DIV_UN)
1717                         ++ip;
1718                         --sp;
1719                         if (sp->type == VAL_I32) {
1720                                 guint32 val;
1721                                 if (GET_NATI (sp [0]) == 0)
1722                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1723                                 val = sp [-1].data.i;
1724                                 val /= (guint32)GET_NATI (sp [0]);
1725                                 sp [-1].data.i = val;
1726                         } else if (sp->type == VAL_I64) {
1727                                 guint64 val;
1728                                 if (sp [0].data.l == 0)
1729                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1730                                 val = sp [-1].data.l;
1731                                 val /= (guint64)sp [0].data.l;
1732                                 sp [-1].data.l = val;
1733                         } else if (sp->type == VAL_NATI) {
1734                                 mono_u val;
1735                                 if (GET_NATI (sp [0]) == 0)
1736                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1737                                 val = (mono_u)sp [-1].data.p;
1738                                 val /= (gulong)sp [0].data.p;
1739                                 sp [-1].data.p = (gpointer)val;
1740                         }
1741                         BREAK;
1742                 CASE (CEE_REM)
1743                         ++ip;
1744                         --sp;
1745                         if (sp->type == VAL_I32) {
1746                                 if (GET_NATI (sp [0]) == 0)
1747                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1748                                 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
1749                         } else if (sp->type == VAL_I64) {
1750                                 if (sp [0].data.l == 0)
1751                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1752                                 sp [-1].data.l %= sp [0].data.l;
1753                         } else if (sp->type == VAL_DOUBLE) {
1754                                 /* FIXME: what do we actually do here? */
1755                                 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
1756                         } else {
1757                                 if (GET_NATI (sp [0]) == 0)
1758                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1759                                 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
1760                         }
1761                         BREAK;
1762                 CASE (CEE_REM_UN)
1763                         ++ip;
1764                         --sp;
1765                         if (sp->type == VAL_I32) {
1766                                 if (GET_NATI (sp [0]) == 0)
1767                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1768                                 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
1769                         } else if (sp->type == VAL_I64) {
1770                                 if (sp [0].data.l == 0)
1771                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1772                                 (gulong)sp [-1].data.l %= (gulong)sp [0].data.l;
1773                         } else if (sp->type == VAL_DOUBLE) {
1774                                 /* unspecified behaviour according to the spec */
1775                         } else {
1776                                 if (GET_NATI (sp [0]) == 0)
1777                                         THROW_EX (get_exception_divide_by_zero (), ip - 1);
1778                                 (gulong)GET_NATI (sp [-1]) %= (gulong)GET_NATI (sp [0]);
1779                         }
1780                         BREAK;
1781                 CASE (CEE_AND)
1782                         ++ip;
1783                         --sp;
1784                         if (sp->type == VAL_I32)
1785                                 sp [-1].data.i &= GET_NATI (sp [0]);
1786                         else if (sp->type == VAL_I64)
1787                                 sp [-1].data.l &= sp [0].data.l;
1788                         else
1789                                 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1790                         BREAK;
1791                 CASE (CEE_OR)
1792                         ++ip;
1793                         --sp;
1794                         if (sp->type == VAL_I32)
1795                                 sp [-1].data.i |= GET_NATI (sp [0]);
1796                         else if (sp->type == VAL_I64)
1797                                 sp [-1].data.l |= sp [0].data.l;
1798                         else
1799                                 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1800                         BREAK;
1801                 CASE (CEE_XOR)
1802                         ++ip;
1803                         --sp;
1804                         if (sp->type == VAL_I32)
1805                                 sp [-1].data.i ^= GET_NATI (sp [0]);
1806                         else if (sp->type == VAL_I64)
1807                                 sp [-1].data.l ^= sp [0].data.l;
1808                         else
1809                                 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1810                         BREAK;
1811                 CASE (CEE_SHL)
1812                         ++ip;
1813                         --sp;
1814                         if (sp->type == VAL_I32)
1815                                 sp [-1].data.i <<= GET_NATI (sp [0]);
1816                         else if (sp->type == VAL_I64)
1817                                 sp [-1].data.l <<= GET_NATI (sp [0]);
1818                         else
1819                                 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1820                         BREAK;
1821                 CASE (CEE_SHR)
1822                         ++ip;
1823                         --sp;
1824                         if (sp->type == VAL_I32)
1825                                 sp [-1].data.i >>= GET_NATI (sp [0]);
1826                         else if (sp->type == VAL_I64)
1827                                 sp [-1].data.l >>= GET_NATI (sp [0]);
1828                         else
1829                                 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1830                         BREAK;
1831                 CASE (CEE_SHR_UN)
1832                         ++ip;
1833                         --sp;
1834                         if (sp->type == VAL_I32)
1835                                 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
1836                         else if (sp->type == VAL_I64)
1837                                 (gulong)sp [-1].data.l >>= GET_NATI (sp [0]);
1838                         else
1839                                 (gulong)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1840                         BREAK;
1841                 CASE (CEE_NEG)
1842                         ++ip;
1843                         --sp;
1844                         if (sp->type == VAL_I32) 
1845                                 sp->data.i = - sp->data.i;
1846                         else if (sp->type == VAL_I64)
1847                                 sp->data.l = - sp->data.l;
1848                         else if (sp->type == VAL_DOUBLE)
1849                                 sp->data.f = - sp->data.f;
1850                         else if (sp->type == VAL_NATI)
1851                                 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
1852                         ++sp;
1853                         BREAK;
1854                 CASE (CEE_NOT)
1855                         ++ip;
1856                         --sp;
1857                         if (sp->type == VAL_I32)
1858                                 sp->data.i = ~ sp->data.i;
1859                         else if (sp->type == VAL_I64)
1860                                 sp->data.l = ~ sp->data.l;
1861                         else if (sp->type == VAL_NATI)
1862                                 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
1863                         ++sp;
1864                         BREAK;
1865                 CASE (CEE_CONV_U1) /* fall through */
1866                 CASE (CEE_CONV_I1) {
1867                         ++ip;
1868                         switch (sp [-1].type) {
1869                         case VAL_DOUBLE:
1870                                 sp [-1].data.i = (gint8)sp [-1].data.f;
1871                                 break;
1872                         case VAL_I64:
1873                                 sp [-1].data.i = (gint8)sp [-1].data.l;
1874                                 break;
1875                         case VAL_VALUET:
1876                                 ves_abort();
1877                         case VAL_I32:
1878                                 sp [-1].data.i = (gint8)sp [-1].data.i;
1879                                 break;
1880                         default:
1881                                 sp [-1].data.i = (gint8)sp [-1].data.nati;
1882                                 break;
1883                         }
1884                         sp [-1].type = VAL_I32;
1885                         BREAK;
1886                 }
1887                 CASE (CEE_CONV_U2) /* fall through */
1888                 CASE (CEE_CONV_I2) {
1889                         ++ip;
1890                         switch (sp [-1].type) {
1891                         case VAL_DOUBLE:
1892                                 sp [-1].data.i = (gint16)sp [-1].data.f;
1893                                 break;
1894                         case VAL_I64:
1895                                 sp [-1].data.i = (gint16)sp [-1].data.l;
1896                                 break;
1897                         case VAL_VALUET:
1898                                 ves_abort();
1899                         case VAL_I32:
1900                                 sp [-1].data.i = (gint16)sp [-1].data.i;
1901                                 break;
1902                         default:
1903                                 sp [-1].data.i = (gint16)sp [-1].data.nati;
1904                                 break;
1905                         }
1906                         sp [-1].type = VAL_I32;
1907                         BREAK;
1908                 }
1909                 CASE (CEE_CONV_U4) /* Fall through */
1910 #if SIZEOF_VOID_P == 4
1911                 CASE (CEE_CONV_I) /* Fall through */
1912                 CASE (CEE_CONV_U) /* Fall through */
1913 #endif
1914                 CASE (CEE_CONV_I4) {
1915                         ++ip;
1916                         switch (sp [-1].type) {
1917                         case VAL_DOUBLE:
1918                                 sp [-1].data.i = (gint32)sp [-1].data.f;
1919                                 break;
1920                         case VAL_I64:
1921                                 sp [-1].data.i = (gint32)sp [-1].data.l;
1922                                 break;
1923                         case VAL_VALUET:
1924                                 ves_abort();
1925                         case VAL_I32:
1926                                 break;
1927                         default:
1928                                 sp [-1].data.i = (gint32)sp [-1].data.p;
1929                                 break;
1930                         }
1931                         sp [-1].type = VAL_I32;
1932                         BREAK;
1933                 }
1934 #if SIZEOF_VOID_P == 8
1935                 CASE (CEE_CONV_I) /* Fall through */
1936 #endif
1937                 CASE (CEE_CONV_I8)
1938                         ++ip;
1939                         switch (sp [-1].type) {
1940                         case VAL_DOUBLE:
1941                                 sp [-1].data.l = (gint64)sp [-1].data.f;
1942                                 break;
1943                         case VAL_I64:
1944                                 break;
1945                         case VAL_VALUET:
1946                                 ves_abort();
1947                         case VAL_I32:
1948                                 sp [-1].data.l = (gint64)sp [-1].data.i;
1949                                 break;
1950                         default:
1951                                 sp [-1].data.l = (gint64)sp [-1].data.nati;
1952                                 break;
1953                         }
1954                         sp [-1].type = VAL_I64;
1955                         BREAK;
1956                 CASE (CEE_CONV_R4) /* Fall through */
1957                 CASE (CEE_CONV_R8) {
1958                         ++ip;
1959                         switch (sp [-1].type) {
1960                         case VAL_DOUBLE:
1961                                 sp [-1].data.f = (double)sp [-1].data.f;
1962                                 break;
1963                         case VAL_I64:
1964                                 sp [-1].data.f = (double)sp [-1].data.l;
1965                                 break;
1966                         case VAL_VALUET:
1967                                 ves_abort();
1968                         case VAL_I32:
1969                                 sp [-1].data.f = (double)sp [-1].data.i;
1970                                 break;
1971                         default:
1972                                 sp [-1].data.f = (double)sp [-1].data.nati;
1973                                 break;
1974                         }
1975                         sp [-1].type = VAL_DOUBLE;
1976                         BREAK;
1977                 }
1978 #if SIZEOF_VOID_P == 8
1979                 CASE (CEE_CONV_U) /* Fall through */
1980 #endif
1981                 CASE (CEE_CONV_U8)
1982                         ++ip;
1983
1984                         switch (sp [-1].type){
1985                         case VAL_DOUBLE:
1986                                 sp [-1].data.l = (guint64)sp [-1].data.f;
1987                                 break;
1988                         case VAL_I64:
1989                                 break;
1990                         case VAL_VALUET:
1991                                 ves_abort();
1992                         case VAL_I32:
1993                                 sp [-1].data.l = (guint64) sp [-1].data.i;
1994                                 break;
1995                         default:
1996                                 sp [-1].data.l = (guint64) sp [-1].data.nati;
1997                                 break;
1998                         }
1999                         sp [-1].type = VAL_I64;
2000                         BREAK;
2001                 CASE (CEE_CPOBJ) {
2002                         MonoClass *vtklass;
2003                         ++ip;
2004                         vtklass = mono_class_get (image, read32 (ip));
2005                         ip += 4;
2006                         sp -= 2;
2007                         memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2008                         BREAK;
2009                 }
2010                 CASE (CEE_LDOBJ) {
2011                         guint32 token;
2012                         MonoClass *c;
2013                         char *addr;
2014
2015                         ++ip;
2016                         token = read32 (ip);
2017                         ip += 4;
2018                         c = mono_class_get (image, token);
2019                         addr = sp [-1].data.vt.vt;
2020                         vt_alloc (&c->byval_arg, &sp [-1]);
2021                         stackval_from_data (&c->byval_arg, &sp [-1], addr);
2022                         BREAK;
2023                 }
2024                 CASE (CEE_LDSTR) {
2025                         MonoObject *o;
2026                         guint32 index;
2027
2028                         ip++;
2029                         index = mono_metadata_token_index (read32 (ip));
2030                         ip += 4;
2031
2032                         o = (MonoObject*)mono_ldstr (image, index);
2033                         sp->type = VAL_OBJ;
2034                         sp->data.p = o;
2035                         sp->data.vt.klass = NULL;
2036
2037                         ++sp;
2038                         BREAK;
2039                 }
2040                 CASE (CEE_NEWOBJ) {
2041                         MonoObject *o;
2042                         MonoMethodSignature *csig;
2043                         stackval *endsp = sp;
2044                         guint32 token;
2045
2046                         frame->ip = ip;
2047
2048                         ip++;
2049                         token = read32 (ip);
2050                         ip += 4;
2051
2052                         if (!(child_frame.method = mono_get_method (image, token, NULL)))
2053                                 THROW_EX (get_exception_missing_method (), ip -5);
2054
2055                         csig = child_frame.method->signature;
2056
2057                         if (child_frame.method->klass->parent == mono_defaults.array_class) {
2058                                 sp -= csig->param_count;
2059                                 o = ves_array_create (child_frame.method->klass, csig, sp);
2060                                 goto array_constructed;
2061                         }
2062
2063                         o = mono_object_new (child_frame.method->klass);
2064
2065                         /*
2066                          * First arg is the object.
2067                          */
2068                         child_frame.obj = o;
2069
2070                         if (csig->param_count) {
2071                                 sp -= csig->param_count;
2072                                 child_frame.stack_args = sp;
2073                         } else {
2074                                 child_frame.stack_args = NULL;
2075                         }
2076
2077                         g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2078
2079                         child_frame.ex = NULL;
2080                         child_frame.ex_handler = NULL;
2081
2082                         ves_exec_method (&child_frame);
2083
2084                         while (endsp > sp) {
2085                                 --endsp;
2086                                 vt_free (endsp);
2087                         }
2088
2089                         if (child_frame.ex) {
2090                                 /*
2091                                  * An exception occurred, need to run finally, fault and catch handlers..
2092                                  */
2093                                 frame->ex = child_frame.ex;
2094                                 goto handle_finally;
2095                         }
2096                         /*
2097                          * a constructor returns void, but we need to return the object we created
2098                          */
2099 array_constructed:
2100                         sp->type = VAL_OBJ;
2101                         sp->data.p = o;
2102                         sp->data.vt.klass = o->klass;
2103                         ++sp;
2104                         BREAK;
2105                 }
2106                 CASE (CEE_CASTCLASS) /* Fall through */
2107                 CASE (CEE_ISINST) {
2108                         MonoObject *o;
2109                         MonoClass *c , *oclass;
2110                         guint32 token;
2111                         int do_isinst = *ip == CEE_ISINST;
2112                         gboolean found = FALSE;
2113
2114                         ++ip;
2115                         token = read32 (ip);
2116                         c = mono_class_get (image, token);
2117
2118                         if (!c->inited)
2119                                 init_class (c);
2120
2121                         g_assert (sp [-1].type == VAL_OBJ);
2122
2123                         if ((o = sp [-1].data.p)) {
2124
2125                                 oclass = o->klass;
2126
2127                                 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2128                                         if ((c->interface_id <= oclass->max_interface_id) &&
2129                                             oclass->interface_offsets [c->interface_id])
2130                                                 found = TRUE;
2131                                 } else {
2132                                         if ((oclass->baseval - c->baseval) <= c->diffval) {
2133                                                 sp [-1].data.vt.klass = c;
2134                                                 found = TRUE;
2135                                         }
2136                                 }
2137
2138                                 if (!found) {
2139                                         if (do_isinst) {
2140                                                 sp [-1].data.p = NULL;
2141                                                 sp [-1].data.vt.klass = NULL;
2142                                         } else
2143                                                 THROW_EX (get_exception_invalid_cast (), ip - 1);
2144                                 }
2145                         }
2146                         ip += 4;
2147                         BREAK;
2148                 }
2149                 CASE (CEE_CONV_R_UN)
2150                         switch (sp [-1].type) {
2151                         case VAL_DOUBLE:
2152                                 break;
2153                         case VAL_I64:
2154                                 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2155                                 break;
2156                         case VAL_VALUET:
2157                                 ves_abort();
2158                         case VAL_I32:
2159                                 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2160                                 break;
2161                         default:
2162                                 sp [-1].data.f = (double)(gulong)sp [-1].data.nati;
2163                                 break;
2164                         }
2165                         sp [-1].type = VAL_DOUBLE;
2166                         BREAK;
2167                 CASE (CEE_UNUSED58)
2168                 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2169                 CASE (CEE_UNBOX) {
2170                         MonoObject *o;
2171                         MonoClass *c;
2172                         guint32 token;
2173
2174                         ++ip;
2175                         token = read32 (ip);
2176                         
2177                         c = mono_class_get (image, token);
2178                         
2179                         o = sp [-1].data.p;
2180                         if (!o)
2181                                 THROW_EX (get_exception_null_reference(), ip - 1);
2182
2183                         if (o->klass->type_token != c->type_token)
2184                                 THROW_EX (get_exception_invalid_cast (), ip - 1);
2185
2186                         sp [-1].type = VAL_MP;
2187                         sp [-1].data.p = (char *)o + sizeof (MonoObject);
2188
2189                         ip += 4;
2190                         BREAK;
2191                 }
2192                 CASE (CEE_THROW)
2193                         --sp;
2194                         THROW_EX (sp->data.p, ip);
2195                         BREAK;
2196                 CASE (CEE_LDFLDA) /* Fall through */
2197                 CASE (CEE_LDFLD) {
2198                         MonoObject *obj;
2199                         MonoClassField *field;
2200                         guint32 token, offset;
2201                         int load_addr = *ip == CEE_LDFLDA;
2202
2203                         if (!sp [-1].data.p)
2204                                 THROW_EX (get_exception_null_reference (), ip);
2205                         
2206                         ++ip;
2207                         token = read32 (ip);
2208                         ip += 4;
2209
2210                         if (sp [-1].type == VAL_OBJ) {
2211                                 obj = sp [-1].data.p;
2212                                 field = mono_class_get_field (obj->klass, token);
2213                                 offset = field->offset;
2214                         } else { /* valuetype */
2215                                 /*g_assert (sp [-1].type == VAL_VALUETA); */
2216                                 obj = sp [-1].data.vt.vt;
2217                                 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2218                                 offset = field->offset - sizeof (MonoObject);
2219                         }
2220                         if (load_addr) {
2221                                 sp [-1].type = VAL_TP;
2222                                 sp [-1].data.p = (char*)obj + offset;
2223                                 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2224                         } else {
2225                                 vt_alloc (field->type, &sp [-1]);
2226                                 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2227                                 
2228                         }
2229                         BREAK;
2230                 }
2231                 CASE (CEE_STFLD) {
2232                         MonoObject *obj;
2233                         MonoClassField *field;
2234                         guint32 token, offset;
2235
2236                         ++ip;
2237                         token = read32 (ip);
2238                         ip += 4;
2239                         
2240                         sp -= 2;
2241                         
2242                         if (sp [0].type == VAL_OBJ) {
2243                                 obj = sp [0].data.p;
2244                                 field = mono_class_get_field (obj->klass, token);
2245                                 offset = field->offset;
2246                         } else { /* valuetype */
2247                                 /*g_assert (sp->type == VAL_VALUETA); */
2248                                 obj = sp [0].data.vt.vt;
2249                                 field = mono_class_get_field (sp [0].data.vt.klass, token);
2250                                 offset = field->offset - sizeof (MonoObject);
2251                         }
2252
2253                         stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2254                         vt_free (&sp [1]);
2255                         BREAK;
2256                 }
2257                 CASE (CEE_LDSFLD) /* Fall through */
2258                 CASE (CEE_LDSFLDA) {
2259                         MonoClass *klass;
2260                         MonoClassField *field;
2261                         guint32 token;
2262                         int load_addr = *ip == CEE_LDSFLDA;
2263
2264                         ++ip;
2265                         token = read32 (ip);
2266                         ip += 4;
2267                         
2268                         /* need to handle fieldrefs */
2269                         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2270                                 field = mono_field_from_memberref (image, token, &klass);
2271                                 if (!klass->inited)
2272                                         init_class (klass);
2273                         } else {
2274                                 klass = mono_class_get (image, 
2275                                         MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2276                                 if (!klass->inited)
2277                                         init_class (klass);
2278                                 field = mono_class_get_field (klass, token);
2279                         }
2280                         g_assert (field);
2281                         if (load_addr) {
2282                                 sp->type = VAL_TP;
2283                                 sp->data.p = (char*)MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
2284                                 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2285                         } else {
2286                                 vt_alloc (field->type, sp);
2287                                 stackval_from_data (field->type, sp, (char*)MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2288                         }
2289                         ++sp;
2290                         BREAK;
2291                 }
2292                 CASE (CEE_STSFLD) {
2293                         MonoClass *klass;
2294                         MonoClassField *field;
2295                         guint32 token;
2296
2297                         ++ip;
2298                         token = read32 (ip);
2299                         ip += 4;
2300                         --sp;
2301
2302                         /* need to handle fieldrefs */
2303                         klass = mono_class_get (image, 
2304                                 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2305                         if (!klass->inited)
2306                                 init_class (klass);
2307                         field = mono_class_get_field (klass, token);
2308                         g_assert (field);
2309                         stackval_to_data (field->type, sp, (char*)MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2310                         vt_free (sp);
2311                         BREAK;
2312                 }
2313                 CASE (CEE_STOBJ) {
2314                         MonoClass *vtklass;
2315                         ++ip;
2316                         vtklass = mono_class_get (image, read32 (ip));
2317                         ip += 4;
2318                         sp -= 2;
2319                         memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2320                         BREAK;
2321                 }
2322 #if SIZEOF_VOID_P == 8
2323                 CASE (CEE_CONV_OVF_I_UN)
2324 #endif
2325                 CASE (CEE_CONV_OVF_I8_UN) {
2326                         switch (sp [-1].type) {
2327                         case VAL_DOUBLE:
2328                                 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2329                                         THROW_EX (get_exception_overflow (), ip);
2330                                 sp [-1].data.l = (guint64)sp [-1].data.f;
2331                                 break;
2332                         case VAL_I64:
2333                                 if (sp [-1].data.l < 0)
2334                                         THROW_EX (get_exception_overflow (), ip);
2335                                 break;
2336                         case VAL_VALUET:
2337                                 ves_abort();
2338                         case VAL_I32:
2339                                 /* Can't overflow */
2340                                 sp [-1].data.l = (guint64)sp [-1].data.i;
2341                                 break;
2342                         default:
2343                                 if ((gint64)sp [-1].data.nati < 0)
2344                                         THROW_EX (get_exception_overflow (), ip);
2345                                 sp [-1].data.l = (guint64)sp [-1].data.nati;
2346                                 break;
2347                         }
2348                         sp [-1].type = VAL_I64;
2349                         ++ip;
2350                         BREAK;
2351                 }
2352 #if SIZEOF_VOID_P == 8
2353                 CASE (CEE_CONV_OVF_U_UN) 
2354 #endif
2355                 CASE (CEE_CONV_OVF_U8_UN) {
2356                         switch (sp [-1].type) {
2357                         case VAL_DOUBLE:
2358                                 if (sp [-1].data.f < 0 || sp [-1].data.f > 18446744073709551615UL)
2359                                         THROW_EX (get_exception_overflow (), ip);
2360                                 sp [-1].data.l = (guint64)sp [-1].data.f;
2361                                 break;
2362                         case VAL_I64:
2363                                 /* nothing to do */
2364                                 break;
2365                         case VAL_VALUET:
2366                                 ves_abort();
2367                         case VAL_I32:
2368                                 /* Can't overflow */
2369                                 sp [-1].data.l = (guint64)sp [-1].data.i;
2370                                 break;
2371                         default:
2372                                 /* Can't overflow */
2373                                 sp [-1].data.l = (guint64)sp [-1].data.nati;
2374                                 break;
2375                         }
2376                         sp [-1].type = VAL_I64;
2377                         ++ip;
2378                         BREAK;
2379                 }
2380 #if SIZEOF_VOID_P == 4
2381                 CASE (CEE_CONV_OVF_I_UN)
2382                 CASE (CEE_CONV_OVF_U_UN) 
2383 #endif
2384                 CASE (CEE_CONV_OVF_I1_UN)
2385                 CASE (CEE_CONV_OVF_I2_UN)
2386                 CASE (CEE_CONV_OVF_I4_UN)
2387                 CASE (CEE_CONV_OVF_U1_UN)
2388                 CASE (CEE_CONV_OVF_U2_UN)
2389                 CASE (CEE_CONV_OVF_U4_UN) {
2390                         guint64 value;
2391                         switch (sp [-1].type) {
2392                         case VAL_DOUBLE:
2393                                 value = (guint64)sp [-1].data.f;
2394                                 break;
2395                         case VAL_I64:
2396                                 value = (guint64)sp [-1].data.l;
2397                                 break;
2398                         case VAL_VALUET:
2399                                 ves_abort();
2400                         case VAL_I32:
2401                                 value = (guint64)sp [-1].data.i;
2402                                 break;
2403                         default:
2404                                 value = (guint64)sp [-1].data.nati;
2405                                 break;
2406                         }
2407                         switch (*ip) {
2408                         case CEE_CONV_OVF_I1_UN:
2409                                 if (value > 127)
2410                                         THROW_EX (get_exception_overflow (), ip);
2411                                 sp [-1].data.i = value;
2412                                 sp [-1].type = VAL_I32;
2413                                 break;
2414                         case CEE_CONV_OVF_I2_UN:
2415                                 if (value > 32767)
2416                                         THROW_EX (get_exception_overflow (), ip);
2417                                 sp [-1].data.i = value;
2418                                 sp [-1].type = VAL_I32;
2419                                 break;
2420 #if SIZEOF_VOID_P == 4
2421                         case CEE_CONV_OVF_I_UN: /* Fall through */
2422 #endif
2423                         case CEE_CONV_OVF_I4_UN:
2424                                 if (value > 2147483647)
2425                                         THROW_EX (get_exception_overflow (), ip);
2426                                 sp [-1].data.i = value;
2427                                 sp [-1].type = VAL_I32;
2428                                 break;
2429                         case CEE_CONV_OVF_U1_UN:
2430                                 if (value > 255)
2431                                         THROW_EX (get_exception_overflow (), ip);
2432                                 sp [-1].data.i = value;
2433                                 sp [-1].type = VAL_I32;
2434                                 break;
2435                         case CEE_CONV_OVF_U2_UN:
2436                                 if (value > 65535)
2437                                         THROW_EX (get_exception_overflow (), ip);
2438                                 sp [-1].data.i = value;
2439                                 sp [-1].type = VAL_I32;
2440                                 break;
2441 #if SIZEOF_VOID_P == 4
2442                         case CEE_CONV_OVF_U_UN: /* Fall through */
2443 #endif
2444                         case CEE_CONV_OVF_U4_UN:
2445                                 if (value > 4294967295U)
2446                                         THROW_EX (get_exception_overflow (), ip);
2447                                 sp [-1].data.i = value;
2448                                 sp [-1].type = VAL_I32;
2449                                 break;
2450                         default:
2451                                 g_assert_not_reached ();
2452                         }
2453                         ++ip;
2454                         BREAK;
2455                 }
2456                 CASE (CEE_BOX) {
2457                         guint32 token;
2458                         MonoClass *class;
2459
2460                         ip++;
2461                         token = read32 (ip);
2462
2463                         class = mono_class_get (image, token);
2464                         g_assert (class != NULL);
2465
2466                         sp [-1].type = VAL_OBJ;
2467                         sp [-1].data.p = mono_value_box (class, &sp [-1]);
2468                         /* need to vt_free (sp); */
2469
2470                         ip += 4;
2471
2472                         BREAK;
2473                 }
2474                 CASE (CEE_NEWARR) {
2475                         MonoClass *class;
2476                         MonoObject *o;
2477                         guint32 token;
2478
2479                         ip++;
2480                         token = read32 (ip);
2481                         class = mono_class_get (image, token);
2482                         o = (MonoObject*) mono_array_new (class, sp [-1].data.i);
2483                         ip += 4;
2484
2485                         sp [-1].type = VAL_OBJ;
2486                         sp [-1].data.p = o;
2487
2488                         BREAK;
2489                 }
2490                 CASE (CEE_LDLEN) {
2491                         MonoArray *o;
2492
2493                         ip++;
2494
2495                         g_assert (sp [-1].type == VAL_OBJ);
2496
2497                         o = sp [-1].data.p;
2498                         if (!o)
2499                                 THROW_EX (get_exception_null_reference (), ip - 1);
2500                         
2501                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2502
2503                         sp [-1].type = VAL_I32;
2504                         sp [-1].data.i = mono_array_length (o);
2505
2506                         BREAK;
2507                 }
2508                 CASE (CEE_LDELEMA) {
2509                         MonoArray *o;
2510                         guint32 esize, token;
2511                         
2512                         ++ip;
2513                         token = read32 (ip);
2514                         ip += 4;
2515                         sp -= 2;
2516
2517                         g_assert (sp [0].type == VAL_OBJ);
2518                         o = sp [0].data.p;
2519
2520                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2521                         
2522                         if (sp [1].data.nati >= mono_array_length (o))
2523                                 THROW_EX (get_exception_index_out_of_range (), ip - 5);
2524
2525                         /* check the array element corresponds to token */
2526                         esize = mono_array_element_size (o->obj.klass);
2527                         
2528                         sp->type = VAL_MP;
2529                         sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
2530                         sp->data.vt.klass = o->obj.klass->element_class;
2531
2532                         ++sp;
2533                         BREAK;
2534                 }
2535                 CASE (CEE_LDELEM_I1) /* fall through */
2536                 CASE (CEE_LDELEM_U1) /* fall through */
2537                 CASE (CEE_LDELEM_I2) /* fall through */
2538                 CASE (CEE_LDELEM_U2) /* fall through */
2539                 CASE (CEE_LDELEM_I4) /* fall through */
2540                 CASE (CEE_LDELEM_U4) /* fall through */
2541                 CASE (CEE_LDELEM_I8)  /* fall through */
2542                 CASE (CEE_LDELEM_I)  /* fall through */
2543                 CASE (CEE_LDELEM_R4) /* fall through */
2544                 CASE (CEE_LDELEM_R8) /* fall through */
2545                 CASE (CEE_LDELEM_REF) {
2546                         MonoArray *o;
2547                         mono_u aindex;
2548
2549                         sp -= 2;
2550
2551                         g_assert (sp [0].type == VAL_OBJ);
2552                         o = sp [0].data.p;
2553                         if (!o)
2554                                 THROW_EX (get_exception_null_reference (), ip);
2555
2556                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2557                         
2558                         aindex = sp [1].data.nati;
2559                         if (aindex >= mono_array_length (o))
2560                                 THROW_EX (get_exception_index_out_of_range (), ip);
2561                         
2562                         /*
2563                          * FIXME: throw get_exception_array_type_mismatch () if needed 
2564                          */
2565                         switch (*ip) {
2566                         case CEE_LDELEM_I1:
2567                                 sp [0].data.i = mono_array_get (o, gint8, aindex);
2568                                 sp [0].type = VAL_I32;
2569                                 break;
2570                         case CEE_LDELEM_U1:
2571                                 sp [0].data.i = mono_array_get (o, guint8, aindex);
2572                                 sp [0].type = VAL_I32;
2573                                 break;
2574                         case CEE_LDELEM_I2:
2575                                 sp [0].data.i = mono_array_get (o, gint16, aindex);
2576                                 sp [0].type = VAL_I32;
2577                                 break;
2578                         case CEE_LDELEM_U2:
2579                                 sp [0].data.i = mono_array_get (o, guint16, aindex);
2580                                 sp [0].type = VAL_I32;
2581                                 break;
2582                         case CEE_LDELEM_I:
2583                                 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
2584                                 sp [0].type = VAL_NATI;
2585                                 break;
2586                         case CEE_LDELEM_I4:
2587                                 sp [0].data.i = mono_array_get (o, gint32, aindex);
2588                                 sp [0].type = VAL_I32;
2589                                 break;
2590                         case CEE_LDELEM_U4:
2591                                 sp [0].data.i = mono_array_get (o, guint32, aindex);
2592                                 sp [0].type = VAL_I32;
2593                                 break;
2594                         case CEE_LDELEM_I8:
2595                                 sp [0].data.l = mono_array_get (o, gint64, aindex);
2596                                 sp [0].type = VAL_I64;
2597                                 break;
2598                         case CEE_LDELEM_R4:
2599                                 sp [0].data.f = mono_array_get (o, float, aindex);
2600                                 sp [0].type = VAL_DOUBLE;
2601                                 break;
2602                         case CEE_LDELEM_R8:
2603                                 sp [0].data.f = mono_array_get (o, double, aindex);
2604                                 sp [0].type = VAL_DOUBLE;
2605                                 break;
2606                         case CEE_LDELEM_REF:
2607                                 sp [0].data.p = mono_array_get (o, gpointer, aindex);
2608                                 sp [0].data.vt.klass = NULL;
2609                                 sp [0].type = VAL_OBJ;
2610                                 break;
2611                         default:
2612                                 ves_abort();
2613                         }
2614
2615                         ++ip;
2616                         ++sp;
2617                         BREAK;
2618                 }
2619                 CASE (CEE_STELEM_I)  /* fall through */
2620                 CASE (CEE_STELEM_I1) /* fall through */ 
2621                 CASE (CEE_STELEM_I2) /* fall through */
2622                 CASE (CEE_STELEM_I4) /* fall through */
2623                 CASE (CEE_STELEM_I8) /* fall through */
2624                 CASE (CEE_STELEM_R4) /* fall through */
2625                 CASE (CEE_STELEM_R8) /* fall through */
2626                 CASE (CEE_STELEM_REF) {
2627                         MonoArray *o;
2628                         MonoClass *ac;
2629                         mono_u aindex;
2630
2631                         sp -= 3;
2632
2633                         g_assert (sp [0].type == VAL_OBJ);
2634                         o = sp [0].data.p;
2635                         if (!o)
2636                                 THROW_EX (get_exception_null_reference (), ip);
2637
2638                         g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2639                         ac = o->obj.klass;
2640                     
2641                         aindex = sp [1].data.nati;
2642                         if (aindex >= mono_array_length (o))
2643                                 THROW_EX (get_exception_index_out_of_range (), ip);
2644
2645                         /*
2646                          * FIXME: throw get_exception_array_type_mismatch () if needed 
2647                          */
2648                         switch (*ip) {
2649                         case CEE_STELEM_I:
2650                                 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
2651                                 break;
2652                         case CEE_STELEM_I1:
2653                                 mono_array_set (o, gint8, aindex, sp [2].data.i);
2654                                 break;
2655                         case CEE_STELEM_I2:
2656                                 mono_array_set (o, gint16, aindex, sp [2].data.i);
2657                                 break;
2658                         case CEE_STELEM_I4:
2659                                 mono_array_set (o, gint32, aindex, sp [2].data.i);
2660                                 break;
2661                         case CEE_STELEM_I8:
2662                                 mono_array_set (o, gint64, aindex, sp [2].data.l);
2663                                 break;
2664                         case CEE_STELEM_R4:
2665                                 mono_array_set (o, float, aindex, sp [2].data.f);
2666                                 break;
2667                         case CEE_STELEM_R8:
2668                                 mono_array_set (o, double, aindex, sp [2].data.f);
2669                                 break;
2670                         case CEE_STELEM_REF:
2671                                 g_assert (sp [2].type == VAL_OBJ);
2672                                 mono_array_set (o, gpointer, aindex, sp [2].data.p);
2673                                 break;
2674                         default:
2675                                 ves_abort();
2676                         }
2677
2678                         ++ip;
2679                         BREAK;
2680                 }
2681                 CASE (CEE_UNUSED2) 
2682                 CASE (CEE_UNUSED3) 
2683                 CASE (CEE_UNUSED4) 
2684                 CASE (CEE_UNUSED5) 
2685                 CASE (CEE_UNUSED6) 
2686                 CASE (CEE_UNUSED7) 
2687                 CASE (CEE_UNUSED8) 
2688                 CASE (CEE_UNUSED9) 
2689                 CASE (CEE_UNUSED10) 
2690                 CASE (CEE_UNUSED11) 
2691                 CASE (CEE_UNUSED12) 
2692                 CASE (CEE_UNUSED13) 
2693                 CASE (CEE_UNUSED14) 
2694                 CASE (CEE_UNUSED15) 
2695                 CASE (CEE_UNUSED16) 
2696                 CASE (CEE_UNUSED17) ves_abort(); BREAK;
2697                 CASE (CEE_CONV_OVF_I1)
2698                 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
2699                 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
2700                 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
2701                 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
2702                 CASE (CEE_CONV_OVF_U4)
2703                         ++ip;
2704                         /* FIXME: handle other cases */
2705                         if (sp [-1].type == VAL_I32) {
2706                                 /* defined as NOP */
2707                         } else {
2708                                 ves_abort();
2709                         }
2710                         BREAK;
2711                 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2712                 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
2713                 CASE (CEE_UNUSED50) 
2714                 CASE (CEE_UNUSED18) 
2715                 CASE (CEE_UNUSED19) 
2716                 CASE (CEE_UNUSED20) 
2717                 CASE (CEE_UNUSED21) 
2718                 CASE (CEE_UNUSED22) 
2719                 CASE (CEE_UNUSED23) ves_abort(); BREAK;
2720                 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
2721                 CASE (CEE_CKFINITE)
2722                         if (!finite(sp [-1].data.f))
2723                                 THROW_EX (get_exception_arithmetic (), ip);
2724                         ++ip;
2725                         BREAK;
2726                 CASE (CEE_UNUSED24) ves_abort(); BREAK;
2727                 CASE (CEE_UNUSED25) ves_abort(); BREAK;
2728                 CASE (CEE_MKREFANY) ves_abort(); BREAK;
2729                 CASE (CEE_UNUSED59) 
2730                 CASE (CEE_UNUSED60) 
2731                 CASE (CEE_UNUSED61) 
2732                 CASE (CEE_UNUSED62) 
2733                 CASE (CEE_UNUSED63) 
2734                 CASE (CEE_UNUSED64) 
2735                 CASE (CEE_UNUSED65) 
2736                 CASE (CEE_UNUSED66) 
2737                 CASE (CEE_UNUSED67) ves_abort(); BREAK;
2738                 CASE (CEE_LDTOKEN) {
2739                         gpointer handle;
2740                         MonoClass *handle_class;
2741                         ++ip;
2742                         handle = mono_ldtoken (image, read32 (ip), &handle_class);
2743                         ip += 4;
2744                         vt_alloc (&handle_class->byval_arg, sp);
2745                         stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
2746                         ++sp;
2747                         BREAK;
2748                 }
2749                 CASE (CEE_CONV_OVF_I)
2750                         ++ip;
2751                         --sp;
2752                         /* FIXME: check overflow. */
2753                         switch (sp->type) {
2754                         case VAL_I32:
2755                                 sp->data.p = (gpointer)(mono_i) sp->data.i;
2756                                 break;
2757                         case VAL_I64:
2758                                 sp->data.p = (gpointer)(mono_i) sp->data.l;
2759                                 break;
2760                         case VAL_NATI:
2761                                 break;
2762                         case VAL_DOUBLE:
2763                                 sp->data.p = (gpointer)(mono_i) sp->data.f;
2764                                 break;
2765                         default:
2766                                 ves_abort ();
2767                         }
2768                         sp->type = VAL_NATI;
2769                         ++sp;
2770                         BREAK;
2771                 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
2772                 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
2773                 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
2774                 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
2775                 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
2776                 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
2777                 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
2778                 CASE (CEE_ENDFINALLY)
2779                         if (frame->ex)
2780                                 goto handle_fault;
2781                         /*
2782                          * There was no exception, we continue normally at the target address.
2783                          */
2784                         ip = endfinally_ip;
2785                         BREAK;
2786                 CASE (CEE_LEAVE) /* Fall through */
2787                 CASE (CEE_LEAVE_S)
2788                         frame->ip = ip;
2789                         if (*ip == CEE_LEAVE_S) {
2790                                 ++ip;
2791                                 ip += (signed char) *ip;
2792                                 ++ip;
2793                         } else {
2794                                 ++ip;
2795                                 ip += (gint32) read32 (ip);
2796                                 ip += 4;
2797                         }
2798                         /*
2799                          * We may be either inside a try block or inside an handler.
2800                          * In the first case there was no exception and we go on
2801                          * executing the finally handlers and after that resume control
2802                          * at endfinally_ip.
2803                          * In the second case we need to clear the exception and
2804                          * continue directly at the target ip.
2805                          */
2806                         if (!frame->ex) {
2807                                 endfinally_ip = ip;
2808                                 goto handle_finally;
2809                         } else {
2810                                 frame->ex = NULL;
2811                                 frame->ex_handler = NULL;
2812                         }
2813                         BREAK;
2814                 CASE (CEE_UNUSED26) 
2815                 CASE (CEE_UNUSED27) 
2816                 CASE (CEE_UNUSED28) 
2817                 CASE (CEE_UNUSED29) 
2818                 CASE (CEE_UNUSED30) 
2819                 CASE (CEE_UNUSED31) 
2820                 CASE (CEE_UNUSED32) 
2821                 CASE (CEE_UNUSED33) 
2822                 CASE (CEE_UNUSED34) 
2823                 CASE (CEE_UNUSED35) 
2824                 CASE (CEE_UNUSED36) 
2825                 CASE (CEE_UNUSED37) 
2826                 CASE (CEE_UNUSED38) 
2827                 CASE (CEE_UNUSED39) 
2828                 CASE (CEE_UNUSED40) 
2829                 CASE (CEE_UNUSED41) 
2830                 CASE (CEE_UNUSED42) 
2831                 CASE (CEE_UNUSED43) 
2832                 CASE (CEE_UNUSED44) 
2833                 CASE (CEE_UNUSED45) 
2834                 CASE (CEE_UNUSED46) 
2835                 CASE (CEE_UNUSED47) 
2836                 CASE (CEE_UNUSED48)
2837                 CASE (CEE_PREFIX7)
2838                 CASE (CEE_PREFIX6)
2839                 CASE (CEE_PREFIX5)
2840                 CASE (CEE_PREFIX4)
2841                 CASE (CEE_PREFIX3)
2842                 CASE (CEE_PREFIX2)
2843                 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
2844                 /*
2845                  * Note: Exceptions thrown when executing a prefixed opcode need
2846                  * to take into account the number of prefix bytes (usually the
2847                  * throw point is just (ip - n_prefix_bytes).
2848                  */
2849                 SUB_SWITCH
2850                         ++ip;
2851                         switch (*ip) {
2852                         case CEE_ARGLIST: ves_abort(); break;
2853                         case CEE_CEQ: {
2854                                 gint32 result;
2855                                 ++ip;
2856                                 sp -= 2;
2857
2858                                 if (sp->type == VAL_I32)
2859                                         result = sp [0].data.i == (gint)GET_NATI (sp [1]);
2860                                 else if (sp->type == VAL_I64)
2861                                         result = sp [0].data.l == sp [1].data.l;
2862                                 else if (sp->type == VAL_DOUBLE) {
2863                                         if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
2864                                                 result = 0;
2865                                         else
2866                                                 result = sp [0].data.f == sp [1].data.f;
2867                                 } else
2868                                         result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
2869                                 sp->type = VAL_I32;
2870                                 sp->data.i = result;
2871
2872                                 sp++;
2873                                 break;
2874                         }
2875                         case CEE_CGT: {
2876                                 gint32 result;
2877                                 ++ip;
2878                                 sp -= 2;
2879
2880                                 if (sp->type == VAL_I32)
2881                                         result = sp [0].data.i > (gint)GET_NATI (sp [1]);
2882                                 else if (sp->type == VAL_I64)
2883                                         result = sp [0].data.l > sp [1].data.l;
2884                                 else if (sp->type == VAL_DOUBLE) {
2885                                         if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
2886                                                 result = 0;
2887                                         else
2888                                                 result = sp [0].data.f > sp [1].data.f;
2889                                 } else
2890                                         result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
2891                                 sp->type = VAL_I32;
2892                                 sp->data.i = result;
2893
2894                                 sp++;
2895                                 break;
2896                         }
2897                         case CEE_CGT_UN: {
2898                                 gint32 result;
2899                                 ++ip;
2900                                 sp -= 2;
2901
2902                                 if (sp->type == VAL_I32)
2903                                         result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2904                                 else if (sp->type == VAL_I64)
2905                                         result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2906                                 else if (sp->type == VAL_DOUBLE)
2907                                         result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
2908                                 else
2909                                         result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
2910                                 sp->type = VAL_I32;
2911                                 sp->data.i = result;
2912
2913                                 sp++;
2914                                 break;
2915                         }
2916                         case CEE_CLT: {
2917                                 gint32 result;
2918                                 ++ip;
2919                                 sp -= 2;
2920
2921                                 if (sp->type == VAL_I32)
2922                                         result = sp [0].data.i < (gint)GET_NATI (sp [1]);
2923                                 else if (sp->type == VAL_I64)
2924                                         result = sp [0].data.l < sp [1].data.l;
2925                                 else if (sp->type == VAL_DOUBLE) {
2926                                         if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
2927                                                 result = 0;
2928                                         else
2929                                                 result = sp [0].data.f < sp [1].data.f;
2930                                 } else
2931                                         result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
2932                                 sp->type = VAL_I32;
2933                                 sp->data.i = result;
2934
2935                                 sp++;
2936                                 break;
2937                         }
2938                         case CEE_CLT_UN: {
2939                                 gint32 result;
2940                                 ++ip;
2941                                 sp -= 2;
2942
2943                                 if (sp->type == VAL_I32)
2944                                         result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
2945                                 else if (sp->type == VAL_I64)
2946                                         result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
2947                                 else if (sp->type == VAL_DOUBLE)
2948                                         result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
2949                                 else
2950                                         result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
2951                                 sp->type = VAL_I32;
2952                                 sp->data.i = result;
2953
2954                                 sp++;
2955                                 break;
2956                         }
2957                         case CEE_LDFTN:
2958                         case CEE_LDVIRTFTN: {
2959                                 int virtual = *ip == CEE_LDVIRTFTN;
2960                                 MonoMethod *m;
2961                                 guint32 token;
2962                                 ++ip;
2963                                 token = read32 (ip);
2964                                 ip += 4;
2965                                 m = mono_get_method (image, token, NULL);
2966                                 if (!m)
2967                                         THROW_EX (get_exception_missing_method (), ip - 5);
2968                                 if (virtual) {
2969                                         --sp;
2970                                         if (!sp->data.p)
2971                                                 THROW_EX (get_exception_null_reference (), ip - 5);
2972                                         m = get_virtual_method (m, sp);
2973                                 }
2974                                 sp->type = VAL_NATI;
2975                                 sp->data.p = mono_create_method_pointer (m);
2976                                 sp->data.vt.klass = NULL;
2977                                 ++sp;
2978                                 break;
2979                         }
2980                         case CEE_UNUSED56: ves_abort(); break;
2981                         case CEE_LDARG: {
2982                                 guint32 arg_pos;
2983                                 ++ip;
2984                                 arg_pos = read32 (ip);
2985                                 ip += 4;
2986                                 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
2987                                 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2988                                 ++sp;
2989                                 break;
2990                         }
2991                         case CEE_LDARGA: {
2992                                 MonoType *t;
2993                                 MonoClass *c;
2994                                 guint32 anum;
2995
2996                                 ++ip;
2997                                 anum = read32 (ip);
2998                                 ip += 4;
2999                                 t = ARG_TYPE (signature, anum);
3000                                 c = mono_class_from_mono_type (t);
3001                                 sp->data.vt.klass = c;
3002                                 sp->data.vt.vt = ARG_POS (anum);
3003
3004                                 if (c->valuetype)
3005                                         sp->type = VAL_VALUETA;
3006                                 else
3007                                         sp->type = VAL_TP;
3008
3009                                 ++sp;
3010                                 ++ip;
3011                                 break;
3012                         }
3013                         case CEE_STARG: {
3014                                 guint32 arg_pos;
3015                                 ++ip;
3016                                 arg_pos = read32 (ip);
3017                                 ip += 4;
3018                                 --sp;
3019                                 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3020                                 vt_free (sp);
3021                                 break;
3022                         }
3023                         case CEE_LDLOC: {
3024                                 guint32 loc_pos;
3025                                 ++ip;
3026                                 loc_pos = read32 (ip);
3027                                 ip += 4;
3028                                 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3029                                 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3030                                 ++sp;
3031                                 break;
3032                         }
3033                         case CEE_LDLOCA: {
3034                                 MonoType *t;
3035                                 MonoClass *c;
3036                                 guint32 loc_pos;
3037
3038                                 ++ip;
3039                                 loc_pos = read32 (ip);
3040                                 ip += 4;
3041                                 t = LOCAL_TYPE (header, loc_pos);
3042                                 c =  mono_class_from_mono_type (t);
3043                                 sp->data.vt.vt = LOCAL_POS (loc_pos);
3044                                 sp->data.vt.klass = c;
3045
3046                                 if (c->valuetype) 
3047                                         sp->type = VAL_VALUETA;
3048                                 else
3049                                         sp->type = VAL_TP;
3050
3051                                 ++sp;
3052                                 break;
3053                         }
3054                         case CEE_STLOC: {
3055                                 guint32 loc_pos;
3056                                 ++ip;
3057                                 loc_pos = read32 (ip);
3058                                 ip += 4;
3059                                 --sp;
3060                                 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3061                                 vt_free (sp);
3062                                 break;
3063                         }
3064                         case CEE_LOCALLOC:
3065                                 if (sp != frame->stack)
3066                                         THROW_EX (get_exception_execution_engine (), ip - 1);
3067                                 ++ip;
3068                                 sp->data.p = alloca (sp->data.i);
3069                                 sp->type = VAL_TP;
3070                                 break;
3071                         case CEE_UNUSED57: ves_abort(); break;
3072                         case CEE_ENDFILTER: ves_abort(); break;
3073                         case CEE_UNALIGNED_:
3074                                 ++ip;
3075                                 unaligned_address = 1;
3076                                 break;
3077                         case CEE_VOLATILE_:
3078                                 ++ip;
3079                                 volatile_address = 1;
3080                                 break;
3081                         case CEE_TAIL_:
3082                                 ++ip;
3083                                 tail_recursion = 1;
3084                                 break;
3085                         case CEE_INITOBJ: {
3086                                 guint32 token;
3087                                 ++ip;
3088                                 token = read32 (ip);
3089                                 ip += 4;
3090                                 /*
3091                                  * we ignore the value of token (I think we can as unspecified
3092                                  * behavior described in Partition II, 3.5).
3093                                  */
3094                                 --sp;
3095                                 g_assert (sp->type = VAL_VALUETA);
3096                                 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3097                                 break;
3098                         }
3099                         case CEE_UNUSED68: ves_abort(); break;
3100                         case CEE_CPBLK:
3101                                 sp -= 3;
3102                                 if (!sp [0].data.p || !sp [1].data.p)
3103                                         THROW_EX (get_exception_null_reference(), ip - 1);
3104                                 ++ip;
3105                                 /* FIXME: value and size may be int64... */
3106                                 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3107                                 break;
3108                         case CEE_INITBLK:
3109                                 sp -= 3;
3110                                 if (!sp [0].data.p)
3111                                         THROW_EX (get_exception_null_reference(), ip - 1);
3112                                 ++ip;
3113                                 /* FIXME: value and size may be int64... */
3114                                 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3115                                 break;
3116                         case CEE_UNUSED69: ves_abort(); break;
3117                         case CEE_RETHROW:
3118                                 /* 
3119                                  * need to clarify what this should actually do:
3120                                  * start the search from the last found handler in
3121                                  * this method or continue in the caller or what.
3122                                  * Also, do we need to run finally/fault handlers after a retrow?
3123                                  * Well, this implementation will follow the usual search
3124                                  * for an handler, considering the current ip as throw spot.
3125                                  * We need to NULL frame->ex_handler for the later code to
3126                                  * actually run the new found handler.
3127                                  */
3128                                 frame->ex_handler = NULL;
3129                                 THROW_EX (frame->ex, ip - 1);
3130                                 break;
3131                         case CEE_UNUSED: ves_abort(); break;
3132                         case CEE_SIZEOF: {
3133                                 guint32 token;
3134                                 MonoClass *c;
3135                                 ++ip;
3136                                 token = read32 (ip);
3137                                 ip += 4;
3138                                 c = mono_class_get (image, token);
3139                                 sp->type = VAL_I32;
3140                                 sp->data.i = mono_class_value_size (c, NULL);
3141                                 ++sp;
3142                                 break;
3143                         }
3144                         case CEE_REFANYTYPE: ves_abort(); break;
3145                         case CEE_UNUSED52: 
3146                         case CEE_UNUSED53: 
3147                         case CEE_UNUSED54: 
3148                         case CEE_UNUSED55: 
3149                         case CEE_UNUSED70: 
3150                         default:
3151                                 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3152                         }
3153                         continue;
3154                 DEFAULT;
3155                 }
3156         }
3157
3158         g_assert_not_reached ();
3159         /*
3160          * Exception handling code.
3161          * The exception object is stored in frame->ex.
3162          */
3163 #define OFFSET_IN_CLAUSE(clause,offset) \
3164         ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
3165
3166         handle_exception:
3167         {
3168                 int i;
3169                 guint32 ip_offset;
3170                 MonoInvocation *inv;
3171                 MonoMethodHeader *hd;
3172                 MonoExceptionClause *clause;
3173                 char *message;
3174                 MonoObject *ex_obj;
3175                 
3176                 for (inv = frame; inv; inv = inv->parent) {
3177                         hd = ((MonoMethodNormal*)inv->method)->header;
3178                         ip_offset = inv->ip - hd->code;
3179                         for (i = 0; i < hd->num_clauses; ++i) {
3180                                 clause = &hd->clauses [i];
3181                                 if (clause->flags <= 1 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3182                                         if (!clause->flags) {
3183                                                 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3184                                                         /* 
3185                                                          * OK, we found an handler, now we need to execute the finally
3186                                                          * and fault blocks before branching to the handler code.
3187                                                          */
3188                                                         inv->ex_handler = clause;
3189                                                         /*
3190                                                          * It seems that if the catch handler is found in the same method,
3191                                                          * it gets executed before the finally handler.
3192                                                          */
3193                                                         if (inv == frame)
3194                                                                 goto handle_fault;
3195                                                         else
3196                                                                 goto handle_finally;
3197                                                 }
3198                                         } else {
3199                                                 /* FIXME: handle filter clauses */
3200                                                 g_assert (0);
3201                                         }
3202                                 }
3203                         }
3204                 }
3205                 /*
3206                  * If we get here, no handler was found: print a stack trace.
3207                  */
3208                 ex_obj = (MonoObject*)frame->ex;
3209                 message = frame->ex->message? mono_string_to_utf8 (frame->ex->message): NULL;
3210                 g_print ("Unhandled exception %s.%s %s.\n", ex_obj->klass->name_space, ex_obj->klass->name,
3211                                 message?message:"");
3212                 g_free (message);
3213                 dump_frame (frame);
3214                 exit (1);
3215         }
3216         handle_finally:
3217         {
3218                 int i;
3219                 guint32 ip_offset;
3220                 MonoExceptionClause *clause;
3221                 
3222                 ip_offset = frame->ip - header->code;
3223                 for (i = 0; i < header->num_clauses; ++i) {
3224                         clause = &header->clauses [i];
3225                         if (clause->flags == 2 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3226                                 ip = header->code + clause->handler_offset;
3227                                 goto main_loop;
3228                         }
3229                 }
3230                 /*
3231                  * If an exception is set, we need to execute the fault handler, too,
3232                  * otherwise, we continue normally.
3233                  */
3234                 if (frame->ex)
3235                         goto handle_fault;
3236                 ip = endfinally_ip;
3237                 goto main_loop;
3238         }
3239         handle_fault:
3240         {
3241                 int i;
3242                 guint32 ip_offset;
3243                 MonoExceptionClause *clause;
3244                 
3245                 ip_offset = frame->ip - header->code;
3246                 for (i = 0; i < header->num_clauses; ++i) {
3247                         clause = &header->clauses [i];
3248                         if (clause->flags == 3 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3249                                 ip = header->code + clause->handler_offset;
3250                                 goto main_loop;
3251                         }
3252                 }
3253                 /*
3254                  * If the handler for the exception was found in this method, we jump
3255                  * to it right away, otherwise we return and let the caller run
3256                  * the finally, fault and catch blocks.
3257                  * This same code should be present in the endfault opcode, but it
3258                  * is corrently not assigned in the ECMA specs: LAMESPEC.
3259                  */
3260                 if (frame->ex_handler) {
3261                         ip = header->code + frame->ex_handler->handler_offset;
3262                         sp = frame->stack;
3263                         sp->type = VAL_OBJ;
3264                         sp->data.p = frame->ex;
3265                         ++sp;
3266                         goto main_loop;
3267                 }
3268                 DEBUG_LEAVE ();
3269                 return;
3270         }
3271         
3272 }
3273
3274 static int 
3275 ves_exec (MonoAssembly *assembly, int argc, char *argv[])
3276 {
3277         MonoImage *image = assembly->image;
3278         MonoCLIImageInfo *iinfo;
3279         stackval result;
3280         MonoInvocation call;
3281         MonoMethod *method;
3282
3283         iinfo = image->image_info;
3284         method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3285         if (!method)
3286                 g_error ("No entry point method found in %s", image->name);
3287
3288         if (method->signature->param_count) {
3289                 int i;
3290                 stackval argv_array;
3291                 MonoArray *arr = (MonoArray*)mono_array_new (mono_defaults.string_class, argc);
3292                 argv_array.type = VAL_OBJ;
3293                 argv_array.data.p = arr;
3294                 argv_array.data.vt.klass = NULL;
3295                 for (i=0; i < argc; ++i) {
3296                         mono_array_set (arr, gpointer, i, mono_string_new (argv [i]));
3297                 }
3298                 INIT_FRAME (&call, NULL, NULL, &argv_array, &result, method);
3299         } else {
3300                 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
3301         }
3302         
3303         ves_exec_method (&call);
3304         mono_free_method (call.method);
3305
3306         return result.data.i;
3307 }
3308
3309 static void
3310 usage (void)
3311 {
3312         fprintf (stderr,
3313                  "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3314                  "Usage is: mint [options] executable args...\n", VERSION);
3315         fprintf (stderr,
3316                  "Valid Options are:\n"
3317                  "--trace\n"
3318                  "--debug method_name\n"
3319                  "--opcode-count\n");
3320         exit (1);
3321 }
3322
3323 #ifdef RUN_TEST
3324 static void
3325 test_load_class (MonoImage* image)
3326 {
3327         MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEDEF];
3328         MonoClass *klass;
3329         int i;
3330
3331         for (i = 1; i <= t->rows; ++i) {
3332                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3333                 mono_class_metadata_init (klass);
3334         }
3335 }
3336 #endif
3337
3338 typedef struct {
3339         char *name;
3340         gulong offset;
3341 } FieldDesc;
3342
3343 typedef struct {
3344         char *name;
3345         FieldDesc *fields;
3346 } ClassDesc;
3347
3348 static FieldDesc 
3349 typebuilder_fields[] = {
3350         {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
3351         {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
3352         {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
3353         {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
3354         {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
3355         {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
3356         {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
3357         {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
3358         {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
3359         {NULL, 0}
3360 };
3361
3362 static FieldDesc 
3363 modulebuilder_fields[] = {
3364         {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
3365         {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
3366         {NULL, 0}
3367 };
3368
3369 static FieldDesc 
3370 assemblybuilder_fields[] = {
3371         {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
3372         {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
3373         {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
3374         {NULL, 0}
3375 };
3376
3377 static FieldDesc 
3378 ctorbuilder_fields[] = {
3379         {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
3380         {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
3381         {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
3382         {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
3383         {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
3384         {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
3385         {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
3386         {NULL, 0}
3387 };
3388
3389 static FieldDesc 
3390 methodbuilder_fields[] = {
3391         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
3392         {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
3393         {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
3394         {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
3395         {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
3396         {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
3397         {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
3398         {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
3399         {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
3400         {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
3401         {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
3402         {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
3403         {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
3404         {"ncharset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
3405         {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
3406         {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
3407         {NULL, 0}
3408 };
3409
3410 static FieldDesc 
3411 fieldbuilder_fields[] = {
3412         {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
3413         {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
3414         {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
3415         {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
3416         {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
3417         {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
3418         {NULL, 0}
3419 };
3420
3421 static FieldDesc 
3422 propertybuilder_fields[] = {
3423         {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
3424         {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
3425         {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
3426         {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
3427         {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
3428         {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
3429         {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
3430         {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
3431         {NULL, 0}
3432 };
3433
3434 static ClassDesc
3435 emit_classes_to_check [] = {
3436         {"TypeBuilder", typebuilder_fields},
3437         {"ModuleBuilder", modulebuilder_fields},
3438         {"AssemblyBuilder", assemblybuilder_fields},
3439         {"ConstructorBuilder", ctorbuilder_fields},
3440         {"MethodBuilder", methodbuilder_fields},
3441         {"FieldBuilder", fieldbuilder_fields},
3442         {"PropertyBuilder", propertybuilder_fields},
3443         {NULL, NULL}
3444 };
3445
3446 static FieldDesc 
3447 delegate_fields[] = {
3448         {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
3449         {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
3450         {"method", G_STRUCT_OFFSET (MonoDelegate, method)},
3451         {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
3452         {NULL, 0}
3453 };
3454
3455 static ClassDesc
3456 system_classes_to_check [] = {
3457         {"Delegate", delegate_fields},
3458         {NULL, NULL}
3459 };
3460
3461 typedef struct {
3462         char *name;
3463         ClassDesc *types;
3464 } NameSpaceDesc;
3465
3466 static NameSpaceDesc
3467 namespaces_to_check[] = {
3468         {"System.Reflection.Emit", emit_classes_to_check},
3469         {"System", system_classes_to_check},
3470         {NULL, NULL}
3471 };
3472
3473 static void
3474 check_corlib (MonoImage *corlib)
3475 {
3476         MonoClass *klass;
3477         MonoClassField *field;
3478         FieldDesc *fdesc;
3479         ClassDesc *cdesc;
3480         NameSpaceDesc *ndesc;
3481
3482         for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
3483                 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
3484                         klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
3485                         if (!klass)
3486                                 g_error ("Cannot find class %s", cdesc->name);
3487                         mono_class_metadata_init (klass);
3488                         for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
3489                                 field = mono_class_get_field_from_name (klass, fdesc->name);
3490                                 if (!field || (field->offset != fdesc->offset))
3491                                         g_error ("field %s mismatch in class %s (%ld != %ld)", fdesc->name, cdesc->name, (long) fdesc->offset, (long) (field?field->offset:-1));
3492                         }
3493                 }
3494         }
3495 }
3496
3497 int 
3498 main (int argc, char *argv [])
3499 {
3500         MonoAssembly *assembly;
3501         int retval = 0, i, ocount = 0;
3502         char *file;
3503
3504         if (argc < 2)
3505                 usage ();
3506
3507         for (i = 1; i < argc && argv [i][0] == '-'; i++){
3508                 if (strcmp (argv [i], "--trace") == 0)
3509                         tracing = 1;
3510                 if (strcmp (argv [i], "--opcode-count") == 0)
3511                         ocount = 1;
3512                 if (strcmp (argv [i], "--help") == 0)
3513                         usage ();
3514 #if DEBUG_INTERP
3515                 if (strcmp (argv [i], "--debug") == 0)
3516                         db_methods = g_list_append (db_methods, argv [++i]);
3517 #endif
3518         }
3519         
3520         file = argv [i];
3521
3522         if (!file)
3523                 usage ();
3524
3525         mono_init ();
3526         mono_init_icall ();
3527         mono_install_handler (interp_ex_handler);
3528
3529         mono_add_internal_call ("__array_Set", ves_array_set);
3530         mono_add_internal_call ("__array_Get", ves_array_get);
3531
3532         assembly = mono_assembly_open (file, NULL, NULL);
3533         if (!assembly){
3534                 fprintf (stderr, "Can not open image %s\n", file);
3535                 exit (1);
3536         }
3537
3538         mono_thread_init();
3539
3540         frame_thread_id = TlsAlloc ();
3541         TlsSetValue (frame_thread_id, NULL);
3542
3543 #ifdef RUN_TEST
3544         test_load_class (assembly->image);
3545 #else
3546         check_corlib (mono_defaults.corlib);
3547         /*
3548          * skip the program name from the args.
3549          */
3550         ++i;
3551         retval = ves_exec (assembly, argc - i, argv + i);
3552 #endif
3553         mono_thread_cleanup();
3554         
3555         mono_assembly_close (assembly);
3556
3557 #if DEBUG_INTERP
3558         if (ocount) {
3559                 fprintf (stderr, "opcode count: %ld\n", opcode_count);
3560                 fprintf (stderr, "fcall count: %ld\n", fcall_count);
3561         }
3562 #endif
3563         return retval;
3564 }
3565
3566
3567