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