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