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);
208 get_virtual_method (MonoImage *image, guint32 token, stackval *args)
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];
230 g_error ("got virtual method: 0x%x\n", token);
235 get_named_exception (const char *name)
239 MonoMethod *method = NULL;
243 klass = mono_class_from_name (mono_defaults.corlib, "System", name);
245 o = mono_new_object (klass);
246 g_assert (o != NULL);
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];
259 INIT_FRAME (&call, NULL, o, NULL, NULL, method);
261 ves_exec_method (&call);
266 get_exception_divide_by_zero ()
268 static MonoObject *ex = NULL;
271 ex = get_named_exception ("DivideByZeroException");
276 get_exception_security ()
278 static MonoObject *ex = NULL;
281 ex = get_named_exception ("SecurityException");
286 get_exception_arithmetic ()
288 static MonoObject *ex = NULL;
291 ex = get_named_exception ("ArithmeticException");
296 get_exception_overflow ()
298 static MonoObject *ex = NULL;
301 ex = get_named_exception ("OverflowException");
306 get_exception_null_reference ()
308 static MonoObject *ex = NULL;
311 ex = get_named_exception ("NullReferenceException");
316 get_exception_execution_engine ()
318 static MonoObject *ex = NULL;
321 ex = get_named_exception ("ExecutionEngineException");
326 stackval_from_data (MonoType *type, stackval *result, const char *data)
329 if (type->type == MONO_TYPE_VALUETYPE)
330 result->type = VAL_VALUETA;
332 result->type = VAL_OBJ;
333 result->data.p = *(gpointer*)data;
336 switch (type->type) {
338 result->type = VAL_I32;
339 result->data.i = *(gint8*)data;
342 case MONO_TYPE_BOOLEAN:
343 result->type = VAL_I32;
344 result->data.i = *(guint8*)data;
347 result->type = VAL_I32;
348 result->data.i = *(gint16*)data;
352 result->type = VAL_I32;
353 result->data.i = *(guint16*)data;
355 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
357 result->type = VAL_I32;
358 result->data.i = *(gint32*)data;
360 case MONO_TYPE_U: /* FIXME: not 64 bit clean */
362 result->type = VAL_I32;
363 result->data.i = *(guint32*)data;
366 result->type = VAL_DOUBLE;
367 result->data.f = *(float*)data;
370 result->type = VAL_I64;
371 result->data.l = *(gint64*)data;
374 result->type = VAL_DOUBLE;
375 result->data.f = *(double*)data;
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:
383 result->type = VAL_OBJ;
384 result->data.p = *(gpointer*)data;
386 case MONO_TYPE_VALUETYPE:
387 if (type->data.klass->enumtype) {
388 result->type = VAL_I32;
389 result->data.i = *(guint32*)data;
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));
397 g_warning ("got type 0x%02x", type->type);
398 g_assert_not_reached ();
403 stackval_to_data (MonoType *type, stackval *val, char *data)
406 *(gpointer*)data = val->data.p;
409 switch (type->type) {
412 *(guint8*)data = val->data.i;
414 case MONO_TYPE_BOOLEAN:
415 *(guint8*)data = (val->data.i != 0);
419 *(guint16*)data = val->data.i;
421 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
422 case MONO_TYPE_U: /* FIXME: not 64 bit clean */
425 *(gint32*)data = val->data.i;
428 *(gint64*)data = val->data.l;
431 *(float*)data = val->data.f;
434 *(double*)data = val->data.f;
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:
442 *(gpointer*)data = val->data.p;
444 case MONO_TYPE_VALUETYPE:
445 if (type->data.klass->enumtype) {
446 *(gint32*)data = val->data.i;
448 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
452 g_warning ("got type %x", type->type);
453 g_assert_not_reached ();
458 mono_get_ansi_string (MonoObject *o)
460 MonoStringObject *s = (MonoStringObject *)o;
464 g_assert (o != NULL);
467 return g_strdup ("");
469 vector = s->c_str->vector;
471 g_assert (vector != NULL);
473 as = g_malloc (s->length + 1);
475 /* fixme: replace with a real unicode/ansi conversion */
476 for (i = 0; i < s->length; i++) {
477 as [i] = vector [i*2];
486 ves_pinvoke_method (MonoInvocation *frame)
488 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)frame->method;
489 MonoMethodSignature *sig = frame->method->signature;
493 int i, acount, rsize, align;
494 stackval *sp = frame->stack_args;
496 GSList *t, *l = NULL;
498 acount = sig->param_count;
500 values = alloca (sizeof (gpointer) * acount);
502 /* fixme: only works on little endian machines */
504 for (i = 0; i < acount; i++) {
506 switch (sig->params [i]->type) {
510 case MONO_TYPE_BOOLEAN:
516 case MONO_TYPE_I: /* FIXME: not 64 bit clean */
519 values[i] = &sp [i].data.i;
522 tmp_float = alloca (sizeof (float));
523 *tmp_float = sp [i].data.f;
524 values[i] = tmp_float;
527 values[i] = &sp [i].data.f;
530 values[i] = &sp [i].data.l;
532 case MONO_TYPE_STRING:
533 g_assert (sp [i].type == VAL_OBJ);
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;
542 * fixme: may we pass the object - I assume
545 values[i] = &sp [i].data.p;
550 g_warning ("not implemented %x",
551 sig->params [i]->type);
552 g_assert_not_reached ();
557 if ((rsize = mono_type_size (sig->ret, &align)))
558 res = alloca (rsize);
560 ffi_call (piinfo->cif, frame->method->addr, res, values);
570 if (sig->ret->type != MONO_TYPE_VOID)
571 stackval_from_data (sig->ret, frame->retval, res);
575 dump_stack (stackval *stack, stackval *sp)
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;
594 #define DEBUG_INTERP 1
601 for (h = 0; h < debug_indent_level; h++)
605 #define DEBUG_ENTER() \
607 MonoClass *klass = frame->method->klass; \
608 debug_indent_level++; \
610 g_print ("Entering %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
612 #define DEBUG_LEAVE() \
614 MonoClass *klass = frame->method->klass; \
616 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
617 debug_indent_level--; \
622 #define DEBUG_ENTER()
623 #define DEBUG_LEAVE()
627 #define LOCAL_POS(n) (locals_pointers [(n)])
628 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
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)])
634 #define THROW_EX(exception,ex_ip) \
636 frame->ip = (ex_ip); \
637 frame->ex = (exception); \
638 goto handle_exception; \
641 typedef struct _vtallocation vtallocation;
643 struct _vtallocation {
646 char data [MONO_ZERO_LEN_ARRAY];
650 * we don't use vtallocation->next, yet
652 #define vt_alloc(vtype,sp) \
653 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
654 if (!(vtype)->byref) { \
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; \
661 (sp)->data.vt.vt = vtalloc->data; \
664 (sp)->data.vt.klass = (vtype)->data.klass; \
668 #define vt_free(sp) \
670 if ((sp)->type == VAL_VALUET) { \
671 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
676 * Need to optimize ALU ops when natural int == int32
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....
682 * The {,.S} versions of many opcodes can/should be merged to reduce code
687 ves_exec_method (MonoInvocation *frame)
689 MonoInvocation child_frame;
690 MonoMethodHeader *header;
691 MonoMethodSignature *signature;
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;
704 if (!frame->method->klass->inited)
705 init_class (frame->method->klass);
709 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
710 ICallMethod icall = frame->method->addr;
716 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
717 ves_pinvoke_method (frame);
722 header = ((MonoMethodNormal *)frame->method)->header;
723 signature = frame->method->signature;
724 image = frame->method->klass->image;
727 * with alloca we get the expected huge performance gain
728 * stackval *stack = g_new0(stackval, header->max_stack);
731 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
733 if (header->num_locals) {
734 int i, align, size, offset = 0;
736 frame->locals = alloca (header->locals_size);
737 locals_pointers = alloca (sizeof(void*) * header->num_locals);
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.
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;
751 * Copy args from stack_args to args.
753 if (signature->params_size) {
754 int i, align, size, offset = 0;
755 int has_this = signature->hasthis;
757 frame->args = alloca (signature->params_size);
758 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
760 args_pointers [0] = frame->args;
761 *(gpointer*) frame->args = frame->obj;
762 offset += sizeof (gpointer);
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;
773 child_frame.parent = frame;
774 frame->child = &child_frame;
781 * using while (ip < end) may result in a 15% performance drop,
782 * but it may be useful for debug
786 /*g_assert (sp >= stack);*/
791 dump_stack (frame->stack, sp);
794 g_print ("0x%04x: %s\n", ip-header->code,
795 *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
805 G_BREAKPOINT (); /* this is not portable... */
811 int n = (*ip)-CEE_LDARG_0;
813 vt_alloc (ARG_TYPE (signature, n), sp);
814 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
822 int n = (*ip)-CEE_LDLOC_0;
824 vt_alloc (LOCAL_TYPE (header, n), sp);
825 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
833 int n = (*ip)-CEE_STLOC_0;
836 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
842 vt_alloc (ARG_TYPE (signature, *ip), sp);
843 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
847 CASE (CEE_LDARGA_S) {
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;
857 sp->data.p = ARG_POS (*ip);
858 sp->data.vt.klass = mono_class_from_mono_type (t);
867 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
873 vt_alloc (LOCAL_TYPE (header, *ip), sp);
874 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
878 CASE (CEE_LDLOCA_S) {
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;
888 sp->data.p = LOCAL_POS (*ip);
897 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
923 sp->data.i = (*ip) - CEE_LDC_I4_0;
930 sp->data.i = *ip; /* FIXME: signed? */
937 sp->data.i = read32 (ip);
944 sp->data.i = read64 (ip);
950 sp->type = VAL_DOUBLE;
951 /* FIXME: ENOENDIAN */
952 sp->data.f = *(float*)(ip);
953 ip += sizeof (float);
958 sp->type = VAL_DOUBLE;
959 /* FIXME: ENOENDIAN */
960 sp->data.f = *(double*) (ip);
961 ip += sizeof (double);
964 CASE (CEE_UNUSED99) ves_abort (); BREAK;
966 if (sp [-1].type == VAL_VALUET) {
968 char *addr = sp [-1].data.vt.vt;
969 MonoType t = sp [-1].data.vt.klass->this_arg;
972 stackval_from_data (&t, sp, addr);
984 CASE (CEE_JMP) ves_abort(); BREAK;
985 CASE (CEE_CALLVIRT) /* Fall through */
987 MonoMethodSignature *csignature;
989 stackval *endsp = sp;
991 int virtual = *ip == CEE_CALLVIRT;
994 * We ignore tail recursion for now.
1001 token = read32 (ip);
1004 child_frame.method = get_virtual_method (image, token, sp);
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);
1010 /* decrement by the actual number of args */
1011 if (csignature->param_count) {
1012 sp -= csignature->param_count;
1013 child_frame.stack_args = sp;
1015 child_frame.stack_args = NULL;
1017 if (csignature->hasthis) {
1018 g_assert (sp >= frame->stack);
1020 g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1021 child_frame.obj = sp->data.p;
1023 child_frame.obj = NULL;
1025 if (csignature->ret->type != MONO_TYPE_VOID) {
1026 vt_alloc (csignature->ret, &retval);
1027 child_frame.retval = &retval;
1029 child_frame.retval = NULL;
1032 child_frame.ex = NULL;
1033 child_frame.ex_handler = NULL;
1035 ves_exec_method (&child_frame);
1037 while (endsp > sp) {
1042 if (child_frame.ex) {
1044 * An exception occurred, need to run finally, fault and catch handlers..
1046 frame->ex = child_frame.ex;
1047 goto handle_finally;
1050 /* need to handle typedbyref ... */
1051 if (csignature->ret->type != MONO_TYPE_VOID) {
1057 CASE (CEE_CALLI) ves_abort(); BREAK;
1059 if (signature->ret->type != MONO_TYPE_VOID) {
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);
1066 *frame->retval = *sp;
1069 if (sp > frame->stack)
1070 g_warning ("more values on stack: %d", sp-frame->stack);
1074 CASE (CEE_BR_S) /* Fall through */
1076 if (*ip == CEE_BR) {
1078 ip += (gint32) read32(ip);
1082 ip += (signed char) *ip;
1086 CASE (CEE_BRFALSE) /* Fall through */
1087 CASE (CEE_BRFALSE_S) {
1089 int near_jump = *ip == CEE_BRFALSE_S;
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;
1100 ip += (signed char)*ip;
1102 ip += (gint32) read32 (ip);
1104 ip += near_jump ? 1: 4;
1107 CASE (CEE_BRTRUE) /* Fall through */
1108 CASE (CEE_BRTRUE_S) {
1110 int near_jump = *ip == CEE_BRTRUE_S;
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;
1121 ip += (signed char)*ip;
1123 ip += (gint32) read32 (ip);
1125 ip += near_jump ? 1: 4;
1128 CASE (CEE_BEQ) /* Fall through */
1131 int near_jump = *ip == CEE_BEQ_S;
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;
1141 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
1144 ip += (signed char)*ip;
1146 ip += (gint32) read32 (ip);
1148 ip += near_jump ? 1: 4;
1151 CASE (CEE_BGE) /* Fall through */
1154 int near_jump = *ip == CEE_BGE_S;
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;
1164 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1167 ip += (signed char)*ip;
1169 ip += (gint32) read32 (ip);
1171 ip += near_jump ? 1: 4;
1174 CASE (CEE_BGT) /* Fall through */
1177 int near_jump = *ip == CEE_BGT_S;
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;
1187 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1190 ip += (signed char)*ip;
1192 ip += (gint32) read32 (ip);
1194 ip += near_jump ? 1: 4;
1197 CASE (CEE_BLT) /* Fall through */
1200 int near_jump = *ip == CEE_BLT_S;
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;
1210 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1213 ip += (signed char)*ip;
1215 ip += (gint32) read32 (ip);
1217 ip += near_jump ? 1: 4;
1220 CASE (CEE_BLE) /* fall through */
1223 int near_jump = *ip == CEE_BLE_S;
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;
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
1239 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1243 ip += (signed char)*ip;
1245 ip += (gint32) read32 (ip);
1247 ip += near_jump ? 1: 4;
1250 CASE (CEE_BNE_UN) /* Fall through */
1251 CASE (CEE_BNE_UN_S) {
1253 int near_jump = *ip == CEE_BNE_UN_S;
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);
1264 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1267 ip += (signed char)*ip;
1269 ip += (gint32) read32 (ip);
1271 ip += near_jump ? 1: 4;
1274 CASE (CEE_BGE_UN) /* Fall through */
1275 CASE (CEE_BGE_UN_S) {
1277 int near_jump = *ip == CEE_BGE_UN_S;
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);
1287 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1290 ip += (signed char)*ip;
1292 ip += (gint32) read32 (ip);
1294 ip += near_jump ? 1: 4;
1297 CASE (CEE_BGT_UN) /* Fall through */
1298 CASE (CEE_BGT_UN_S) {
1300 int near_jump = *ip == CEE_BGT_UN_S;
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);
1310 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1313 ip += (signed char)*ip;
1315 ip += (gint32) read32 (ip);
1317 ip += near_jump ? 1: 4;
1320 CASE (CEE_BLE_UN) /* Fall through */
1321 CASE (CEE_BLE_UN_S) {
1323 int near_jump = *ip == CEE_BLE_UN_S;
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);
1333 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1336 ip += (signed char)*ip;
1338 ip += (gint32) read32 (ip);
1340 ip += near_jump ? 1: 4;
1343 CASE (CEE_BLT_UN) /* Fall through */
1344 CASE (CEE_BLT_UN_S) {
1346 int near_jump = *ip == CEE_BLT_UN_S;
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);
1357 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1360 ip += (signed char)*ip;
1362 ip += (gint32) read32 (ip);
1364 ip += near_jump ? 1: 4;
1369 const unsigned char *st;
1373 st = ip + sizeof (gint32) * n;
1375 if ((guint32)sp->data.i < n) {
1377 ip += sizeof (gint32) * (guint32)sp->data.i;
1378 offset = read32 (ip);
1387 sp[-1].type = VAL_I32;
1388 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1392 sp[-1].type = VAL_I32;
1393 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1397 sp[-1].type = VAL_I32;
1398 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1402 sp[-1].type = VAL_I32;
1403 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1405 CASE (CEE_LDIND_I4) /* Fall through */
1408 sp[-1].type = VAL_I32;
1409 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1413 sp[-1].type = VAL_I64;
1414 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1418 sp[-1].type = VAL_NATI;
1419 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1423 sp[-1].type = VAL_DOUBLE;
1424 sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1428 sp[-1].type = VAL_DOUBLE;
1429 sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1431 CASE (CEE_LDIND_REF)
1433 sp[-1].type = VAL_OBJ;
1434 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1436 CASE (CEE_STIND_REF)
1439 *(gpointer*)sp->data.p = sp[1].data.p;
1444 *(gint8*)sp->data.p = (gint8)sp[1].data.i;
1449 *(gint16*)sp->data.p = (gint16)sp[1].data.i;
1454 *(gint32*)sp->data.p = sp[1].data.i;
1459 *(gint64*)sp->data.p = sp[1].data.l;
1464 *(gint64*)sp->data.p = sp[1].data.l;
1469 *(gfloat*)sp->data.p = (gfloat)sp[1].data.f;
1474 *(gdouble*)sp->data.p = sp[1].data.f;
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;
1487 (char*)sp [-1].data.p += GET_NATI (sp [0]);
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;
1500 (char*)sp [-1].data.p -= GET_NATI (sp [0]);
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;
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;
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;
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? */
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]);
1565 CASE (CEE_REM_UN) ves_abort(); BREAK;
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;
1574 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
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;
1584 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
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;
1594 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
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]);
1604 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
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]);
1614 GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1616 CASE (CEE_SHR_UN) ves_abort(); BREAK;
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);
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);
1637 CASE (CEE_CONV_I1) {
1639 switch (sp [-1].type) {
1641 sp [-1].data.i = (gint8)sp [-1].data.f;
1644 sp [-1].data.i = (gint8)sp [-1].data.l;
1649 sp [-1].data.i = (gint8)sp [-1].data.i;
1652 sp [-1].data.i = (gint8)sp [-1].data.nati;
1655 sp [-1].type = VAL_I32;
1658 CASE (CEE_CONV_I2) {
1660 switch (sp [-1].type) {
1662 sp [-1].data.i = (gint16)sp [-1].data.f;
1665 sp [-1].data.i = (gint16)sp [-1].data.l;
1670 sp [-1].data.i = (gint16)sp [-1].data.i;
1673 sp [-1].data.i = (gint16)sp [-1].data.nati;
1676 sp [-1].type = VAL_I32;
1679 CASE (CEE_CONV_U4) /* Fall through */
1680 CASE (CEE_CONV_I) /* Fall through: FIXME: not 64 bit clean */
1681 CASE (CEE_CONV_I4) {
1683 switch (sp [-1].type) {
1685 sp [-1].data.i = (gint32)sp [-1].data.f;
1688 sp [-1].data.i = (gint32)sp [-1].data.l;
1695 sp [-1].data.i = (gint32)sp [-1].data.p;
1698 sp [-1].type = VAL_I32;
1703 switch (sp [-1].type) {
1705 sp [-1].data.l = (gint64)sp [-1].data.f;
1712 sp [-1].data.l = (gint64)sp [-1].data.i;
1715 sp [-1].data.l = (gint64)sp [-1].data.nati;
1718 sp [-1].type = VAL_I64;
1720 CASE (CEE_CONV_R4) /* Fall through */
1721 CASE (CEE_CONV_R8) {
1723 switch (sp [-1].type) {
1725 sp [-1].data.f = (double)sp [-1].data.f;
1728 sp [-1].data.f = (double)sp [-1].data.l;
1733 sp [-1].data.f = (double)sp [-1].data.i;
1736 sp [-1].data.f = (double)sp [-1].data.nati;
1739 sp [-1].type = VAL_DOUBLE;
1744 /* FIXME: handle other cases */
1745 if (sp [-1].type == VAL_I32) {
1746 /* defined as NOP */
1751 CASE (CEE_CONV_U8) ves_abort(); BREAK;
1752 CASE (CEE_CPOBJ) ves_abort(); BREAK;
1760 token = read32 (ip);
1762 c = mono_class_get (image, token);
1763 addr = sp [-1].data.vt.vt;
1767 vt_alloc (&t, &sp [-1]);
1768 stackval_from_data (&t, &sp [-1], addr);
1778 index = mono_metadata_token_index (read32 (ip));
1781 name = mono_metadata_user_string (image, index);
1782 len = mono_metadata_decode_blob_size (name, &name);
1784 o = mono_new_utf16_string (name, len);
1794 MonoMethodSignature *csig;
1795 stackval *endsp = sp;
1801 token = read32 (ip);
1802 o = newobj (image, token);
1805 /* call the contructor */
1806 child_frame.method = mono_get_method (image, token, o->klass);
1807 csig = child_frame.method->signature;
1810 * First arg is the object.
1812 child_frame.obj = o;
1814 if (csig->param_count) {
1815 sp -= csig->param_count;
1816 child_frame.stack_args = sp;
1818 child_frame.stack_args = NULL;
1821 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1823 child_frame.ex = NULL;
1824 child_frame.ex_handler = NULL;
1826 ves_exec_method (&child_frame);
1828 while (endsp > sp) {
1833 if (child_frame.ex) {
1835 * An exception occurred, need to run finally, fault and catch handlers..
1837 frame->ex = child_frame.ex;
1838 goto handle_finally;
1841 * a constructor returns void, but we need to return the object we created
1848 CASE (CEE_CASTCLASS) {
1852 gboolean found = FALSE;
1855 token = read32 (ip);
1857 g_assert (sp [-1].type == VAL_OBJ);
1859 if ((o = sp [-1].data.p)) {
1863 * fixme: this only works for class casts, but not for
1867 if (c->type_token == token) {
1886 token = read32 (ip);
1888 g_assert (sp [-1].type == VAL_OBJ);
1889 if (!sp [-1].data.p)
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;
1898 CASE (CEE_CONV_R_UN) ves_abort(); BREAK;
1900 CASE (CEE_UNUSED1) ves_abort(); BREAK;
1907 token = read32 (ip);
1909 c = mono_class_get (image, token);
1913 g_assert (o->klass->type_token == c->type_token);
1915 sp [-1].type = VAL_MP;
1916 sp [-1].data.p = (char *)o + sizeof (MonoObject);
1923 THROW_EX (sp->data.p, ip);
1925 CASE (CEE_LDFLDA) /* Fall through */
1928 MonoClassField *field;
1929 guint32 token, offset;
1930 int load_addr = *ip == CEE_LDFLDA;
1933 token = read32 (ip);
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);
1948 sp->data.p = (char*)obj + offset;
1950 vt_alloc (field->type, &sp [-1]);
1951 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
1957 MonoClassField *field;
1958 guint32 token, offset;
1961 token = read32 (ip);
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);
1976 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
1980 CASE (CEE_LDSFLD) /* Fall through */
1981 CASE (CEE_LDSFLDA) {
1983 MonoClassField *field;
1985 int load_addr = *ip == CEE_LDSFLDA;
1988 token = read32 (ip);
1991 /* need to handle fieldrefs */
1992 klass = mono_class_get (image,
1993 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
1996 field = mono_class_get_field (klass, token);
2000 sp->data.p = (char*)klass + field->offset;
2001 sp->data.vt.klass = klass;
2003 vt_alloc (field->type, sp);
2004 stackval_from_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2011 MonoClassField *field;
2015 token = read32 (ip);
2019 /* need to handle fieldrefs */
2020 klass = mono_class_get (image,
2021 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2024 field = mono_class_get_field (klass, token);
2026 stackval_to_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
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;
2046 token = read32 (ip);
2048 class = mono_class_get (image, token);
2049 g_assert (class != NULL);
2051 sp [-1].type = VAL_OBJ;
2052 sp [-1].data.p = mono_value_box (class, &sp [-1]);
2053 /* need to vt_free (sp); */
2065 token = read32 (ip);
2066 class = mono_class_get (image, token);
2067 o = mono_new_szarray (class, sp [-1].data.i);
2070 sp [-1].type = VAL_OBJ;
2080 g_assert (sp [-1].type == VAL_OBJ);
2083 g_assert (o != NULL);
2085 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2087 sp [-1].type = VAL_I32;
2088 sp [-1].data.i = o->bounds [0].length;
2092 CASE (CEE_LDELEMA) {
2094 guint32 esize, token;
2097 token = read32 (ip);
2101 g_assert (sp [0].type == VAL_OBJ);
2104 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2106 g_assert (sp [1].data.i >= 0);
2107 g_assert (sp [1].data.i < o->bounds [0].length);
2109 /* check the array element corresponds to token */
2110 esize = mono_array_element_size ((MonoArrayClass *)o->obj.klass);
2113 sp->data.p = ((MonoArrayObject *)o)->vector + (sp [1].data.i * esize);
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) {
2132 g_assert (sp [0].type == VAL_OBJ);
2135 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2137 g_assert (sp [1].data.i >= 0);
2138 g_assert (sp [1].data.i < o->bounds [0].length);
2142 sp [0].data.i = ((gint8 *)o->vector)[sp [1].data.i];
2143 sp [0].type = VAL_I32;
2146 sp [0].data.i = ((guint8 *)o->vector)[sp [1].data.i];
2147 sp [0].type = VAL_I32;
2150 sp [0].data.i = ((gint16 *)o->vector)[sp [1].data.i];
2151 sp [0].type = VAL_I32;
2154 sp [0].data.i = ((guint16 *)o->vector)[sp [1].data.i];
2155 sp [0].type = VAL_I32;
2158 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i];
2159 sp [0].type = VAL_NATI;
2162 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i];
2163 sp [0].type = VAL_I32;
2166 sp [0].data.i = ((guint32 *)o->vector)[sp [1].data.i];
2167 sp [0].type = VAL_I32;
2170 sp [0].data.l = ((gint64 *)o->vector)[sp [1].data.i];
2171 sp [0].type = VAL_I64;
2174 sp [0].data.f = ((float *)o->vector)[sp [1].data.i];
2175 sp [0].type = VAL_DOUBLE;
2178 sp [0].data.i = ((double *)o->vector)[sp [1].data.i];
2179 sp [0].type = VAL_DOUBLE;
2181 case CEE_LDELEM_REF:
2182 sp [0].data.p = ((gpointer *)o->vector)[sp [1].data.i];
2183 sp [0].type = VAL_OBJ;
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) {
2208 g_assert (sp [0].type == VAL_OBJ);
2211 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2212 ac = (MonoArrayClass *)o->obj.klass;
2214 g_assert (sp [1].data.i >= 0);
2215 g_assert (sp [1].data.i < o->bounds [0].length);
2219 ((gint32 *)o->vector)[sp [1].data.i] =
2223 ((gint8 *)o->vector)[sp [1].data.i] =
2227 ((gint16 *)o->vector)[sp [1].data.i] =
2231 ((gint32 *)o->vector)[sp [1].data.i] =
2235 ((gint64 *)o->vector)[sp [1].data.i] =
2239 ((float *)o->vector)[sp [1].data.i] =
2243 ((double *)o->vector)[sp [1].data.i] =
2246 case CEE_STELEM_REF:
2247 g_assert (sp [2].type == VAL_OBJ);
2251 //fixme: what about type conversions ?
2252 g_assert (v->klass == ac->element_class);
2254 ((gpointer *)o->vector)[sp [1].data.i] =
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)
2288 /* FIXME: handle other cases */
2289 if (sp [-1].type == VAL_I32) {
2290 /* defined as NOP */
2295 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2296 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
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;
2317 CASE (CEE_UNUSED67) ves_abort(); BREAK;
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)
2334 * There was no exception, we continue normally at the target address.
2338 CASE (CEE_LEAVE) /* Fall through */
2340 if (*ip == CEE_LEAVE_S) {
2342 ip += (signed char) *ip;
2346 ip += (gint32) read32 (ip);
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
2354 * In the second case we need to clear the exception and
2355 * continue directly at the target ip.
2359 frame->ex_handler = NULL;
2362 goto handle_finally;
2394 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
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).
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;
2415 arg_pos = read32 (ip);
2417 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
2418 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2422 case CEE_LDARGA: ves_abort(); break;
2426 arg_pos = read32 (ip);
2429 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2436 loc_pos = read32 (ip);
2438 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
2439 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2447 loc_pos = read32 (ip);
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;
2456 sp->data.p = LOCAL_POS (loc_pos);
2464 loc_pos = read32 (ip);
2467 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2472 if (sp != frame->stack)
2473 THROW_EX (get_exception_execution_engine (), ip - 1);
2475 sp->data.p = alloca (sp->data.i);
2478 case CEE_UNUSED57: ves_abort(); break;
2479 case CEE_ENDFILTER: ves_abort(); break;
2480 case CEE_UNALIGNED_:
2482 unaligned_address = 1;
2486 volatile_address = 1;
2495 token = read32 (ip);
2498 * we ignore the value of token (I think we can as unspecified
2499 * behavior described in Partition II, 3.5).
2502 g_assert (sp->type = VAL_VALUETA);
2503 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
2506 case CEE_UNUSED68: ves_abort(); break;
2509 if (!sp [0].data.p || !sp [1].data.p)
2510 THROW_EX (get_exception_null_reference(), ip - 1);
2512 /* FIXME: value and size may be int64... */
2513 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
2518 THROW_EX (get_exception_null_reference(), ip - 1);
2520 /* FIXME: value and size may be int64... */
2521 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
2523 case CEE_UNUSED69: ves_abort(); break;
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.
2535 frame->ex_handler = NULL;
2536 THROW_EX (frame->ex, ip - 1);
2538 case CEE_UNUSED: ves_abort(); break;
2543 token = read32 (ip);
2545 c = mono_class_get (image, token);
2547 sp->data.i = mono_class_value_size (c, NULL);
2551 case CEE_REFANYTYPE: ves_abort(); break;
2558 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
2565 g_assert_not_reached ();
2567 * Exception handling code.
2568 * The exception object is stored in frame->ex.
2570 #define OFFSET_IN_CLAUSE(clause,offset) \
2571 ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
2577 MonoInvocation *inv;
2578 MonoMethodHeader *hd;
2579 MonoExceptionClause *clause;
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))) {
2590 * OK, we found an handler, now we need to execute the finally
2591 * and fault blocks before branching to the handler code.
2593 inv->ex_handler = clause;
2594 goto handle_finally;
2597 /* FIXME: handle filter clauses */
2604 * If we get here, no handler was found: print a stack trace.
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;
2611 * FIXME: print out also the arguments passed to the func.
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);
2624 MonoExceptionClause *clause;
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;
2635 * If an exception is set, we need to execute the fault handler, too,
2636 * otherwise, we continue normally.
2647 MonoExceptionClause *clause;
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;
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.
2664 if (frame->ex_handler) {
2665 ip = header->code + frame->ex_handler->handler_offset;
2668 sp->data.p = frame->ex;
2679 ves_exec (MonoAssembly *assembly, int argc, char *argv[])
2681 MonoImage *image = assembly->image;
2682 MonoCLIImageInfo *iinfo;
2684 MonoInvocation call;
2687 iinfo = image->image_info;
2688 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
2690 if (method->signature->param_count) {
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) {
2699 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
2702 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
2705 ves_exec_method (&call);
2706 mono_free_method (call.method);
2708 return result.data.i;
2715 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
2716 "Usage is: mint [options] executable args...\n", VERSION);
2718 "Valid Options are:\n"
2725 test_load_class (MonoImage* image)
2727 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
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);
2739 main (int argc, char *argv [])
2741 MonoAssembly *assembly;
2748 for (i = 1; argv [i][0] == '-'; i++){
2749 if (strcmp (argv [i], "--trace") == 0)
2758 assembly = mono_assembly_open (file, NULL, NULL);
2760 fprintf (stderr, "Can not open image %s\n", file);
2765 test_load_class (assembly->image);
2767 retval = ves_exec (assembly, argc, argv);
2769 mono_assembly_close (assembly);