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.
14 #define _ISOC99_SOURCE
28 # define alloca __builtin_alloca
32 /* trim excessive headers */
33 #include <mono/metadata/image.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/cil-coff.h>
36 #include <mono/metadata/endian.h>
37 #include <mono/metadata/tabledefs.h>
38 #include <mono/metadata/blob.h>
39 #include <mono/metadata/tokentype.h>
40 #include <mono/cli/cli.h>
41 #include <mono/cli/types.h>
45 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
49 #include "mono/cil/opcode.def"
54 static int debug_indent_level = 0;
55 static MonoImage *corlib = NULL;
57 #define GET_NATI(sp) ((guint32)(sp).data.i)
58 #define CSIZE(x) (sizeof (x) / 4)
60 static void ves_exec_method (MonoInvocation *frame);
62 typedef void (*ICallMethod) (MonoMethod *mh, stackval *args);
66 ves_real_abort (int line, MonoMethod *mh,
67 const unsigned char *ip, stackval *stack, stackval *sp)
69 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
70 fprintf (stderr, "Execution aborted in method: %s\n", mh->name);
71 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
73 g_print ("0x%04x %02x\n",
74 ip-mm->header->code, *ip);
76 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
79 #define ves_abort() ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp)
83 * @klass: klass that needs to be initialized
85 * This routine calls the class constructor for @class if it needs it.
88 init_class (MonoClass *klass)
90 guint32 cols [MONO_METHOD_SIZE];
99 call.stack_args = NULL;
104 init_class (klass->parent);
106 m = &klass->image->metadata;
107 t = &m->tables [MONO_TABLE_METHOD];
109 for (i = klass->method.first; i < klass->method.last; ++i) {
110 mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
112 if (strcmp (".cctor", mono_metadata_string_heap (m, cols [MONO_METHOD_NAME])) == 0) {
113 call.method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (i + 1));
114 ves_exec_method (&call);
115 mono_free_method (call.method);
120 /* No class constructor found */
126 * @image: image where the object is being referenced
127 * @token: method token to invoke
129 * This routine creates a new object based on the class where the
130 * constructor lives.x
133 newobj (MonoImage *image, guint32 token)
135 MonoMetadata *m = &image->metadata;
136 MonoObject *result = NULL;
138 switch (mono_metadata_token_code (token)){
139 case MONO_TOKEN_METHOD_DEF: {
140 guint32 idx = mono_metadata_typedef_from_method (m, token);
141 result = mono_object_new (image, MONO_TOKEN_TYPE_DEF | idx);
144 case MONO_TOKEN_MEMBER_REF: {
145 guint32 member_cols [MONO_MEMBERREF_SIZE];
146 guint32 mpr_token, table, idx;
148 mono_metadata_decode_row (
149 &m->tables [MONO_TABLE_MEMBERREF],
150 mono_metadata_token_index (token) - 1,
151 member_cols, CSIZE (member_cols));
152 mpr_token = member_cols [MONO_MEMBERREF_CLASS];
153 table = mpr_token & 7;
154 idx = mpr_token >> 3;
156 if (strcmp (mono_metadata_string_heap (m, member_cols[1]), ".ctor"))
157 g_error ("Unhandled: call to non constructor");
160 case 0: /* TypeDef */
161 result = mono_object_new (image, MONO_TOKEN_TYPE_DEF | idx);
163 case 1: /* TypeRef */
164 result = mono_object_new (image, MONO_TOKEN_TYPE_REF | idx);
166 case 2: /* ModuleRef */
167 g_error ("Unhandled: ModuleRef");
169 case 3: /* MethodDef */
170 g_error ("Unhandled: MethodDef");
172 case 4: /* TypeSpec */
173 result = mono_object_new (image, MONO_TOKEN_TYPE_SPEC | idx);
180 init_class (result->klass);
185 get_virtual_method (MonoImage *image, guint32 token, stackval *args)
187 switch (mono_metadata_token_table (token)) {
188 case MONO_TABLE_METHOD:
189 case MONO_TABLE_MEMBERREF:
190 return mono_get_method (image, token);
192 g_error ("got virtual method: 0x%x\n", token);
197 * When this is tested, export it from cli/.
200 match_signature (const char *name, MonoMethodSignature *sig, MonoMethod *method)
203 MonoMethodSignature *sig2 = method->signature;
205 * compare the signatures.
206 * First the cheaper comparisons.
208 if (sig->param_count != sig2->param_count)
210 if (sig->hasthis != sig2->hasthis)
213 if (sig2->ret) return 0;
215 if (!sig2->ret) return 0;
216 if (sig->ret->type->type != sig2->ret->type->type)
219 for (i = sig->param_count - 1; i >= 0; ++i) {
220 if (sig->params [i]->type->type != sig2->params [i]->type->type)
223 /* compare the function name */
224 return strcmp (name, method->name) == 0;
228 get_named_exception (const char *name)
233 MonoMethodSignature sig = {
238 0, /* sentinel pos */
239 NULL, /* retval -> void */
244 guint32 tdef = mono_typedef_from_name (corlib, name, "System", NULL);
245 o = newobj (corlib, tdef);
246 klass = mono_class_get (corlib, tdef);
248 for (i = 0; i < klass->method.count; ++i) {
249 if (match_signature (".ctor", &sig, klass->methods [i])) {
250 call.method = klass->methods [i];
254 g_assert (call.method);
256 ves_exec_method (&call);
261 get_exception_divide_by_zero ()
263 static MonoObject *ex = NULL;
266 ex = get_named_exception ("DivideByZeroException");
271 mono_isinst (MonoObject *obj, MonoClass *klass)
273 MonoClass *oklass = obj->klass;
277 oklass = oklass->parent;
283 stackval_from_data (MonoType *type, const char *data)
287 result.type = VAL_OBJ;
288 result.data.p = *(gpointer*)data;
291 switch (type->type) {
293 result.type = VAL_I32;
294 result.data.i = *(gint8*)data;
297 case MONO_TYPE_BOOLEAN:
298 result.type = VAL_I32;
299 result.data.i = *(guint8*)data;
302 result.type = VAL_I32;
303 result.data.i = *(gint16*)data;
307 result.type = VAL_I32;
308 result.data.i = *(guint16*)data;
311 result.type = VAL_I32;
312 result.data.i = *(gint32*)data;
315 result.type = VAL_I32;
316 result.data.i = *(guint32*)data;
319 result.type = VAL_DOUBLE;
320 result.data.f = *(float*)data;
323 result.type = VAL_DOUBLE;
324 result.data.f = *(double*)data;
326 case MONO_TYPE_STRING:
327 case MONO_TYPE_SZARRAY:
328 case MONO_TYPE_CLASS:
329 case MONO_TYPE_OBJECT:
330 case MONO_TYPE_ARRAY:
332 result.type = VAL_OBJ;
333 result.data.p = *(gpointer*)data;
336 g_warning ("got type %x", type->type);
337 g_assert_not_reached ();
343 stackval_to_data (MonoType *type, stackval *val, char *data)
346 *(gpointer*)data = val->data.p;
349 switch (type->type) {
352 *(guint8*)data = val->data.i;
354 case MONO_TYPE_BOOLEAN:
355 *(guint8*)data = (val->data.i != 0);
359 *(guint16*)data = val->data.i;
363 *(gint32*)data = val->data.i;
366 *(float*)data = val->data.f;
369 *(double*)data = val->data.f;
371 case MONO_TYPE_STRING:
372 case MONO_TYPE_SZARRAY:
373 case MONO_TYPE_CLASS:
374 case MONO_TYPE_OBJECT:
375 case MONO_TYPE_ARRAY:
377 *(gpointer*)data = val->data.p;
380 g_warning ("got type %x", type->type);
381 g_assert_not_reached ();
386 mono_get_ansi_string (MonoObject *o)
388 MonoStringObject *s = (MonoStringObject *)o;
392 g_assert (o != NULL);
395 return g_strdup ("");
397 vector = s->c_str->vector;
399 g_assert (vector != NULL);
401 as = g_malloc (s->length + 1);
403 /* fixme: replace with a real unicode/ansi conversion */
404 for (i = 0; i < s->length; i++) {
405 as [i] = vector [i*2];
414 ves_pinvoke_method (MonoMethod *mh, stackval *sp)
416 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)mh;
420 int i, acount, rsize, align;
422 GSList *t, *l = NULL;
424 acount = mh->signature->param_count;
426 values = alloca (sizeof (gpointer) * acount);
428 /* fixme: only works on little endian mashines */
430 for (i = 0; i < acount; i++) {
432 switch (mh->signature->params [i]->type->type) {
436 case MONO_TYPE_BOOLEAN:
442 values[i] = &sp [i].data.i;
445 tmp_float = alloca (sizeof (float));
446 *tmp_float = sp [i].data.f;
447 values[i] = tmp_float;
450 values[i] = &sp [i].data.f;
452 case MONO_TYPE_STRING:
453 g_assert (sp [i].type == VAL_OBJ);
455 if (mh->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI && sp [i].data.p) {
456 tmp_string = alloca (sizeof (char *));
457 *tmp_string = mono_get_ansi_string (sp [i].data.p);
458 l = g_slist_prepend (l, *tmp_string);
459 values[i] = tmp_string;
462 * fixme: may we pass the object - I assume
465 values[i] = &sp [i].data.p;
470 g_warning ("not implemented %x",
471 mh->signature->params [i]->type->type);
472 g_assert_not_reached ();
477 if ((rsize = mono_type_size (mh->signature->ret->type, &align)))
478 res = alloca (rsize);
480 ffi_call (piinfo->cif, mh->addr, res, values);
490 if (mh->signature->ret->type)
491 *sp = stackval_from_data (mh->signature->ret->type, res);
495 #define DEBUG_INTERP 0
497 #define OPDEF(a,b,c,d,e,f,g,h,i,j) b,
498 static char *opcode_names[] = {
499 #include "mono/cil/opcode.def"
509 for (h = 0; h < debug_indent_level; h++)
514 dump_stack (stackval *stack, stackval *sp)
526 case VAL_I32: g_print ("[%d] ", s->data.i); break;
527 case VAL_I64: g_print ("[%lld] ", s->data.l); break;
528 case VAL_DOUBLE: g_print ("[%0.5f] ", s->data.f); break;
529 default: g_print ("[%p] ", s->data.p); break;
546 #define LOCAL_POS(n) (locals_pointers [(n)])
547 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
549 #define ARG_POS(n) (args_pointers [(n)])
550 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis]->type : \
551 (sig)->hasthis ? &method_this: (sig)->params [(0)]->type)
553 #define THROW_EX(exception,ex_ip) \
555 frame->ip = (ex_ip); \
556 frame->ex = (exception); \
557 goto handle_exception; \
561 * Need to optimize ALU ops when natural int == int32
563 * IDEA: if we maintain a stack of ip, sp to be checked
564 * in the return opcode, we could inline simple methods that don't
565 * use the stack or local variables....
567 * The {,.S} versions of many opcodes can/should be merged to reduce code
572 ves_exec_method (MonoInvocation *frame)
574 MonoInvocation child_frame;
575 MonoMethodHeader *header;
576 MonoMethodSignature *signature;
578 const unsigned char *endfinally_ip;
579 register const unsigned char *ip;
580 register stackval *sp;
581 void **locals_pointers;
582 void **args_pointers;
585 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
586 ICallMethod icall = frame->method->addr;
588 icall (frame->method, frame->stack_args);
592 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
593 ves_pinvoke_method (frame->method, frame->stack_args);
597 header = ((MonoMethodNormal *)frame->method)->header;
598 signature = frame->method->signature;
599 image = frame->method->image;
602 debug_indent_level++;
604 g_print ("Entering %s\n", frame->method->name);
608 * with alloca we get the expected huge performance gain
609 * stackval *stack = g_new0(stackval, header->max_stack);
612 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
614 if (header->num_locals) {
615 int i, align, size, offset = 0;
617 frame->locals = alloca (header->locals_size);
618 locals_pointers = alloca (sizeof(void*) * header->num_locals);
620 * yes, we do it unconditionally, because it needs to be done for
621 * some cases anyway and checking for that would be even slower.
623 memset (frame->locals, 0, header->locals_size);
624 for (i = 0; i < header->num_locals; ++i) {
625 locals_pointers [i] = frame->locals + offset;
626 size = mono_type_size (header->locals [i], &align);
627 offset += offset % align;
632 * Copy args from stack_args to args.
634 if (signature->params_size) {
635 int i, align, size, offset = 0;
636 int has_this = signature->hasthis;
638 frame->args = alloca (signature->params_size);
639 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
641 args_pointers [0] = frame->args;
642 *(gpointer*) frame->args = frame->obj;
643 offset += sizeof (gpointer);
645 for (i = 0; i < signature->param_count; ++i) {
646 args_pointers [i + has_this] = frame->args + offset;
647 stackval_to_data (signature->params [i]->type, frame->stack_args + i, frame->args + offset);
648 size = mono_type_size (signature->params [i]->type, &align);
649 offset += offset % align;
654 child_frame.parent = frame;
655 frame->child = &child_frame;
662 * using while (ip < end) may result in a 15% performance drop,
663 * but it may be useful for debug
667 /*g_assert (sp >= stack);*/
669 dump_stack (frame->stack, sp);
672 g_print ("0x%04x: %s\n", ip-header->code,
673 *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
682 G_BREAKPOINT (); /* this is not portable... */
688 int n = (*ip)-CEE_LDARG_0;
690 *sp = stackval_from_data (ARG_TYPE (signature, n), ARG_POS (n));
698 int n = (*ip)-CEE_LDLOC_0;
700 *sp = stackval_from_data (LOCAL_TYPE (header, n), LOCAL_POS (n));
708 int n = (*ip)-CEE_STLOC_0;
711 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
716 *sp = stackval_from_data (ARG_TYPE (signature, *ip), ARG_POS (*ip));
723 sp->data.p = ARG_POS (*ip);
727 CASE (CEE_STARG_S) ves_abort(); BREAK;
730 *sp = stackval_from_data (LOCAL_TYPE (header, *ip), LOCAL_POS (*ip));
737 sp->data.p = LOCAL_POS (*ip);
744 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
769 sp->data.i = (*ip) - CEE_LDC_I4_0;
776 sp->data.i = *ip; /* FIXME: signed? */
783 sp->data.i = read32 (ip);
790 sp->data.i = read64 (ip);
796 sp->type = VAL_DOUBLE;
797 /* FIXME: ENOENDIAN */
798 sp->data.f = *(float*)(ip);
799 ip += sizeof (float);
804 sp->type = VAL_DOUBLE;
805 /* FIXME: ENOENDIAN */
806 sp->data.f = *(double*) (ip);
807 ip += sizeof (double);
810 CASE (CEE_UNUSED99) ves_abort (); BREAK;
820 CASE (CEE_JMP) ves_abort(); BREAK;
821 CASE (CEE_CALLVIRT) /* Fall through */
823 MonoMethodSignature *csignature;
826 int virtual = *ip == CEE_CALLVIRT;
834 child_frame.method = get_virtual_method (image, token, sp);
836 child_frame.method = mono_get_method (image, token);
837 csignature = child_frame.method->signature;
838 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
840 /* decrement by the actual number of args */
841 if (csignature->param_count) {
842 sp -= csignature->param_count;
843 child_frame.stack_args = sp;
845 child_frame.stack_args = NULL;
847 if (csignature->hasthis) {
848 g_assert (sp >= frame->stack);
850 g_assert (sp->type == VAL_OBJ);
851 child_frame.obj = sp->data.p;
853 child_frame.obj = NULL;
855 if (csignature->ret->type) {
856 /* FIXME: handle valuetype */
857 child_frame.retval = &retval;
859 child_frame.retval = NULL;
861 ves_exec_method (&child_frame);
862 if (child_frame.ex) {
864 * An exception occurred, need to run finally, fault and catch handlers..
866 frame->ex = child_frame.ex;
870 /* need to handle typedbyref ... */
871 if (csignature->ret->type) {
877 CASE (CEE_CALLI) ves_abort(); BREAK;
879 if (signature->ret->type) {
881 *frame->retval = *sp;
883 if (sp > frame->stack)
884 g_warning ("more values on stack: %d", sp-frame->stack);
887 debug_indent_level--;
892 ip += (signed char) *ip;
895 CASE (CEE_BRFALSE_S) {
900 case VAL_I32: result = sp->data.i == 0; break;
901 case VAL_I64: result = sp->data.l == 0; break;
902 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
903 default: result = sp->data.p == NULL; break;
906 ip += (signed char)*ip;
910 CASE (CEE_BRTRUE_S) {
915 case VAL_I32: result = sp->data.i != 0; break;
916 case VAL_I64: result = sp->data.l != 0; break;
917 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
918 default: result = sp->data.p != NULL; break;
921 ip += (signed char)*ip;
929 if (sp->type == VAL_I32)
930 result = sp [0].data.i == GET_NATI (sp [1]);
931 else if (sp->type == VAL_I64)
932 result = sp [0].data.l == sp [1].data.l;
933 else if (sp->type == VAL_DOUBLE)
934 result = sp [0].data.f == sp [1].data.f;
936 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
938 ip += (signed char)*ip;
946 if (sp->type == VAL_I32)
947 result = sp [0].data.i >= GET_NATI (sp [1]);
948 else if (sp->type == VAL_I64)
949 result = sp [0].data.l >= sp [1].data.l;
950 else if (sp->type == VAL_DOUBLE)
951 result = sp [0].data.f >= sp [1].data.f;
953 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
955 ip += (signed char)*ip;
963 if (sp->type == VAL_I32)
964 result = sp [0].data.i > GET_NATI (sp [1]);
965 else if (sp->type == VAL_I64)
966 result = sp [0].data.l > sp [1].data.l;
967 else if (sp->type == VAL_DOUBLE)
968 result = sp [0].data.f > sp [1].data.f;
970 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
972 ip += (signed char)*ip;
980 if (sp->type == VAL_I32)
981 result = sp[0].data.i < GET_NATI(sp[1]);
982 else if (sp->type == VAL_I64)
983 result = sp[0].data.l < sp[1].data.l;
984 else if (sp->type == VAL_DOUBLE)
985 result = sp[0].data.f < sp[1].data.f;
987 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
989 ip += (signed char)*ip;
998 if (sp->type == VAL_I32)
999 result = sp [0].data.i <= GET_NATI (sp [1]);
1000 else if (sp->type == VAL_I64)
1001 result = sp [0].data.l <= sp [1].data.l;
1002 else if (sp->type == VAL_DOUBLE)
1003 result = sp [0].data.f <= sp [1].data.f;
1006 * FIXME: here and in other places GET_NATI on the left side
1007 * _will_ be wrong when we change the macro to work on 64 buts
1010 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1013 ip += (signed char)*ip;
1017 CASE (CEE_BNE_UN_S) {
1021 if (sp->type == VAL_I32)
1022 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1023 else if (sp->type == VAL_I64)
1024 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1025 else if (sp->type == VAL_DOUBLE)
1026 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1027 (sp [0].data.f != sp [1].data.f);
1029 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1031 ip += (signed char)*ip;
1035 CASE (CEE_BGE_UN_S) {
1039 if (sp->type == VAL_I32)
1040 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1041 else if (sp->type == VAL_I64)
1042 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1043 else if (sp->type == VAL_DOUBLE)
1044 result = !isless (sp [0].data.f,sp [1].data.f);
1046 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1048 ip += (signed char)*ip;
1052 CASE (CEE_BGT_UN_S) {
1056 if (sp->type == VAL_I32)
1057 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1058 else if (sp->type == VAL_I64)
1059 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1060 else if (sp->type == VAL_DOUBLE)
1061 result = isgreater (sp [0].data.f, sp [1].data.f);
1063 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1065 ip += (signed char)*ip;
1069 CASE (CEE_BLE_UN_S) {
1073 if (sp->type == VAL_I32)
1074 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1075 else if (sp->type == VAL_I64)
1076 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1077 else if (sp->type == VAL_DOUBLE)
1078 result = islessequal (sp [0].data.f, sp [1].data.f);
1080 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1082 ip += (signed char)*ip;
1086 CASE (CEE_BLT_UN_S) {
1090 if (sp->type == VAL_I32)
1091 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1092 else if (sp->type == VAL_I64)
1093 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1094 else if (sp->type == VAL_DOUBLE)
1095 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1096 (sp [0].data.f < sp [1].data.f);
1098 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1100 ip += (signed char)*ip;
1104 CASE (CEE_BR) ves_abort(); BREAK;
1105 CASE (CEE_BRFALSE) ves_abort(); BREAK;
1106 CASE (CEE_BRTRUE) ves_abort(); BREAK;
1107 CASE (CEE_BEQ) ves_abort(); BREAK;
1108 CASE (CEE_BGE) ves_abort(); BREAK;
1109 CASE (CEE_BGT) ves_abort(); BREAK;
1110 CASE (CEE_BLE) ves_abort(); BREAK;
1111 CASE (CEE_BLT) ves_abort(); BREAK;
1112 CASE (CEE_BNE_UN) ves_abort(); BREAK;
1113 CASE (CEE_BGE_UN) ves_abort(); BREAK;
1114 CASE (CEE_BGT_UN) ves_abort(); BREAK;
1115 CASE (CEE_BLE_UN) ves_abort(); BREAK;
1116 CASE (CEE_BLT_UN) ves_abort(); BREAK;
1119 const unsigned char *st;
1123 st = ip + sizeof (gint32) * n;
1125 if ((guint32)sp->data.i < n) {
1127 ip += sizeof (gint32) * (guint32)sp->data.i;
1128 offset = read32 (ip);
1137 sp[-1].type = VAL_I32;
1138 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1142 sp[-1].type = VAL_I32;
1143 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1147 sp[-1].type = VAL_I32;
1148 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1152 sp[-1].type = VAL_I32;
1153 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1155 CASE (CEE_LDIND_I4) /* Fall through */
1158 sp[-1].type = VAL_I32;
1159 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1163 sp[-1].type = VAL_I64;
1164 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1168 sp[-1].type = VAL_NATI;
1169 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1173 sp[-1].type = VAL_DOUBLE;
1174 sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1178 sp[-1].type = VAL_DOUBLE;
1179 sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1181 CASE (CEE_LDIND_REF)
1183 sp[-1].type = VAL_OBJ;
1184 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1186 CASE (CEE_STIND_REF)
1189 *(gpointer*)sp->data.p = sp[1].data.p;
1194 *(gint8*)sp->data.p = (gint8)sp[1].data.i;
1199 *(gint16*)sp->data.p = (gint16)sp[1].data.i;
1204 *(gint32*)sp->data.p = sp[1].data.i;
1209 *(gint64*)sp->data.p = sp[1].data.l;
1214 *(gfloat*)sp->data.p = (gfloat)sp[1].data.f;
1219 *(gdouble*)sp->data.p = sp[1].data.f;
1224 /* should probably consider the pointers as unsigned */
1225 if (sp->type == VAL_I32)
1226 sp [-1].data.i += GET_NATI (sp [0]);
1227 else if (sp->type == VAL_I64)
1228 sp [-1].data.l += sp [0].data.l;
1229 else if (sp->type == VAL_DOUBLE)
1230 sp [-1].data.f += sp [0].data.f;
1232 (char*)sp [-1].data.p += GET_NATI (sp [0]);
1237 /* should probably consider the pointers as unsigned */
1238 if (sp->type == VAL_I32)
1239 sp [-1].data.i -= GET_NATI (sp [0]);
1240 else if (sp->type == VAL_I64)
1241 sp [-1].data.l -= sp [0].data.l;
1242 else if (sp->type == VAL_DOUBLE)
1243 sp [-1].data.f -= sp [0].data.f;
1245 (char*)sp [-1].data.p -= GET_NATI (sp [0]);
1250 if (sp->type == VAL_I32)
1251 sp [-1].data.i *= GET_NATI (sp [0]);
1252 else if (sp->type == VAL_I64)
1253 sp [-1].data.l *= sp [0].data.l;
1254 else if (sp->type == VAL_DOUBLE)
1255 sp [-1].data.f *= sp [0].data.f;
1260 if (sp->type == VAL_I32) {
1262 * FIXME: move to handle also the other types
1264 if (GET_NATI (sp [0]) == 0)
1265 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1266 sp [-1].data.i /= GET_NATI (sp [0]);
1267 } else if (sp->type == VAL_I64)
1268 sp [-1].data.l /= sp [0].data.l;
1269 else if (sp->type == VAL_DOUBLE)
1270 sp [-1].data.f /= sp [0].data.f;
1275 if (sp->type == VAL_I32)
1276 (guint32)sp [-1].data.i /= (guint32)GET_NATI (sp [0]);
1277 else if (sp->type == VAL_I64)
1278 (guint64)sp [-1].data.l /= (guint64)sp [0].data.l;
1279 else if (sp->type == VAL_NATI)
1280 (gulong)sp [-1].data.p /= (gulong)sp [0].data.p;
1285 if (sp->type == VAL_I32)
1286 sp [-1].data.i %= GET_NATI (sp [0]);
1287 else if (sp->type == VAL_I64)
1288 sp [-1].data.l %= sp [0].data.l;
1289 else if (sp->type == VAL_DOUBLE)
1290 /* FIXME: what do we actually fo here? */
1293 GET_NATI (sp [-1]) %= GET_NATI (sp [0]);
1295 CASE (CEE_REM_UN) ves_abort(); BREAK;
1299 if (sp->type == VAL_I32)
1300 sp [-1].data.i &= GET_NATI (sp [0]);
1301 else if (sp->type == VAL_I64)
1302 sp [-1].data.l &= sp [0].data.l;
1304 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1309 if (sp->type == VAL_I32)
1310 sp [-1].data.i |= GET_NATI (sp [0]);
1311 else if (sp->type == VAL_I64)
1312 sp [-1].data.l |= sp [0].data.l;
1314 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1319 if (sp->type == VAL_I32)
1320 sp [-1].data.i ^= GET_NATI (sp [0]);
1321 else if (sp->type == VAL_I64)
1322 sp [-1].data.l ^= sp [0].data.l;
1324 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1329 if (sp->type == VAL_I32)
1330 sp [-1].data.i <<= GET_NATI (sp [0]);
1331 else if (sp->type == VAL_I64)
1332 sp [-1].data.l <<= GET_NATI (sp [0]);
1334 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1339 if (sp->type == VAL_I32)
1340 sp [-1].data.i >>= GET_NATI (sp [0]);
1341 else if (sp->type == VAL_I64)
1342 sp [-1].data.l >>= GET_NATI (sp [0]);
1344 GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1346 CASE (CEE_SHR_UN) ves_abort(); BREAK;
1349 if (sp->type == VAL_I32)
1350 sp->data.i = - sp->data.i;
1351 else if (sp->type == VAL_I64)
1352 sp->data.l = - sp->data.l;
1353 else if (sp->type == VAL_DOUBLE)
1354 sp->data.f = - sp->data.f;
1355 else if (sp->type == VAL_NATI)
1356 sp->data.p = (gpointer)(- (m_i)sp->data.p);
1360 if (sp->type == VAL_I32)
1361 sp->data.i = ~ sp->data.i;
1362 else if (sp->type == VAL_I64)
1363 sp->data.l = ~ sp->data.l;
1364 else if (sp->type == VAL_NATI)
1365 sp->data.p = (gpointer)(~ (m_i)sp->data.p);
1367 CASE (CEE_CONV_I1) ves_abort(); BREAK;
1368 CASE (CEE_CONV_I2) ves_abort(); BREAK;
1369 CASE (CEE_CONV_I4) {
1371 /* FIXME: handle other cases. what about sign? */
1373 switch (sp [-1].type) {
1375 sp [-1].data.i = (gint32)sp [-1].data.f;
1376 sp [-1].type = VAL_I32;
1385 CASE (CEE_CONV_I8) ves_abort(); BREAK;
1386 CASE (CEE_CONV_R4) ves_abort(); BREAK;
1389 /* FIXME: handle other cases. what about sign? */
1390 if (sp [-1].type == VAL_I32) {
1391 sp [-1].data.f = (double)sp [-1].data.i;
1392 sp [-1].type = VAL_DOUBLE;
1399 /* FIXME: handle other cases. what about sign? */
1400 if (sp [-1].type == VAL_DOUBLE) {
1401 sp [-1].data.i = (guint32)sp [-1].data.f;
1402 sp [-1].type = VAL_I32;
1409 /* FIXME: handle other cases */
1410 if (sp [-1].type == VAL_I32) {
1411 /* defined as NOP */
1416 CASE (CEE_CONV_U8) ves_abort(); BREAK;
1417 CASE (CEE_CPOBJ) ves_abort(); BREAK;
1418 CASE (CEE_LDOBJ) ves_abort(); BREAK;
1420 guint32 ctor, ttoken;
1421 MonoMetadata *m = &image->metadata;
1430 index = mono_metadata_token_index (read32 (ip));
1433 name = mono_metadata_user_string (m, index);
1434 len = mono_metadata_decode_blob_size (name, &name);
1436 * terminate with 0, maybe we should use another
1437 * constructor and pass the len
1439 data = g_malloc (len + 2);
1440 memcpy (data, name, len + 2);
1441 data [len/2 + 1] = 0;
1443 ctor = mono_get_string_class_info (&ttoken, &cl);
1444 o = mono_object_new (cl, ttoken);
1446 g_assert (o != NULL);
1448 child_frame.method = mono_get_method (cl, ctor);
1450 child_frame.obj = o;
1455 child_frame.stack_args = sp;
1457 g_assert (child_frame.method->signature->call_convention == MONO_CALL_DEFAULT);
1458 ves_exec_method (&child_frame);
1469 MonoMethodSignature *csig;
1473 token = read32 (ip);
1474 o = newobj (image, token);
1477 /* call the contructor */
1478 child_frame.method = mono_get_method (image, token);
1479 csig = child_frame.method->signature;
1482 * First arg is the object.
1484 child_frame.obj = o;
1486 if (csig->param_count) {
1487 sp -= csig->param_count;
1488 child_frame.stack_args = sp;
1490 child_frame.stack_args = NULL;
1493 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
1495 ves_exec_method (&child_frame);
1497 * FIXME: check for exceptions
1500 * a constructor returns void, but we need to return the object we created
1507 CASE (CEE_CASTCLASS) {
1511 gboolean found = FALSE;
1514 token = read32 (ip);
1516 g_assert (sp [-1].type == VAL_OBJ);
1518 if ((o = sp [-1].data.p)) {
1522 * fixme: this only works for class casts, but not for
1526 if (c->type_token == token) {
1540 CASE (CEE_ISINST) ves_abort(); BREAK;
1541 CASE (CEE_CONV_R_UN) ves_abort(); BREAK;
1542 CASE (CEE_UNUSED58) ves_abort(); BREAK;
1543 CASE (CEE_UNUSED1) ves_abort(); BREAK;
1550 token = read32 (ip);
1552 c = mono_class_get (image, token);
1556 g_assert (o->klass->type_token == c->type_token);
1558 sp [-1].type = VAL_MP;
1559 sp [-1].data.p = (char *)o + sizeof (MonoObject);
1566 THROW_EX (sp->data.p, ip);
1570 MonoClassField *field;
1574 token = read32 (ip);
1577 g_assert (sp [-1].type == VAL_OBJ);
1578 obj = sp [-1].data.p;
1579 field = mono_class_get_field (obj->klass, token);
1581 sp [-1] = stackval_from_data (field->type->type, (char*)obj + field->offset);
1584 CASE (CEE_LDFLDA) ves_abort(); BREAK;
1587 MonoClassField *field;
1591 token = read32 (ip);
1596 g_assert (sp [0].type == VAL_OBJ);
1597 obj = sp [0].data.p;
1598 field = mono_class_get_field (obj->klass, token);
1600 stackval_to_data (field->type->type, &sp [1], (char*)obj + field->offset);
1605 MonoClassField *field;
1609 token = read32 (ip);
1612 /* need to handle fieldrefs */
1613 klass = mono_class_get (image,
1614 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (&image->metadata, token & 0xffffff));
1615 field = mono_class_get_field (klass, token);
1617 *sp = stackval_from_data (field->type->type, (char*)klass + field->offset);
1621 CASE (CEE_LDSFLDA) ves_abort(); BREAK;
1624 MonoClassField *field;
1628 token = read32 (ip);
1632 /* need to handle fieldrefs */
1633 klass = mono_class_get (image,
1634 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (&image->metadata, token & 0xffffff));
1635 field = mono_class_get_field (klass, token);
1637 stackval_to_data (field->type->type, sp, (char*)klass + field->offset);
1640 CASE (CEE_STOBJ) ves_abort(); BREAK;
1641 CASE (CEE_CONV_OVF_I1_UN) ves_abort(); BREAK;
1642 CASE (CEE_CONV_OVF_I2_UN) ves_abort(); BREAK;
1643 CASE (CEE_CONV_OVF_I4_UN) ves_abort(); BREAK;
1644 CASE (CEE_CONV_OVF_I8_UN) ves_abort(); BREAK;
1645 CASE (CEE_CONV_OVF_U1_UN) ves_abort(); BREAK;
1646 CASE (CEE_CONV_OVF_U2_UN) ves_abort(); BREAK;
1647 CASE (CEE_CONV_OVF_U4_UN) ves_abort(); BREAK;
1648 CASE (CEE_CONV_OVF_U8_UN) ves_abort(); BREAK;
1649 CASE (CEE_CONV_OVF_I_UN) ves_abort(); BREAK;
1650 CASE (CEE_CONV_OVF_U_UN) ves_abort(); BREAK;
1655 token = read32 (ip);
1657 sp [-1].type = VAL_OBJ;
1658 sp [-1].data.p = mono_value_box (image, token,
1670 token = read32 (ip);
1671 o = mono_new_szarray (image, token, sp [-1].data.i);
1674 sp [-1].type = VAL_OBJ;
1684 g_assert (sp [-1].type == VAL_OBJ);
1687 g_assert (o != NULL);
1689 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
1691 sp [-1].type = VAL_I32;
1692 sp [-1].data.i = o->bounds [0].length;
1696 CASE (CEE_LDELEMA) ves_abort(); BREAK;
1697 CASE (CEE_LDELEM_I1) /* fall through */
1698 CASE (CEE_LDELEM_U1) /* fall through */
1699 CASE (CEE_LDELEM_I2) /* fall through */
1700 CASE (CEE_LDELEM_U2) /* fall through */
1701 CASE (CEE_LDELEM_I4) /* fall through */
1702 CASE (CEE_LDELEM_U4) /* fall through */
1703 CASE (CEE_LDELEM_I) /* fall through */
1704 CASE (CEE_LDELEM_R4) /* fall through */
1705 CASE (CEE_LDELEM_R8) /* fall through */
1706 CASE (CEE_LDELEM_REF) {
1711 g_assert (sp [0].type == VAL_OBJ);
1714 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
1716 g_assert (sp [1].data.i >= 0);
1717 g_assert (sp [1].data.i < o->bounds [0].length);
1721 sp [0].data.i = ((gint8 *)o->vector)[sp [1].data.i];
1722 sp [0].type = VAL_I32;
1725 sp [0].data.i = ((guint8 *)o->vector)[sp [1].data.i];
1726 sp [0].type = VAL_I32;
1729 sp [0].data.i = ((gint16 *)o->vector)[sp [1].data.i];
1730 sp [0].type = VAL_I32;
1733 sp [0].data.i = ((guint16 *)o->vector)[sp [1].data.i];
1734 sp [0].type = VAL_I32;
1737 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i];
1738 sp [0].type = VAL_NATI;
1741 sp [0].data.i = ((gint32 *)o->vector)[sp [1].data.i];
1742 sp [0].type = VAL_I32;
1745 sp [0].data.i = ((guint32 *)o->vector)[sp [1].data.i];
1746 sp [0].type = VAL_I32;
1749 sp [0].data.f = ((float *)o->vector)[sp [1].data.i];
1750 sp [0].type = VAL_DOUBLE;
1753 sp [0].data.i = ((double *)o->vector)[sp [1].data.i];
1754 sp [0].type = VAL_DOUBLE;
1756 case CEE_LDELEM_REF:
1757 sp [0].data.p = ((gpointer *)o->vector)[sp [1].data.i];
1758 sp [0].type = VAL_OBJ;
1769 CASE (CEE_LDELEM_I8) ves_abort(); BREAK;
1770 CASE (CEE_STELEM_I) /* fall through */
1771 CASE (CEE_STELEM_I1) /* fall through */
1772 CASE (CEE_STELEM_I2) /* fall through */
1773 CASE (CEE_STELEM_I4) /* fall through */
1774 CASE (CEE_STELEM_R4) /* fall through */
1775 CASE (CEE_STELEM_R8) /* fall through */
1776 CASE (CEE_STELEM_REF) {
1783 g_assert (sp [0].type == VAL_OBJ);
1786 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
1787 ac = (MonoArrayClass *)o->obj.klass;
1789 g_assert (sp [1].data.i >= 0);
1790 g_assert (sp [1].data.i < o->bounds [0].length);
1794 ((gint32 *)o->vector)[sp [1].data.i] =
1798 ((gint8 *)o->vector)[sp [1].data.i] =
1802 ((gint16 *)o->vector)[sp [1].data.i] =
1806 ((gint32 *)o->vector)[sp [1].data.i] =
1810 ((float *)o->vector)[sp [1].data.i] =
1814 ((double *)o->vector)[sp [1].data.i] =
1817 case CEE_STELEM_REF:
1818 g_assert (sp [2].type == VAL_OBJ);
1822 //fixme: what about type conversions ?
1823 g_assert (v->klass->type_token == ac->etype_token);
1825 ((gpointer *)o->vector)[sp [1].data.i] =
1836 CASE (CEE_STELEM_I8) ves_abort(); BREAK;
1852 CASE (CEE_UNUSED17) ves_abort(); BREAK;
1853 CASE (CEE_CONV_OVF_I1) ves_abort(); BREAK;
1854 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
1855 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
1856 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
1857 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
1858 CASE (CEE_CONV_OVF_U4)
1860 /* FIXME: handle other cases */
1861 if (sp [-1].type == VAL_I32) {
1862 /* defined as NOP */
1867 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
1868 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
1875 CASE (CEE_UNUSED23) ves_abort(); BREAK;
1876 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
1877 CASE (CEE_CKFINITE) ves_abort(); BREAK;
1878 CASE (CEE_UNUSED24) ves_abort(); BREAK;
1879 CASE (CEE_UNUSED25) ves_abort(); BREAK;
1880 CASE (CEE_MKREFANY) ves_abort(); BREAK;
1889 CASE (CEE_UNUSED67) ves_abort(); BREAK;
1890 CASE (CEE_LDTOKEN) ves_abort(); BREAK;
1891 CASE (CEE_CONV_U2) ves_abort(); BREAK;
1892 CASE (CEE_CONV_U1) ves_abort(); BREAK;
1893 CASE (CEE_CONV_I) ves_abort(); BREAK;
1894 CASE (CEE_CONV_OVF_I) ves_abort(); BREAK;
1895 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
1896 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
1897 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
1898 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
1899 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
1900 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
1901 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
1902 CASE (CEE_ENDFINALLY)
1906 * There was no exception, we continue normally at the target address.
1910 CASE (CEE_LEAVE) ves_abort(); BREAK;
1913 ip += (signed char) *ip;
1915 * We may be either inside a try block or inside an handler.
1916 * In the first case there was no exception and we go on
1917 * executing the finally handlers and after that resume control
1919 * In the second case we need to clear the exception and
1920 * continue directly at the target ip.
1924 frame->ex_handler = NULL;
1927 goto handle_finally;
1930 CASE (CEE_STIND_I) ves_abort(); BREAK;
1953 CASE (CEE_UNUSED48) ves_abort(); BREAK;
1954 CASE (CEE_PREFIX7) ves_abort(); BREAK;
1955 CASE (CEE_PREFIX6) ves_abort(); BREAK;
1956 CASE (CEE_PREFIX5) ves_abort(); BREAK;
1957 CASE (CEE_PREFIX4) ves_abort(); BREAK;
1958 CASE (CEE_PREFIX3) ves_abort(); BREAK;
1959 CASE (CEE_PREFIX2) ves_abort(); BREAK;
1960 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
1964 case CEE_ARGLIST: ves_abort(); break;
1965 case CEE_CEQ: ves_abort(); break;
1966 case CEE_CGT: ves_abort(); break;
1967 case CEE_CGT_UN: ves_abort(); break;
1968 case CEE_CLT: ves_abort(); break;
1969 case CEE_CLT_UN: ves_abort(); break;
1970 case CEE_LDFTN: ves_abort(); break;
1971 case CEE_LDVIRTFTN: ves_abort(); break;
1972 case CEE_UNUSED56: ves_abort(); break;
1973 case CEE_LDARG: ves_abort(); break;
1974 case CEE_LDARGA: ves_abort(); break;
1975 case CEE_STARG: ves_abort(); break;
1976 case CEE_LDLOC: ves_abort(); break;
1977 case CEE_LDLOCA: ves_abort(); break;
1978 case CEE_STLOC: ves_abort(); break;
1979 case CEE_LOCALLOC: ves_abort(); break;
1980 case CEE_UNUSED57: ves_abort(); break;
1981 case CEE_ENDFILTER: ves_abort(); break;
1982 case CEE_UNALIGNED_: ves_abort(); break;
1983 case CEE_VOLATILE_: ves_abort(); break;
1984 case CEE_TAIL_: ves_abort(); break;
1985 case CEE_INITOBJ: ves_abort(); break;
1986 case CEE_UNUSED68: ves_abort(); break;
1987 case CEE_CPBLK: ves_abort(); break;
1988 case CEE_INITBLK: ves_abort(); break;
1989 case CEE_UNUSED69: ves_abort(); break;
1990 case CEE_RETHROW: ves_abort(); break;
1991 case CEE_UNUSED: ves_abort(); break;
1992 case CEE_SIZEOF: ves_abort(); break;
1993 case CEE_REFANYTYPE: ves_abort(); break;
2000 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
2007 g_assert_not_reached ();
2009 * Exception handling code.
2010 * The exception object is stored in frame->ex.
2012 #define OFFSET_IN_CLAUSE(clause,offset) \
2013 ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
2019 MonoInvocation *inv;
2020 MonoMethodHeader *hd;
2021 MonoExceptionClause *clause;
2023 for (inv = frame; inv; inv = inv->parent) {
2024 hd = ((MonoMethodNormal*)inv->method)->header;
2025 ip_offset = inv->ip - hd->code;
2026 for (i = 0; i < hd->num_clauses; ++i) {
2027 clause = &hd->clauses [i];
2028 if (clause->flags <= 1 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2029 if (!clause->flags && mono_isinst (frame->ex, mono_class_get (inv->method->image, clause->token_or_filter))) {
2031 * OK, we found an handler, now we need to execute the finally
2032 * and fault blocks before branching to the handler code.
2034 inv->ex_handler = clause;
2035 goto handle_finally;
2037 /* FIXME: handle filter clauses */
2044 * If we get here, no handler was found: print a stack trace.
2046 for (inv = frame, i = 0; inv; inv = inv->parent, ++i) {
2048 * FIXME: print out also the arguments passed to the func.
2050 g_print ("Unhandled exception.\n");
2051 g_print ("$%d: %s ()\n", i, inv->method->name);
2059 MonoExceptionClause *clause;
2061 ip_offset = frame->ip - header->code;
2062 for (i = 0; i < header->num_clauses; ++i) {
2063 clause = &header->clauses [i];
2064 if (clause->flags == 2 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2065 ip = header->code + clause->handler_offset;
2070 * If an exception is set, we need to execute the fault handler, too,
2071 * otherwise, we continue normally.
2082 MonoExceptionClause *clause;
2084 ip_offset = frame->ip - header->code;
2085 for (i = 0; i < header->num_clauses; ++i) {
2086 clause = &header->clauses [i];
2087 if (clause->flags == 3 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2088 ip = header->code + clause->handler_offset;
2093 * If the handler for the exception was found in this method, we jump
2094 * to it right away, otherwise we return and let the caller run
2095 * the finally, fault and catch blocks.
2096 * This same code should be present in the endfault opcode, but it
2097 * is corrently not assigned in the ECMA specs: LAMESPEC.
2099 if (frame->ex_handler) {
2100 ip = header->code + frame->ex_handler->handler_offset;
2103 sp->data.p = frame->ex;
2107 debug_indent_level--;
2115 ves_exec (MonoAssembly *assembly)
2117 MonoImage *image = assembly->image;
2118 MonoCLIImageInfo *iinfo;
2120 MonoInvocation call;
2122 iinfo = image->image_info;
2126 call.stack_args = NULL;
2127 call.method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point);
2128 call.retval = &result;
2129 ves_exec_method (&call);
2130 mono_free_method (call.method);
2132 return result.data.i;
2138 fprintf (stderr, "Usage is: mono-int executable args...");
2143 main (int argc, char *argv [])
2145 MonoAssembly *assembly;
2154 corlib = mono_get_corlib ();
2156 assembly = mono_assembly_open (file, NULL, NULL);
2158 fprintf (stderr, "Can not open image %s\n", file);
2161 retval = ves_exec (assembly);
2162 mono_assembly_close (assembly);