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