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