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