2 * PLEASE NOTE: This is a research prototype.
5 * interp.c: Interpreter for CIL byte codes
8 * Paolo Molaro (lupus@ximian.com)
9 * Miguel de Icaza (miguel@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2001 Ximian, Inc.
25 # define alloca __builtin_alloca
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>
43 /* If true, then we output the opcodes as we interpret them */
44 static int tracing = 0;
46 static int debug_indent_level = 0;
49 * Pull the list of opcodes
51 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
55 #include "mono/cil/opcode.def"
61 * Pull the opcode names
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"
69 #define GET_NATI(sp) ((guint32)(sp).data.i)
70 #define CSIZE(x) (sizeof (x) / 4)
72 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
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; \
81 (frame)->child = NULL; \
84 static void ves_exec_method (MonoInvocation *frame);
86 typedef void (*ICallMethod) (MonoInvocation *frame);
89 ves_real_abort (int line, MonoMethod *mh,
90 const unsigned char *ip, stackval *stack, stackval *sp)
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,
96 g_print ("0x%04x %02x\n",
97 ip-mm->header->code, *ip);
99 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
102 #define ves_abort() ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp)
106 * @klass: klass that needs to be initialized
108 * This routine calls the class constructor for @class if it needs it.
111 init_class (MonoClass *klass)
117 if (!klass->metadata_inited)
118 mono_class_metadata_init (klass);
122 if (klass->parent && !klass->parent->inited)
123 init_class (klass->parent);
127 klass->data = g_malloc0 (klass->class_size);
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);
134 ves_exec_method (&call);
135 mono_free_method (call.method);
139 /* No class constructor found */
144 * @image: image where the object is being referenced
145 * @token: method token to invoke
147 * This routine creates a new object based on the class where the
148 * constructor lives.x
151 newobj (MonoImage *image, guint32 token)
153 MonoObject *result = NULL;
155 switch (mono_metadata_token_code (token)){
156 case MONO_TOKEN_METHOD_DEF: {
159 idx = mono_metadata_typedef_from_method (image, token);
161 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_DEF | idx);
164 case MONO_TOKEN_MEMBER_REF: {
165 guint32 member_cols [MONO_MEMBERREF_SIZE];
166 guint32 mpr_token, table, idx;
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;
176 if (strcmp (mono_metadata_string_heap (image, member_cols[1]), ".ctor"))
177 g_error ("Unhandled: call to non constructor");
180 case 0: /* TypeDef */
181 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_DEF | idx);
183 case 1: /* TypeRef */
184 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_REF | idx);
186 case 2: /* ModuleRef */
187 g_error ("Unhandled: ModuleRef");
189 case 3: /* MethodDef */
190 g_error ("Unhandled: MethodDef");
192 case 4: /* TypeSpec */
193 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_SPEC | idx);
198 g_warning ("dont know how to handle token %08x\n", token);
199 g_assert_not_reached ();
203 init_class (result->klass);
207 #undef DEBUG_VM_DISPATCH
210 get_virtual_method (MonoImage *image, guint32 token, stackval *args)
218 switch (mono_metadata_token_table (token)) {
219 case MONO_TABLE_METHOD:
220 case MONO_TABLE_MEMBERREF:
221 m = mono_get_method (image, token, NULL);
222 objs = &args [-(m->signature->param_count + 1)];
224 klass = objs->data.vt.klass ? objs->data.vt.klass: obj->klass;
225 #ifdef DEBUG_VM_DISPATCH
226 g_print ("%s%smethod lookup %s.%s::%s (cast class %s; real class %s)\n",
227 m->flags & METHOD_ATTRIBUTE_VIRTUAL ? "virtual ": "",
228 m->flags & METHOD_ATTRIBUTE_FINAL ? "final ": "",
229 m->klass->name_space, m->klass->name, m->name, klass->name, obj->klass->name);
231 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
233 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
235 for (; klass && klass != m->klass; klass = klass->parent) {
236 for (i = 0; i < klass->method.count; ++i) {
237 if (!klass->methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
239 if (!strcmp(m->name, klass->methods [i]->name) && mono_metadata_signature_equal (m->signature, klass->methods [i]->signature)) {
240 #ifdef DEBUG_VM_DISPATCH
241 g_print ("\tfound %s%s.%s::%s\n", klass->methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL ? "virtual ": "",
242 klass->name_space, klass->name, klass->methods [i]->name);
244 return klass->methods [i];
250 g_error ("got virtual method: 0x%x\n", token);
255 get_named_exception (const char *name)
259 MonoMethod *method = NULL;
263 klass = mono_class_from_name (mono_defaults.corlib, "System", name);
265 o = mono_new_object (klass);
266 g_assert (o != NULL);
268 for (i = 0; i < klass->method.count; ++i) {
269 if (!strcmp (".ctor", klass->methods [i]->name) &&
270 klass->methods [i]->signature->param_count == 0) {
271 method = klass->methods [i];
279 INIT_FRAME (&call, NULL, o, NULL, NULL, method);
281 ves_exec_method (&call);
286 get_exception_divide_by_zero ()
288 static MonoObject *ex = NULL;
291 ex = get_named_exception ("DivideByZeroException");
296 get_exception_security ()
298 static MonoObject *ex = NULL;
301 ex = get_named_exception ("SecurityException");
306 get_exception_arithmetic ()
308 static MonoObject *ex = NULL;
311 ex = get_named_exception ("ArithmeticException");
316 get_exception_overflow ()
318 static MonoObject *ex = NULL;
321 ex = get_named_exception ("OverflowException");
326 get_exception_null_reference ()
328 static MonoObject *ex = NULL;
331 ex = get_named_exception ("NullReferenceException");
336 get_exception_execution_engine ()
338 static MonoObject *ex = NULL;
341 ex = get_named_exception ("ExecutionEngineException");
346 get_exception_invalid_cast ()
348 static MonoObject *ex = NULL;
351 ex = get_named_exception ("InvalidCastException");
356 stackval_from_data (MonoType *type, stackval *result, const char *data)
359 if (type->type == MONO_TYPE_VALUETYPE)
360 result->type = VAL_VALUETA;
362 result->type = VAL_OBJ;
363 result->data.p = *(gpointer*)data;
366 result->data.vt.klass = mono_class_from_mono_type (type);
367 switch (type->type) {
369 result->type = VAL_I32;
370 result->data.i = *(gint8*)data;
373 case MONO_TYPE_BOOLEAN:
374 result->type = VAL_I32;
375 result->data.i = *(guint8*)data;
378 result->type = VAL_I32;
379 result->data.i = *(gint16*)data;
383 result->type = VAL_I32;
384 result->data.i = *(guint16*)data;
386 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
388 result->type = VAL_I32;
389 result->data.i = *(gint32*)data;
391 case MONO_TYPE_U: /* FIXME: not 64 bit clean */
393 result->type = VAL_I32;
394 result->data.i = *(guint32*)data;
397 result->type = VAL_DOUBLE;
398 result->data.f = *(float*)data;
401 result->type = VAL_I64;
402 result->data.l = *(gint64*)data;
405 result->type = VAL_DOUBLE;
406 result->data.f = *(double*)data;
408 case MONO_TYPE_STRING:
409 case MONO_TYPE_SZARRAY:
410 case MONO_TYPE_CLASS:
411 case MONO_TYPE_OBJECT:
412 case MONO_TYPE_ARRAY:
414 result->type = VAL_OBJ;
415 result->data.p = *(gpointer*)data;
417 case MONO_TYPE_VALUETYPE:
418 if (type->data.klass->enumtype) {
419 result->type = VAL_I32;
420 result->data.i = *(guint32*)data;
422 result->type = VAL_VALUET;
423 result->data.vt.klass = type->data.klass;
424 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
428 g_warning ("got type 0x%02x", type->type);
429 g_assert_not_reached ();
434 stackval_to_data (MonoType *type, stackval *val, char *data)
437 *(gpointer*)data = val->data.p;
440 switch (type->type) {
443 *(guint8*)data = val->data.i;
445 case MONO_TYPE_BOOLEAN:
446 *(guint8*)data = (val->data.i != 0);
450 *(guint16*)data = val->data.i;
452 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
453 case MONO_TYPE_U: /* FIXME: not 64 bit clean */
456 *(gint32*)data = val->data.i;
459 *(gint64*)data = val->data.l;
462 *(float*)data = val->data.f;
465 *(double*)data = val->data.f;
467 case MONO_TYPE_STRING:
468 case MONO_TYPE_SZARRAY:
469 case MONO_TYPE_CLASS:
470 case MONO_TYPE_OBJECT:
471 case MONO_TYPE_ARRAY:
473 *(gpointer*)data = val->data.p;
475 case MONO_TYPE_VALUETYPE:
476 if (type->data.klass->enumtype) {
477 *(gint32*)data = val->data.i;
479 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
483 g_warning ("got type %x", type->type);
484 g_assert_not_reached ();
489 mono_get_ansi_string (MonoObject *o)
491 MonoStringObject *s = (MonoStringObject *)o;
495 g_assert (o != NULL);
498 return g_strdup ("");
500 vector = s->c_str->vector;
502 g_assert (vector != NULL);
504 as = g_malloc (s->length + 1);
506 /* fixme: replace with a real unicode/ansi conversion */
507 for (i = 0; i < s->length; i++) {
508 as [i] = vector [i*2];
517 ves_pinvoke_method (MonoInvocation *frame)
519 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)frame->method;
520 MonoMethodSignature *sig = frame->method->signature;
524 int i, acount, rsize, align;
525 stackval *sp = frame->stack_args;
527 GSList *t, *l = NULL;
529 acount = sig->param_count;
531 values = alloca (sizeof (gpointer) * acount);
533 /* fixme: only works on little endian machines */
535 for (i = 0; i < acount; i++) {
537 switch (sig->params [i]->type) {
541 case MONO_TYPE_BOOLEAN:
547 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
550 values[i] = &sp [i].data.i;
553 tmp_float = alloca (sizeof (float));
554 *tmp_float = sp [i].data.f;
555 values[i] = tmp_float;
558 values[i] = &sp [i].data.f;
561 values[i] = &sp [i].data.l;
563 case MONO_TYPE_STRING:
564 g_assert (sp [i].type == VAL_OBJ);
566 if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI && sp [i].data.p) {
567 tmp_string = alloca (sizeof (char *));
568 *tmp_string = mono_get_ansi_string (sp [i].data.p);
569 l = g_slist_prepend (l, *tmp_string);
570 values[i] = tmp_string;
573 * fixme: may we pass the object - I assume
576 values[i] = &sp [i].data.p;
581 g_warning ("not implemented %x",
582 sig->params [i]->type);
583 g_assert_not_reached ();
588 if ((rsize = mono_type_size (sig->ret, &align)))
589 res = alloca (rsize);
591 ffi_call (piinfo->cif, frame->method->addr, res, values);
601 if (sig->ret->type != MONO_TYPE_VOID)
602 stackval_from_data (sig->ret, frame->retval, res);
606 dump_stack (stackval *stack, stackval *sp)
615 case VAL_I32: g_print ("[%d] ", s->data.i); break;
616 case VAL_I64: g_print ("[%lld] ", s->data.l); break;
617 case VAL_DOUBLE: g_print ("[%0.5f] ", s->data.f); break;
618 case VAL_VALUET: g_print ("[vt: %p] ", s->data.vt.vt); break;
619 default: g_print ("[%p] ", s->data.p); break;
625 #define DEBUG_INTERP 1
633 for (h = 0; h < debug_indent_level; h++)
637 #define DEBUG_ENTER() \
639 MonoClass *klass = frame->method->klass; \
640 debug_indent_level++; \
642 g_print ("Entering %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
644 #define DEBUG_LEAVE() \
646 MonoClass *klass = frame->method->klass; \
648 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
649 debug_indent_level--; \
654 #define DEBUG_ENTER()
655 #define DEBUG_LEAVE()
659 #define LOCAL_POS(n) (locals_pointers [(n)])
660 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
662 #define ARG_POS(n) (args_pointers [(n)])
663 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
664 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
666 #define THROW_EX(exception,ex_ip) \
668 frame->ip = (ex_ip); \
669 frame->ex = (exception); \
670 goto handle_exception; \
673 typedef struct _vtallocation vtallocation;
675 struct _vtallocation {
678 char data [MONO_ZERO_LEN_ARRAY];
682 * we don't use vtallocation->next, yet
684 #define vt_alloc(vtype,sp) \
685 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
686 if (!(vtype)->byref) { \
688 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
689 if (!vtalloc || vtalloc->size < size) { \
690 vtalloc = alloca (sizeof (vtallocation) + size); \
691 vtalloc->size = size; \
693 (sp)->data.vt.vt = vtalloc->data; \
696 (sp)->data.vt.klass = (vtype)->data.klass; \
700 #define vt_free(sp) \
702 if ((sp)->type == VAL_VALUET) { \
703 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
708 * Need to optimize ALU ops when natural int == int32
710 * IDEA: if we maintain a stack of ip, sp to be checked
711 * in the return opcode, we could inline simple methods that don't
712 * use the stack or local variables....
714 * The {,.S} versions of many opcodes can/should be merged to reduce code
719 ves_exec_method (MonoInvocation *frame)
721 MonoInvocation child_frame;
722 MonoMethodHeader *header;
723 MonoMethodSignature *signature;
725 const unsigned char *endfinally_ip;
726 register const unsigned char *ip;
727 register stackval *sp;
728 void **locals_pointers;
729 void **args_pointers;
730 unsigned char tail_recursion = 0;
731 unsigned char unaligned_address = 0;
732 unsigned char volatile_address = 0;
733 vtallocation *vtalloc = NULL;
736 if (!frame->method->klass->inited)
737 init_class (frame->method->klass);
741 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
742 ICallMethod icall = frame->method->addr;
748 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
749 ves_pinvoke_method (frame);
754 header = ((MonoMethodNormal *)frame->method)->header;
755 signature = frame->method->signature;
756 image = frame->method->klass->image;
759 * with alloca we get the expected huge performance gain
760 * stackval *stack = g_new0(stackval, header->max_stack);
763 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
765 if (header->num_locals) {
766 int i, align, size, offset = 0;
768 frame->locals = alloca (header->locals_size);
769 locals_pointers = alloca (sizeof(void*) * header->num_locals);
771 * yes, we do it unconditionally, because it needs to be done for
772 * some cases anyway and checking for that would be even slower.
774 memset (frame->locals, 0, header->locals_size);
775 for (i = 0; i < header->num_locals; ++i) {
776 locals_pointers [i] = frame->locals + offset;
777 size = mono_type_size (header->locals [i], &align);
778 offset += offset % align;
783 * Copy args from stack_args to args.
785 if (signature->params_size) {
786 int i, align, size, offset = 0;
787 int has_this = signature->hasthis;
789 frame->args = alloca (signature->params_size);
790 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
792 args_pointers [0] = frame->args;
793 *(gpointer*) frame->args = frame->obj;
794 offset += sizeof (gpointer);
796 for (i = 0; i < signature->param_count; ++i) {
797 args_pointers [i + has_this] = frame->args + offset;
798 stackval_to_data (signature->params [i], frame->stack_args + i, frame->args + offset);
799 size = mono_type_size (signature->params [i], &align);
800 offset += offset % align;
805 child_frame.parent = frame;
806 frame->child = &child_frame;
813 * using while (ip < end) may result in a 15% performance drop,
814 * but it may be useful for debug
818 /*g_assert (sp >= stack);*/
823 dump_stack (frame->stack, sp);
826 g_print ("0x%04x: %s\n", ip-header->code,
827 *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
837 G_BREAKPOINT (); /* this is not portable... */
843 int n = (*ip)-CEE_LDARG_0;
845 vt_alloc (ARG_TYPE (signature, n), sp);
846 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
854 int n = (*ip)-CEE_LDLOC_0;
856 vt_alloc (LOCAL_TYPE (header, n), sp);
857 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
865 int n = (*ip)-CEE_STLOC_0;
868 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
874 vt_alloc (ARG_TYPE (signature, *ip), sp);
875 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
879 CASE (CEE_LDARGA_S) {
884 t = ARG_TYPE (signature, *ip);
885 c = mono_class_from_mono_type (t);
886 sp->data.vt.klass = c;
887 sp->data.vt.vt = ARG_POS (*ip);
890 sp->type = VAL_VALUETA;
901 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
907 vt_alloc (LOCAL_TYPE (header, *ip), sp);
908 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
912 CASE (CEE_LDLOCA_S) {
917 t = LOCAL_TYPE (header, *ip);
918 c = mono_class_from_mono_type (t);
919 sp->data.vt.klass = c;
920 sp->data.p = LOCAL_POS (*ip);
923 sp->type = VAL_VALUETA;
934 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
942 sp->data.vt.klass = NULL;
961 sp->data.i = (*ip) - CEE_LDC_I4_0;
968 sp->data.i = *ip; /* FIXME: signed? */
975 sp->data.i = read32 (ip);
982 sp->data.i = read64 (ip);
988 sp->type = VAL_DOUBLE;
989 /* FIXME: ENOENDIAN */
990 sp->data.f = *(float*)(ip);
991 ip += sizeof (float);
996 sp->type = VAL_DOUBLE;
997 /* FIXME: ENOENDIAN */
998 sp->data.f = *(double*) (ip);
999 ip += sizeof (double);
1002 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1004 if (sp [-1].type == VAL_VALUET) {
1006 char *addr = sp [-1].data.vt.vt;
1007 MonoType t = sp [-1].data.vt.klass->this_arg;
1010 stackval_from_data (&t, sp, addr);
1022 CASE (CEE_JMP) ves_abort(); BREAK;
1023 CASE (CEE_CALLVIRT) /* Fall through */
1025 MonoMethodSignature *csignature;
1027 stackval *endsp = sp;
1029 int virtual = *ip == CEE_CALLVIRT;
1032 * We ignore tail recursion for now.
1039 token = read32 (ip);
1042 child_frame.method = get_virtual_method (image, token, sp);
1044 child_frame.method = mono_get_method (image, token, NULL);
1045 csignature = child_frame.method->signature;
1046 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1047 /* decrement by the actual number of args */
1048 if (csignature->param_count) {
1049 sp -= csignature->param_count;
1050 child_frame.stack_args = sp;
1052 child_frame.stack_args = NULL;
1054 if (csignature->hasthis) {
1055 g_assert (sp >= frame->stack);
1057 g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1058 child_frame.obj = sp->data.p;
1060 child_frame.obj = NULL;
1062 if (csignature->ret->type != MONO_TYPE_VOID) {
1063 vt_alloc (csignature->ret, &retval);
1064 child_frame.retval = &retval;
1066 child_frame.retval = NULL;
1069 child_frame.ex = NULL;
1070 child_frame.ex_handler = NULL;
1072 ves_exec_method (&child_frame);
1074 while (endsp > sp) {
1079 if (child_frame.ex) {
1081 * An exception occurred, need to run finally, fault and catch handlers..
1083 frame->ex = child_frame.ex;
1084 goto handle_finally;
1087 /* need to handle typedbyref ... */
1088 if (csignature->ret->type != MONO_TYPE_VOID) {
1094 CASE (CEE_CALLI) ves_abort(); BREAK;
1096 if (signature->ret->type != MONO_TYPE_VOID) {
1098 if (sp->type == VAL_VALUET) {
1099 /* the caller has already allocated the memory */
1100 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1103 *frame->retval = *sp;
1106 if (sp > frame->stack)
1107 g_warning ("more values on stack: %d", sp-frame->stack);
1111 CASE (CEE_BR_S) /* Fall through */
1113 if (*ip == CEE_BR) {
1115 ip += (gint32) read32(ip);
1119 ip += (signed char) *ip;
1123 CASE (CEE_BRFALSE) /* Fall through */
1124 CASE (CEE_BRFALSE_S) {
1126 int near_jump = *ip == CEE_BRFALSE_S;
1130 case VAL_I32: result = sp->data.i == 0; break;
1131 case VAL_I64: result = sp->data.l == 0; break;
1132 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1133 default: result = sp->data.p == NULL; break;
1137 ip += (signed char)*ip;
1139 ip += (gint32) read32 (ip);
1141 ip += near_jump ? 1: 4;
1144 CASE (CEE_BRTRUE) /* Fall through */
1145 CASE (CEE_BRTRUE_S) {
1147 int near_jump = *ip == CEE_BRTRUE_S;
1151 case VAL_I32: result = sp->data.i != 0; break;
1152 case VAL_I64: result = sp->data.l != 0; break;
1153 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1154 default: result = sp->data.p != NULL; break;
1158 ip += (signed char)*ip;
1160 ip += (gint32) read32 (ip);
1162 ip += near_jump ? 1: 4;
1165 CASE (CEE_BEQ) /* Fall through */
1168 int near_jump = *ip == CEE_BEQ_S;
1171 if (sp->type == VAL_I32)
1172 result = sp [0].data.i == GET_NATI (sp [1]);
1173 else if (sp->type == VAL_I64)
1174 result = sp [0].data.l == sp [1].data.l;
1175 else if (sp->type == VAL_DOUBLE)
1176 result = sp [0].data.f == sp [1].data.f;
1178 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
1181 ip += (signed char)*ip;
1183 ip += (gint32) read32 (ip);
1185 ip += near_jump ? 1: 4;
1188 CASE (CEE_BGE) /* Fall through */
1191 int near_jump = *ip == CEE_BGE_S;
1194 if (sp->type == VAL_I32)
1195 result = sp [0].data.i >= GET_NATI (sp [1]);
1196 else if (sp->type == VAL_I64)
1197 result = sp [0].data.l >= sp [1].data.l;
1198 else if (sp->type == VAL_DOUBLE)
1199 result = sp [0].data.f >= sp [1].data.f;
1201 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1204 ip += (signed char)*ip;
1206 ip += (gint32) read32 (ip);
1208 ip += near_jump ? 1: 4;
1211 CASE (CEE_BGT) /* Fall through */
1214 int near_jump = *ip == CEE_BGT_S;
1217 if (sp->type == VAL_I32)
1218 result = sp [0].data.i > GET_NATI (sp [1]);
1219 else if (sp->type == VAL_I64)
1220 result = sp [0].data.l > sp [1].data.l;
1221 else if (sp->type == VAL_DOUBLE)
1222 result = sp [0].data.f > sp [1].data.f;
1224 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1227 ip += (signed char)*ip;
1229 ip += (gint32) read32 (ip);
1231 ip += near_jump ? 1: 4;
1234 CASE (CEE_BLT) /* Fall through */
1237 int near_jump = *ip == CEE_BLT_S;
1240 if (sp->type == VAL_I32)
1241 result = sp[0].data.i < GET_NATI(sp[1]);
1242 else if (sp->type == VAL_I64)
1243 result = sp[0].data.l < sp[1].data.l;
1244 else if (sp->type == VAL_DOUBLE)
1245 result = sp[0].data.f < sp[1].data.f;
1247 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1250 ip += (signed char)*ip;
1252 ip += (gint32) read32 (ip);
1254 ip += near_jump ? 1: 4;
1257 CASE (CEE_BLE) /* fall through */
1260 int near_jump = *ip == CEE_BLE_S;
1264 if (sp->type == VAL_I32)
1265 result = sp [0].data.i <= GET_NATI (sp [1]);
1266 else if (sp->type == VAL_I64)
1267 result = sp [0].data.l <= sp [1].data.l;
1268 else if (sp->type == VAL_DOUBLE)
1269 result = sp [0].data.f <= sp [1].data.f;
1272 * FIXME: here and in other places GET_NATI on the left side
1273 * _will_ be wrong when we change the macro to work on 64 buts
1276 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1280 ip += (signed char)*ip;
1282 ip += (gint32) read32 (ip);
1284 ip += near_jump ? 1: 4;
1287 CASE (CEE_BNE_UN) /* Fall through */
1288 CASE (CEE_BNE_UN_S) {
1290 int near_jump = *ip == CEE_BNE_UN_S;
1293 if (sp->type == VAL_I32)
1294 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1295 else if (sp->type == VAL_I64)
1296 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1297 else if (sp->type == VAL_DOUBLE)
1298 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1299 (sp [0].data.f != sp [1].data.f);
1301 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1304 ip += (signed char)*ip;
1306 ip += (gint32) read32 (ip);
1308 ip += near_jump ? 1: 4;
1311 CASE (CEE_BGE_UN) /* Fall through */
1312 CASE (CEE_BGE_UN_S) {
1314 int near_jump = *ip == CEE_BGE_UN_S;
1317 if (sp->type == VAL_I32)
1318 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1319 else if (sp->type == VAL_I64)
1320 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1321 else if (sp->type == VAL_DOUBLE)
1322 result = !isless (sp [0].data.f,sp [1].data.f);
1324 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1327 ip += (signed char)*ip;
1329 ip += (gint32) read32 (ip);
1331 ip += near_jump ? 1: 4;
1334 CASE (CEE_BGT_UN) /* Fall through */
1335 CASE (CEE_BGT_UN_S) {
1337 int near_jump = *ip == CEE_BGT_UN_S;
1340 if (sp->type == VAL_I32)
1341 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1342 else if (sp->type == VAL_I64)
1343 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1344 else if (sp->type == VAL_DOUBLE)
1345 result = isgreater (sp [0].data.f, sp [1].data.f);
1347 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1350 ip += (signed char)*ip;
1352 ip += (gint32) read32 (ip);
1354 ip += near_jump ? 1: 4;
1357 CASE (CEE_BLE_UN) /* Fall through */
1358 CASE (CEE_BLE_UN_S) {
1360 int near_jump = *ip == CEE_BLE_UN_S;
1363 if (sp->type == VAL_I32)
1364 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1365 else if (sp->type == VAL_I64)
1366 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1367 else if (sp->type == VAL_DOUBLE)
1368 result = islessequal (sp [0].data.f, sp [1].data.f);
1370 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1373 ip += (signed char)*ip;
1375 ip += (gint32) read32 (ip);
1377 ip += near_jump ? 1: 4;
1380 CASE (CEE_BLT_UN) /* Fall through */
1381 CASE (CEE_BLT_UN_S) {
1383 int near_jump = *ip == CEE_BLT_UN_S;
1386 if (sp->type == VAL_I32)
1387 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1388 else if (sp->type == VAL_I64)
1389 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1390 else if (sp->type == VAL_DOUBLE)
1391 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1392 (sp [0].data.f < sp [1].data.f);
1394 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1397 ip += (signed char)*ip;
1399 ip += (gint32) read32 (ip);
1401 ip += near_jump ? 1: 4;
1406 const unsigned char *st;
1410 st = ip + sizeof (gint32) * n;
1412 if ((guint32)sp->data.i < n) {
1414 ip += sizeof (gint32) * (guint32)sp->data.i;
1415 offset = read32 (ip);
1424 sp[-1].type = VAL_I32;
1425 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1429 sp[-1].type = VAL_I32;
1430 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1434 sp[-1].type = VAL_I32;
1435 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1439 sp[-1].type = VAL_I32;
1440 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1442 CASE (CEE_LDIND_I4) /* Fall through */
1445 sp[-1].type = VAL_I32;
1446 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1450 sp[-1].type = VAL_I64;
1451 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1455 sp[-1].type = VAL_NATI;
1456 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1460 sp[-1].type = VAL_DOUBLE;
1461 sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1465 sp[-1].type = VAL_DOUBLE;
1466 sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1468 CASE (CEE_LDIND_REF)
1470 sp[-1].type = VAL_OBJ;
1471 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1472 sp[-1].data.vt.klass = NULL;
1474 CASE (CEE_STIND_REF)
1477 *(gpointer*)sp->data.p = sp[1].data.p;
1482 *(gint8*)sp->data.p = (gint8)sp[1].data.i;
1487 *(gint16*)sp->data.p = (gint16)sp[1].data.i;
1492 *(gint32*)sp->data.p = sp[1].data.i;
1497 *(gint64*)sp->data.p = sp[1].data.l;
1502 *(gint64*)sp->data.p = sp[1].data.l;
1507 *(gfloat*)sp->data.p = (gfloat)sp[1].data.f;
1512 *(gdouble*)sp->data.p = sp[1].data.f;
1517 /* should probably consider the pointers as unsigned */
1518 if (sp->type == VAL_I32)
1519 sp [-1].data.i += GET_NATI (sp [0]);
1520 else if (sp->type == VAL_I64)
1521 sp [-1].data.l += sp [0].data.l;
1522 else if (sp->type == VAL_DOUBLE)
1523 sp [-1].data.f += sp [0].data.f;
1525 (char*)sp [-1].data.p += GET_NATI (sp [0]);
1530 /* should probably consider the pointers as unsigned */
1531 if (sp->type == VAL_I32)
1532 sp [-1].data.i -= GET_NATI (sp [0]);
1533 else if (sp->type == VAL_I64)
1534 sp [-1].data.l -= sp [0].data.l;
1535 else if (sp->type == VAL_DOUBLE)
1536 sp [-1].data.f -= sp [0].data.f;
1538 (char*)sp [-1].data.p -= GET_NATI (sp [0]);
1543 if (sp->type == VAL_I32)
1544 sp [-1].data.i *= GET_NATI (sp [0]);
1545 else if (sp->type == VAL_I64)
1546 sp [-1].data.l *= sp [0].data.l;
1547 else if (sp->type == VAL_DOUBLE)
1548 sp [-1].data.f *= sp [0].data.f;
1553 if (sp->type == VAL_I32) {
1554 if (GET_NATI (sp [0]) == 0)
1555 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1556 sp [-1].data.i /= GET_NATI (sp [0]);
1557 } else if (sp->type == VAL_I64) {
1558 if (sp [0].data.l == 0)
1559 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1560 sp [-1].data.l /= sp [0].data.l;
1561 } else if (sp->type == VAL_DOUBLE) {
1562 /* set NaN is divisor is 0.0 */
1563 sp [-1].data.f /= sp [0].data.f;
1569 if (sp->type == VAL_I32) {
1570 if (GET_NATI (sp [0]) == 0)
1571 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1572 (guint32)sp [-1].data.i /= (guint32)GET_NATI (sp [0]);
1573 } else if (sp->type == VAL_I64) {
1574 if (sp [0].data.l == 0)
1575 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1576 (guint64)sp [-1].data.l /= (guint64)sp [0].data.l;
1577 } else if (sp->type == VAL_NATI) {
1578 if (GET_NATI (sp [0]) == 0)
1579 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1580 (gulong)sp [-1].data.p /= (gulong)sp [0].data.p;
1586 if (sp->type == VAL_I32) {
1587 if (GET_NATI (sp [0]) == 0)
1588 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1589 sp [-1].data.i %= GET_NATI (sp [0]);
1590 } else if (sp->type == VAL_I64) {
1591 if (sp [0].data.l == 0)
1592 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1593 sp [-1].data.l %= sp [0].data.l;
1594 } else if (sp->type == VAL_DOUBLE) {
1595 /* FIXME: what do we actually do here? */
1598 if (GET_NATI (sp [0]) == 0)
1599 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1600 GET_NATI (sp [-1]) %= GET_NATI (sp [0]);
1603 CASE (CEE_REM_UN) ves_abort(); BREAK;
1607 if (sp->type == VAL_I32)
1608 sp [-1].data.i &= GET_NATI (sp [0]);
1609 else if (sp->type == VAL_I64)
1610 sp [-1].data.l &= sp [0].data.l;
1612 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1617 if (sp->type == VAL_I32)
1618 sp [-1].data.i |= GET_NATI (sp [0]);
1619 else if (sp->type == VAL_I64)
1620 sp [-1].data.l |= sp [0].data.l;
1622 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1627 if (sp->type == VAL_I32)
1628 sp [-1].data.i ^= GET_NATI (sp [0]);
1629 else if (sp->type == VAL_I64)
1630 sp [-1].data.l ^= sp [0].data.l;
1632 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1637 if (sp->type == VAL_I32)
1638 sp [-1].data.i <<= GET_NATI (sp [0]);
1639 else if (sp->type == VAL_I64)
1640 sp [-1].data.l <<= GET_NATI (sp [0]);
1642 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1647 if (sp->type == VAL_I32)
1648 sp [-1].data.i >>= GET_NATI (sp [0]);
1649 else if (sp->type == VAL_I64)
1650 sp [-1].data.l >>= GET_NATI (sp [0]);
1652 GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1654 CASE (CEE_SHR_UN) ves_abort(); BREAK;
1657 if (sp->type == VAL_I32)
1658 sp->data.i = - sp->data.i;
1659 else if (sp->type == VAL_I64)
1660 sp->data.l = - sp->data.l;
1661 else if (sp->type == VAL_DOUBLE)
1662 sp->data.f = - sp->data.f;
1663 else if (sp->type == VAL_NATI)
1664 sp->data.p = (gpointer)(- (int)sp->data.p);
1668 if (sp->type == VAL_I32)
1669 sp->data.i = ~ sp->data.i;
1670 else if (sp->type == VAL_I64)
1671 sp->data.l = ~ sp->data.l;
1672 else if (sp->type == VAL_NATI)
1673 sp->data.p = (gpointer)(~ (int)sp->data.p);
1675 CASE (CEE_CONV_U1) // fall through
1676 CASE (CEE_CONV_I1) {
1678 switch (sp [-1].type) {
1680 sp [-1].data.i = (gint8)sp [-1].data.f;
1683 sp [-1].data.i = (gint8)sp [-1].data.l;
1688 sp [-1].data.i = (gint8)sp [-1].data.i;
1691 sp [-1].data.i = (gint8)sp [-1].data.nati;
1694 sp [-1].type = VAL_I32;
1697 CASE (CEE_CONV_U2) // fall through
1698 CASE (CEE_CONV_I2) {
1700 switch (sp [-1].type) {
1702 sp [-1].data.i = (gint16)sp [-1].data.f;
1705 sp [-1].data.i = (gint16)sp [-1].data.l;
1710 sp [-1].data.i = (gint16)sp [-1].data.i;
1713 sp [-1].data.i = (gint16)sp [-1].data.nati;
1716 sp [-1].type = VAL_I32;
1719 CASE (CEE_CONV_U4) /* Fall through */
1720 CASE (CEE_CONV_I) /* Fall through: FIXME: not 64 bit clean */
1721 CASE (CEE_CONV_I4) {
1723 switch (sp [-1].type) {
1725 sp [-1].data.i = (gint32)sp [-1].data.f;
1728 sp [-1].data.i = (gint32)sp [-1].data.l;
1735 sp [-1].data.i = (gint32)sp [-1].data.p;
1738 sp [-1].type = VAL_I32;
1743 switch (sp [-1].type) {
1745 sp [-1].data.l = (gint64)sp [-1].data.f;
1752 sp [-1].data.l = (gint64)sp [-1].data.i;
1755 sp [-1].data.l = (gint64)sp [-1].data.nati;
1758 sp [-1].type = VAL_I64;
1760 CASE (CEE_CONV_R4) /* Fall through */
1761 CASE (CEE_CONV_R8) {
1763 switch (sp [-1].type) {
1765 sp [-1].data.f = (double)sp [-1].data.f;
1768 sp [-1].data.f = (double)sp [-1].data.l;
1773 sp [-1].data.f = (double)sp [-1].data.i;
1776 sp [-1].data.f = (double)sp [-1].data.nati;
1779 sp [-1].type = VAL_DOUBLE;
1784 /* FIXME: handle other cases */
1785 if (sp [-1].type == VAL_I32) {
1786 /* defined as NOP */
1791 CASE (CEE_CONV_U8) ves_abort(); BREAK;
1792 CASE (CEE_CPOBJ) ves_abort(); BREAK;
1800 token = read32 (ip);
1802 c = mono_class_get (image, token);
1803 addr = sp [-1].data.vt.vt;
1807 vt_alloc (&t, &sp [-1]);
1808 stackval_from_data (&t, &sp [-1], addr);
1818 index = mono_metadata_token_index (read32 (ip));
1821 name = mono_metadata_user_string (image, index);
1822 len = mono_metadata_decode_blob_size (name, &name);
1824 o = mono_new_utf16_string (name, len >> 1);
1827 sp->data.vt.klass = NULL;
1834 MonoMethodSignature *csig;
1835 stackval *endsp = sp;
1841 token = read32 (ip);
1842 o = newobj (image, token);
1845 /* call the contructor */
1846 child_frame.method = mono_get_method (image, token, o->klass);
1847 csig = child_frame.method->signature;
1850 * First arg is the object.
1852 child_frame.obj = o;
1854 if (csig->param_count) {
1855 sp -= csig->param_count;
1856 child_frame.stack_args = sp;
1858 child_frame.stack_args = NULL;
1861 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1863 child_frame.ex = NULL;
1864 child_frame.ex_handler = NULL;
1866 ves_exec_method (&child_frame);
1868 while (endsp > sp) {
1873 if (child_frame.ex) {
1875 * An exception occurred, need to run finally, fault and catch handlers..
1877 frame->ex = child_frame.ex;
1878 goto handle_finally;
1881 * a constructor returns void, but we need to return the object we created
1885 sp->data.vt.klass = o->klass;
1889 CASE (CEE_CASTCLASS) /* Fall through */
1892 MonoClass *c , *oclass;
1894 int do_isinst = *ip == CEE_ISINST;
1895 gboolean found = FALSE;
1898 token = read32 (ip);
1899 c = mono_class_get (image, token);
1901 g_assert (sp [-1].type == VAL_OBJ);
1903 if ((o = sp [-1].data.p)) {
1905 * fixme: this only works for class casts, but not for
1911 sp [-1].data.vt.klass = oclass;
1915 oclass = oclass->parent;
1919 sp [-1].data.p = NULL;
1920 sp [-1].data.vt.klass = NULL;
1922 THROW_EX (get_exception_invalid_cast (), ip - 1);
1928 CASE (CEE_CONV_R_UN) ves_abort(); BREAK;
1930 CASE (CEE_UNUSED1) ves_abort(); BREAK;
1937 token = read32 (ip);
1939 c = mono_class_get (image, token);
1943 g_assert (o->klass->type_token == c->type_token);
1945 sp [-1].type = VAL_MP;
1946 sp [-1].data.p = (char *)o + sizeof (MonoObject);
1953 THROW_EX (sp->data.p, ip);
1955 CASE (CEE_LDFLDA) /* Fall through */
1958 MonoClassField *field;
1959 guint32 token, offset;
1960 int load_addr = *ip == CEE_LDFLDA;
1963 token = read32 (ip);
1966 if (sp [-1].type == VAL_OBJ) {
1967 obj = sp [-1].data.p;
1968 field = mono_class_get_field (obj->klass, token);
1969 offset = field->offset;
1970 } else { /* valuetype */
1971 //g_assert (sp [-1].type == VAL_VALUETA);
1972 obj = sp [-1].data.vt.vt;
1973 field = mono_class_get_field (sp [-1].data.vt.klass, token);
1974 offset = field->offset - sizeof (MonoObject);
1977 sp [-1].type = VAL_TP;
1978 sp [-1].data.p = (char*)obj + offset;
1979 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
1981 vt_alloc (field->type, &sp [-1]);
1982 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
1989 MonoClassField *field;
1990 guint32 token, offset;
1993 token = read32 (ip);
1998 if (sp [0].type == VAL_OBJ) {
1999 obj = sp [0].data.p;
2000 field = mono_class_get_field (obj->klass, token);
2001 offset = field->offset;
2002 } else { /* valuetype */
2003 //g_assert (sp->type == VAL_VALUETA);
2004 obj = sp [0].data.vt.vt;
2005 field = mono_class_get_field (sp [0].data.vt.klass, token);
2006 offset = field->offset - sizeof (MonoObject);
2009 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2013 CASE (CEE_LDSFLD) /* Fall through */
2014 CASE (CEE_LDSFLDA) {
2016 MonoClassField *field;
2018 int load_addr = *ip == CEE_LDSFLDA;
2021 token = read32 (ip);
2024 /* need to handle fieldrefs */
2025 klass = mono_class_get (image,
2026 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2029 field = mono_class_get_field (klass, token);
2033 sp->data.p = MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
2034 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2036 vt_alloc (field->type, sp);
2037 stackval_from_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2044 MonoClassField *field;
2048 token = read32 (ip);
2052 /* need to handle fieldrefs */
2053 klass = mono_class_get (image,
2054 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2057 field = mono_class_get_field (klass, token);
2059 stackval_to_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2063 CASE (CEE_STOBJ) ves_abort(); BREAK;
2064 CASE (CEE_CONV_OVF_I1_UN) ves_abort(); BREAK;
2065 CASE (CEE_CONV_OVF_I2_UN) ves_abort(); BREAK;
2066 CASE (CEE_CONV_OVF_I4_UN) ves_abort(); BREAK;
2067 CASE (CEE_CONV_OVF_I8_UN) ves_abort(); BREAK;
2068 CASE (CEE_CONV_OVF_U1_UN) ves_abort(); BREAK;
2069 CASE (CEE_CONV_OVF_U2_UN) ves_abort(); BREAK;
2070 CASE (CEE_CONV_OVF_U4_UN) ves_abort(); BREAK;
2071 CASE (CEE_CONV_OVF_U8_UN) ves_abort(); BREAK;
2072 CASE (CEE_CONV_OVF_I_UN) ves_abort(); BREAK;
2073 CASE (CEE_CONV_OVF_U_UN) ves_abort(); BREAK;
2079 token = read32 (ip);
2081 class = mono_class_get (image, token);
2082 g_assert (class != NULL);
2084 sp [-1].type = VAL_OBJ;
2085 sp [-1].data.p = mono_value_box (class, &sp [-1]);
2086 /* need to vt_free (sp); */
2098 token = read32 (ip);
2099 class = mono_class_get (image, token);
2100 o = mono_new_szarray (class, sp [-1].data.i);
2103 sp [-1].type = VAL_OBJ;
2113 g_assert (sp [-1].type == VAL_OBJ);
2116 g_assert (o != NULL);
2118 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2120 sp [-1].type = VAL_I32;
2121 sp [-1].data.i = o->bounds [0].length;
2125 CASE (CEE_LDELEMA) {
2127 guint32 esize, token;
2130 token = read32 (ip);
2134 g_assert (sp [0].type == VAL_OBJ);
2137 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2139 g_assert (sp [1].data.i >= 0);
2140 g_assert (sp [1].data.i < o->bounds [0].length);
2142 /* check the array element corresponds to token */
2143 esize = mono_array_element_size ((MonoArrayClass *)o->obj.klass);
2146 sp->data.p = ((MonoArrayObject *)o)->vector + (sp [1].data.i * esize);
2147 sp->data.vt.klass = ((MonoArrayClass *)o->obj.klass)->element_class;
2151 CASE (CEE_LDELEM_I1) /* fall through */
2152 CASE (CEE_LDELEM_U1) /* fall through */
2153 CASE (CEE_LDELEM_I2) /* fall through */
2154 CASE (CEE_LDELEM_U2) /* fall through */
2155 CASE (CEE_LDELEM_I4) /* fall through */
2156 CASE (CEE_LDELEM_U4) /* fall through */
2157 CASE (CEE_LDELEM_I8) /* fall through */
2158 CASE (CEE_LDELEM_I) /* fall through */
2159 CASE (CEE_LDELEM_R4) /* fall through */
2160 CASE (CEE_LDELEM_R8) /* fall through */
2161 CASE (CEE_LDELEM_REF) {
2166 g_assert (sp [0].type == VAL_OBJ);
2169 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2171 g_assert (sp [1].data.i >= 0);
2172 g_assert (sp [1].data.i < o->bounds [0].length);
2176 sp [0].data.i = ((gint8 *)o->vector)[sp [1].data.i];
2177 sp [0].type = VAL_I32;
2180 sp [0].data.i = ((guint8 *)o->vector)[sp [1].data.i];
2181 sp [0].type = VAL_I32;
2184 sp [0].data.i = ((gint16 *)o->vector)[sp [1].data.i];
2185 sp [0].type = VAL_I32;
2188 sp [0].data.i = ((guint16 *)o->vector)[sp [1].data.i];
2189 sp [0].type = VAL_I32;
2192 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i];
2193 sp [0].type = VAL_NATI;
2196 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i];
2197 sp [0].type = VAL_I32;
2200 sp [0].data.i = ((guint32 *)o->vector)[sp [1].data.i];
2201 sp [0].type = VAL_I32;
2204 sp [0].data.l = ((gint64 *)o->vector)[sp [1].data.i];
2205 sp [0].type = VAL_I64;
2208 sp [0].data.f = ((float *)o->vector)[sp [1].data.i];
2209 sp [0].type = VAL_DOUBLE;
2212 sp [0].data.i = ((double *)o->vector)[sp [1].data.i];
2213 sp [0].type = VAL_DOUBLE;
2215 case CEE_LDELEM_REF:
2216 sp [0].data.p = ((gpointer *)o->vector)[sp [1].data.i];
2217 sp [0].data.vt.klass = NULL;
2218 sp [0].type = VAL_OBJ;
2229 CASE (CEE_STELEM_I) /* fall through */
2230 CASE (CEE_STELEM_I1) /* fall through */
2231 CASE (CEE_STELEM_I2) /* fall through */
2232 CASE (CEE_STELEM_I4) /* fall through */
2233 CASE (CEE_STELEM_I8) /* fall through */
2234 CASE (CEE_STELEM_R4) /* fall through */
2235 CASE (CEE_STELEM_R8) /* fall through */
2236 CASE (CEE_STELEM_REF) {
2243 g_assert (sp [0].type == VAL_OBJ);
2246 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2247 ac = (MonoArrayClass *)o->obj.klass;
2249 g_assert (sp [1].data.i >= 0);
2250 g_assert (sp [1].data.i < o->bounds [0].length);
2254 ((gint32 *)o->vector)[sp [1].data.i] =
2258 ((gint8 *)o->vector)[sp [1].data.i] =
2262 ((gint16 *)o->vector)[sp [1].data.i] =
2266 ((gint32 *)o->vector)[sp [1].data.i] =
2270 ((gint64 *)o->vector)[sp [1].data.i] =
2274 ((float *)o->vector)[sp [1].data.i] =
2278 ((double *)o->vector)[sp [1].data.i] =
2281 case CEE_STELEM_REF:
2282 g_assert (sp [2].type == VAL_OBJ);
2286 //fixme: what about type conversions ?
2287 g_assert (v->klass == ac->element_class);
2289 ((gpointer *)o->vector)[sp [1].data.i] =
2315 CASE (CEE_UNUSED17) ves_abort(); BREAK;
2316 CASE (CEE_CONV_OVF_I1) ves_abort(); BREAK;
2317 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
2318 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
2319 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
2320 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
2321 CASE (CEE_CONV_OVF_U4)
2323 /* FIXME: handle other cases */
2324 if (sp [-1].type == VAL_I32) {
2325 /* defined as NOP */
2330 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2331 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
2338 CASE (CEE_UNUSED23) ves_abort(); BREAK;
2339 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
2340 CASE (CEE_CKFINITE) ves_abort(); BREAK;
2341 CASE (CEE_UNUSED24) ves_abort(); BREAK;
2342 CASE (CEE_UNUSED25) ves_abort(); BREAK;
2343 CASE (CEE_MKREFANY) ves_abort(); BREAK;
2352 CASE (CEE_UNUSED67) ves_abort(); BREAK;
2354 //CASE (CEE_CONV_I) ves_abort(); BREAK;
2355 CASE (CEE_CONV_OVF_I) ves_abort(); BREAK;
2356 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
2357 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
2358 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
2359 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
2360 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
2361 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
2362 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
2363 CASE (CEE_ENDFINALLY)
2367 * There was no exception, we continue normally at the target address.
2371 CASE (CEE_LEAVE) /* Fall through */
2373 if (*ip == CEE_LEAVE_S) {
2375 ip += (signed char) *ip;
2379 ip += (gint32) read32 (ip);
2383 * We may be either inside a try block or inside an handler.
2384 * In the first case there was no exception and we go on
2385 * executing the finally handlers and after that resume control
2387 * In the second case we need to clear the exception and
2388 * continue directly at the target ip.
2392 frame->ex_handler = NULL;
2395 goto handle_finally;
2427 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
2429 * Note: Exceptions thrown when executing a prefixed opcode need
2430 * to take into account the number of prefix bytes (usually the
2431 * throw point is just (ip - n_prefix_bytes).
2436 case CEE_ARGLIST: ves_abort(); break;
2442 if (sp->type == VAL_I32)
2443 result = sp [0].data.i == GET_NATI (sp [1]);
2444 else if (sp->type == VAL_I64)
2445 result = sp [0].data.l == sp [1].data.l;
2446 else if (sp->type == VAL_DOUBLE)
2447 result = sp [0].data.f == sp [1].data.f;
2449 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
2451 sp->data.i = result;
2457 case CEE_CGT: ves_abort(); break;
2458 case CEE_CGT_UN: ves_abort(); break;
2459 case CEE_CLT: ves_abort(); break;
2460 case CEE_CLT_UN: ves_abort(); break;
2461 case CEE_LDFTN: ves_abort(); break;
2462 case CEE_LDVIRTFTN: ves_abort(); break;
2463 case CEE_UNUSED56: ves_abort(); break;
2467 arg_pos = read32 (ip);
2469 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
2470 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2474 case CEE_LDARGA: ves_abort(); break;
2478 arg_pos = read32 (ip);
2481 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2488 loc_pos = read32 (ip);
2490 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
2491 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2501 loc_pos = read32 (ip);
2503 t = LOCAL_TYPE (header, loc_pos);
2504 c = mono_class_from_mono_type (t);
2505 sp->data.vt.vt = LOCAL_POS (loc_pos);
2506 sp->data.vt.klass = c;
2509 sp->type = VAL_VALUETA;
2519 loc_pos = read32 (ip);
2522 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2527 if (sp != frame->stack)
2528 THROW_EX (get_exception_execution_engine (), ip - 1);
2530 sp->data.p = alloca (sp->data.i);
2533 case CEE_UNUSED57: ves_abort(); break;
2534 case CEE_ENDFILTER: ves_abort(); break;
2535 case CEE_UNALIGNED_:
2537 unaligned_address = 1;
2541 volatile_address = 1;
2550 token = read32 (ip);
2553 * we ignore the value of token (I think we can as unspecified
2554 * behavior described in Partition II, 3.5).
2557 g_assert (sp->type = VAL_VALUETA);
2558 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
2561 case CEE_UNUSED68: ves_abort(); break;
2564 if (!sp [0].data.p || !sp [1].data.p)
2565 THROW_EX (get_exception_null_reference(), ip - 1);
2567 /* FIXME: value and size may be int64... */
2568 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
2573 THROW_EX (get_exception_null_reference(), ip - 1);
2575 /* FIXME: value and size may be int64... */
2576 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
2578 case CEE_UNUSED69: ves_abort(); break;
2581 * need to clarify what this should actually do:
2582 * start the search from the last found handler in
2583 * this method or continue in the caller or what.
2584 * Also, do we need to run finally/fault handlers after a retrow?
2585 * Well, this implementation will follow the usual search
2586 * for an handler, considering the current ip as throw spot.
2587 * We need to NULL frame->ex_handler for the later code to
2588 * actually run the new found handler.
2590 frame->ex_handler = NULL;
2591 THROW_EX (frame->ex, ip - 1);
2593 case CEE_UNUSED: ves_abort(); break;
2598 token = read32 (ip);
2600 c = mono_class_get (image, token);
2602 sp->data.i = mono_class_value_size (c, NULL);
2606 case CEE_REFANYTYPE: ves_abort(); break;
2613 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
2620 g_assert_not_reached ();
2622 * Exception handling code.
2623 * The exception object is stored in frame->ex.
2625 #define OFFSET_IN_CLAUSE(clause,offset) \
2626 ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
2632 MonoInvocation *inv;
2633 MonoMethodHeader *hd;
2634 MonoExceptionClause *clause;
2636 for (inv = frame; inv; inv = inv->parent) {
2637 hd = ((MonoMethodNormal*)inv->method)->header;
2638 ip_offset = inv->ip - hd->code;
2639 for (i = 0; i < hd->num_clauses; ++i) {
2640 clause = &hd->clauses [i];
2641 if (clause->flags <= 1 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2642 if (!clause->flags) {
2643 if (mono_object_isinst (frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
2645 * OK, we found an handler, now we need to execute the finally
2646 * and fault blocks before branching to the handler code.
2648 inv->ex_handler = clause;
2649 goto handle_finally;
2652 /* FIXME: handle filter clauses */
2659 * If we get here, no handler was found: print a stack trace.
2661 g_print ("Unhandled exception %s.%s.\n", frame->ex->klass->name_space, frame->ex->klass->name);
2662 for (inv = frame, i = 0; inv; inv = inv->parent, ++i) {
2663 MonoClass *k = inv->method->klass;
2664 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
2666 * FIXME: print out also the arguments passed to the func.
2668 g_print ("#%d: 0x%05x in %s.%s::%s (", i, inv->ip - hd->code,
2669 k->name_space, k->name, inv->method->name);
2670 dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
2679 MonoExceptionClause *clause;
2681 ip_offset = frame->ip - header->code;
2682 for (i = 0; i < header->num_clauses; ++i) {
2683 clause = &header->clauses [i];
2684 if (clause->flags == 2 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2685 ip = header->code + clause->handler_offset;
2690 * If an exception is set, we need to execute the fault handler, too,
2691 * otherwise, we continue normally.
2702 MonoExceptionClause *clause;
2704 ip_offset = frame->ip - header->code;
2705 for (i = 0; i < header->num_clauses; ++i) {
2706 clause = &header->clauses [i];
2707 if (clause->flags == 3 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2708 ip = header->code + clause->handler_offset;
2713 * If the handler for the exception was found in this method, we jump
2714 * to it right away, otherwise we return and let the caller run
2715 * the finally, fault and catch blocks.
2716 * This same code should be present in the endfault opcode, but it
2717 * is corrently not assigned in the ECMA specs: LAMESPEC.
2719 if (frame->ex_handler) {
2720 ip = header->code + frame->ex_handler->handler_offset;
2723 sp->data.p = frame->ex;
2734 ves_exec (MonoAssembly *assembly, int argc, char *argv[])
2736 MonoImage *image = assembly->image;
2737 MonoCLIImageInfo *iinfo;
2739 MonoInvocation call;
2742 iinfo = image->image_info;
2743 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
2745 if (method->signature->param_count) {
2746 g_warning ("Main () with arguments not yet supported");
2750 stackval argv_array;
2751 MonoObject *arr = mono_new_szarray (mono_defaults.corlib, mono_defaults.string_token, argc);
2752 argv_array.type = VAL_OBJ;
2753 argv_array.data.p = arr;
2754 for (i=0; i < argc; ++i) {
2756 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
2759 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
2762 ves_exec_method (&call);
2763 mono_free_method (call.method);
2765 return result.data.i;
2772 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
2773 "Usage is: mint [options] executable args...\n", VERSION);
2775 "Valid Options are:\n"
2782 test_load_class (MonoImage* image)
2784 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
2788 for (i = 1; i <= t->rows; ++i) {
2789 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
2790 mono_class_metadata_init (klass);
2796 main (int argc, char *argv [])
2798 MonoAssembly *assembly;
2805 for (i = 1; argv [i][0] == '-'; i++){
2806 if (strcmp (argv [i], "--trace") == 0)
2815 assembly = mono_assembly_open (file, NULL, NULL);
2817 fprintf (stderr, "Can not open image %s\n", file);
2822 test_load_class (assembly->image);
2824 retval = ves_exec (assembly, argc, argv);
2826 mono_assembly_close (assembly);