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/mono-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/metadata/threads.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/arch/x86/x86-codegen.h>
41 #include <mono/io-layer/io-layer.h>
42 /*#include <mono/cli/types.h>*/
47 /* If true, then we output the opcodes as we interpret them */
48 static int tracing = 0;
50 static int debug_indent_level = 0;
53 * Pull the list of opcodes
55 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
59 #include "mono/cil/opcode.def"
65 * Pull the opcode names
67 #define OPDEF(a,b,c,d,e,f,g,h,i,j) b,
68 static char *opcode_names[] = {
69 #include "mono/cil/opcode.def"
73 #define GET_NATI(sp) ((sp).data.nati)
74 #define CSIZE(x) (sizeof (x) / 4)
76 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
78 (frame)->parent = (parent_frame); \
79 (frame)->obj = (obj_this); \
80 (frame)->stack_args = (method_args); \
81 (frame)->retval = (method_retval); \
82 (frame)->method = (mono_method); \
83 (frame)->ex_handler = NULL; \
85 (frame)->child = NULL; \
88 void ves_exec_method (MonoInvocation *frame);
90 typedef void (*ICallMethod) (MonoInvocation *frame);
92 static guint32 frame_thread_id = 0;
95 interp_ex_handler (MonoException *ex) {
96 MonoInvocation *frame = TlsGetValue (frame_thread_id);
98 longjmp (*(jmp_buf*)frame->locals, 1);
102 ves_real_abort (int line, MonoMethod *mh,
103 const unsigned char *ip, stackval *stack, stackval *sp)
105 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
106 fprintf (stderr, "Execution aborted in method: %s\n", mh->name);
107 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
108 ip-mm->header->code);
109 g_print ("0x%04x %02x\n",
110 ip-mm->header->code, *ip);
112 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
114 #define ves_abort() do {ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp); THROW_EX (get_exception_execution_engine (), ip);} while (0);
118 * @klass: klass that needs to be initialized
120 * This routine calls the class constructor for @class if it needs it.
123 init_class (MonoClass *klass)
129 if (!klass->metadata_inited)
130 mono_class_metadata_init (klass);
135 if (klass->parent && !klass->parent->inited)
136 init_class (klass->parent);
140 for (i = 0; i < klass->method.count; ++i) {
141 method = klass->methods [i];
142 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) {
143 INIT_FRAME (&call, NULL, NULL, NULL, NULL, method);
145 ves_exec_method (&call);
149 /* No class constructor found */
153 get_virtual_method (MonoMethod *m, stackval *objs)
159 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
162 g_assert (m->klass->metadata_inited);
166 vtable = (MonoMethod **)klass->vtable;
168 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
169 return *(MonoMethod**)(klass->interface_offsets [m->klass->interface_id] + (m->slot<<2));
171 return vtable [m->slot];
175 get_named_exception (const char *name)
179 MonoMethod *method = NULL;
183 klass = mono_class_from_name (mono_defaults.corlib, "System", name);
185 o = mono_object_new (klass);
186 g_assert (o != NULL);
188 for (i = 0; i < klass->method.count; ++i) {
189 if (!strcmp (".ctor", klass->methods [i]->name) &&
190 klass->methods [i]->signature->param_count == 0) {
191 method = klass->methods [i];
199 INIT_FRAME (&call, NULL, o, NULL, NULL, method);
201 ves_exec_method (&call);
206 get_exception_divide_by_zero ()
208 static MonoObject *ex = NULL;
211 ex = get_named_exception ("DivideByZeroException");
216 get_exception_security ()
218 static MonoObject *ex = NULL;
221 ex = get_named_exception ("SecurityException");
226 get_exception_arithmetic ()
228 static MonoObject *ex = NULL;
231 ex = get_named_exception ("ArithmeticException");
236 get_exception_overflow ()
238 static MonoObject *ex = NULL;
241 ex = get_named_exception ("OverflowException");
246 get_exception_null_reference ()
248 static MonoObject *ex = NULL;
251 ex = get_named_exception ("NullReferenceException");
256 get_exception_execution_engine ()
258 static MonoObject *ex = NULL;
261 ex = get_named_exception ("ExecutionEngineException");
266 get_exception_invalid_cast ()
268 static MonoObject *ex = NULL;
271 ex = get_named_exception ("InvalidCastException");
276 get_exception_index_out_of_range ()
278 static MonoObject *ex = NULL;
281 ex = get_named_exception ("IndexOutOfRangeException");
286 get_exception_array_type_mismatch ()
288 static MonoObject *ex = NULL;
291 ex = get_named_exception ("ArrayTypeMismatchException");
296 get_exception_missing_method ()
298 static MonoObject *ex = NULL;
301 ex = get_named_exception ("MissingMethodException");
306 stackval_from_data (MonoType *type, stackval *result, const char *data)
309 switch (type->type) {
310 case MONO_TYPE_OBJECT:
311 case MONO_TYPE_CLASS:
312 case MONO_TYPE_STRING:
313 case MONO_TYPE_ARRAY:
314 case MONO_TYPE_SZARRAY:
315 result->type = VAL_OBJ;
318 result->type = VAL_VALUETA;
321 result->data.p = *(gpointer*)data;
322 result->data.vt.klass = mono_class_from_mono_type (type);
325 switch (type->type) {
329 result->type = VAL_I32;
330 result->data.i = *(gint8*)data;
333 case MONO_TYPE_BOOLEAN:
334 result->type = VAL_I32;
335 result->data.i = *(guint8*)data;
338 result->type = VAL_I32;
339 result->data.i = *(gint16*)data;
343 result->type = VAL_I32;
344 result->data.i = *(guint16*)data;
347 result->type = VAL_I32;
348 result->data.i = *(gint32*)data;
352 result->type = VAL_TP;
353 result->data.p = *(gpointer*)data;
356 result->type = VAL_I32;
357 result->data.i = *(guint32*)data;
360 result->type = VAL_DOUBLE;
361 result->data.f = *(float*)data;
365 result->type = VAL_I64;
366 result->data.l = *(gint64*)data;
369 result->type = VAL_DOUBLE;
370 result->data.f = *(double*)data;
372 case MONO_TYPE_STRING:
373 case MONO_TYPE_SZARRAY:
374 case MONO_TYPE_CLASS:
375 case MONO_TYPE_OBJECT:
376 case MONO_TYPE_ARRAY:
378 result->type = VAL_OBJ;
379 result->data.p = *(gpointer*)data;
380 result->data.vt.klass = mono_class_from_mono_type (type);
382 case MONO_TYPE_VALUETYPE:
383 if (type->data.klass->enumtype) {
384 return stackval_from_data (type->data.klass->enum_basetype, result, data);
386 result->type = VAL_VALUET;
387 result->data.vt.klass = type->data.klass;
388 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
392 g_warning ("got type 0x%02x", type->type);
393 g_assert_not_reached ();
398 stackval_to_data (MonoType *type, stackval *val, char *data)
401 gpointer *p = (gpointer*)data;
405 switch (type->type) {
408 guint8 *p = (guint8*)data;
412 case MONO_TYPE_BOOLEAN: {
413 guint8 *p = (guint8*)data;
414 *p = (val->data.i != 0);
419 case MONO_TYPE_CHAR: {
420 guint16 *p = (guint16*)data;
424 #if SIZEOF_VOID_P == 4
430 gint32 *p = (gint32*)data;
434 #if SIZEOF_VOID_P == 8
440 gint64 *p = (gint64*)data;
445 float *p = (float*)data;
450 double *p = (double*)data;
454 case MONO_TYPE_STRING:
455 case MONO_TYPE_SZARRAY:
456 case MONO_TYPE_CLASS:
457 case MONO_TYPE_OBJECT:
458 case MONO_TYPE_ARRAY:
459 case MONO_TYPE_PTR: {
460 gpointer *p = (gpointer*)data;
464 case MONO_TYPE_VALUETYPE:
465 if (type->data.klass->enumtype) {
466 return stackval_to_data (type->data.klass->enum_basetype, val, data);
468 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
472 g_warning ("got type %x", type->type);
473 g_assert_not_reached ();
478 ves_array_create (MonoClass *klass, MonoMethodSignature *sig, stackval *values)
481 guint32 *lower_bounds;
484 lengths = alloca (sizeof (guint32) * klass->rank * 2);
485 for (i = 0; i < sig->param_count; ++i) {
486 lengths [i] = values->data.i;
489 if (klass->rank == sig->param_count) {
490 /* Only lengths provided. */
493 /* lower bounds are first. */
494 lower_bounds = lengths;
495 lengths += klass->rank;
497 return (MonoObject*)mono_array_new_full (klass, lengths, lower_bounds);
501 ves_array_set (MonoInvocation *frame)
503 stackval *sp = frame->stack_args;
507 gint32 i, t, pos, esize;
515 g_assert (ac->rank >= 1);
517 pos = sp [0].data.i - ao->bounds [0].lower_bound;
518 for (i = 1; i < ac->rank; i++) {
519 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
520 ao->bounds [i].length) {
521 g_warning ("wrong array index");
522 g_assert_not_reached ();
524 pos = pos*ao->bounds [i].length + sp [i].data.i -
525 ao->bounds [i].lower_bound;
528 esize = mono_array_element_size (ac);
529 ea = mono_array_addr_with_size (ao, esize, pos);
531 mt = frame->method->signature->params [ac->rank];
532 stackval_to_data (mt, &sp [ac->rank], ea);
536 ves_array_get (MonoInvocation *frame)
538 stackval *sp = frame->stack_args;
542 gint32 i, pos, esize;
550 g_assert (ac->rank >= 1);
552 pos = sp [0].data.i - ao->bounds [0].lower_bound;
553 for (i = 1; i < ac->rank; i++)
554 pos = pos*ao->bounds [i].length + sp [i].data.i -
555 ao->bounds [i].lower_bound;
557 esize = mono_array_element_size (ac);
558 ea = mono_array_addr_with_size (ao, esize, pos);
560 mt = frame->method->signature->ret;
561 stackval_from_data (mt, frame->retval, ea);
565 ves_pinvoke_method (MonoInvocation *frame)
568 volatile MonoPIFunc func = mono_create_trampoline (frame->method);
570 g_free ((void*)func);
574 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
575 * locals will point to the jmp_buf, while args will point to the previous
576 * MonoInvocation frame: this is needed to make exception searching work across
577 * managed/unmanaged boundaries.
579 frame->locals = (char*)&env;
580 frame->args = (char*)TlsGetValue (frame_thread_id);
581 TlsSetValue (frame_thread_id, frame);
583 func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
584 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
585 g_free ((void*)func);
590 * runtime specifies that the implementation of the method is automatically
591 * provided by the runtime and is primarily used for the methods of delegates.
594 ves_runtime_method (MonoInvocation *frame)
596 const char *name = frame->method->name;
597 MonoObject *obj = (MonoObject*)frame->obj;
598 MonoDelegate *delegate = (MonoDelegate*)frame->obj;
600 init_class(mono_defaults.delegate_class);
602 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
603 mono_object_isinst (obj, mono_defaults.delegate_class)) {
604 delegate->target = frame->stack_args[0].data.p;
605 delegate->method_ptr = frame->stack_args[1].data.p;
608 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
609 mono_object_isinst (obj, mono_defaults.delegate_class)) {
610 MonoPIFunc func = mono_create_trampoline (frame->method);
611 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
612 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, delegate->target, frame->stack_args);
613 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
614 g_free ((void*)func);
617 g_error ("Don't know how to exec runtime method %s.%s::%s",
618 frame->method->klass->name_space, frame->method->klass->name,
619 frame->method->name);
623 dump_stack (stackval *stack, stackval *sp)
632 case VAL_I32: printf ("[%d] ", s->data.i); break;
633 case VAL_I64: printf ("[%lld] ", s->data.l); break;
634 case VAL_DOUBLE: printf ("[%0.5f] ", s->data.f); break;
635 case VAL_VALUET: printf ("[vt: %p] ", s->data.vt.vt); break;
638 MonoObject *obj = s->data.p;
639 if (obj && obj->klass == mono_defaults.string_class) {
640 char *str = mono_string_to_utf8 ((MonoString*)obj);
641 printf ("\"%s\" ", str);
647 default: printf ("[%p] ", s->data.p); break;
654 dump_frame (MonoInvocation *inv)
657 for (i = 0; inv; inv = inv->parent, ++i) {
658 MonoClass *k = inv->method->klass;
659 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
660 g_print ("#%d: 0x%05x in %s.%s::%s (", i, inv->ip - hd->code,
661 k->name_space, k->name, inv->method->name);
662 dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
667 #define DEBUG_INTERP 1
670 static unsigned long opcode_count = 0;
671 static unsigned long fcall_count = 0;
672 static int break_on_method = 0;
673 static GList *db_methods = NULL;
680 for (h = 0; h < debug_indent_level; h++)
685 db_match_method (gpointer data, gpointer user_data)
688 * Make this function smarter (accept Class:method...)
690 if (strcmp((char*)data, (char*)user_data) == 0)
694 #define DEBUG_ENTER() \
696 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method->name); \
697 if (break_on_method) G_BREAKPOINT (); \
698 break_on_method = 0; \
700 MonoClass *klass = frame->method->klass; \
701 debug_indent_level++; \
703 g_print ("Entering %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
705 #define DEBUG_LEAVE() \
707 MonoClass *klass = frame->method->klass; \
709 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
710 debug_indent_level--; \
715 #define DEBUG_ENTER()
716 #define DEBUG_LEAVE()
720 #define LOCAL_POS(n) (locals_pointers [(n)])
721 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
723 #define ARG_POS(n) (args_pointers [(n)])
724 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
725 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
727 #define THROW_EX(exception,ex_ip) \
729 frame->ip = (ex_ip); \
730 frame->ex = (MonoException*)(exception); \
731 goto handle_exception; \
734 typedef struct _vtallocation vtallocation;
736 struct _vtallocation {
739 char data [MONO_ZERO_LEN_ARRAY];
743 * we don't use vtallocation->next, yet
745 #define vt_alloc(vtype,sp) \
746 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
747 if (!(vtype)->byref) { \
749 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
750 if (!vtalloc || vtalloc->size < size) { \
751 vtalloc = alloca (sizeof (vtallocation) + size); \
752 vtalloc->size = size; \
754 (sp)->data.vt.vt = vtalloc->data; \
757 (sp)->data.vt.klass = (vtype)->data.klass; \
761 #define vt_free(sp) \
763 if ((sp)->type == VAL_VALUET) { \
764 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
769 * Need to optimize ALU ops when natural int == int32
771 * IDEA: if we maintain a stack of ip, sp to be checked
772 * in the return opcode, we could inline simple methods that don't
773 * use the stack or local variables....
775 * The {,.S} versions of many opcodes can/should be merged to reduce code
780 ves_exec_method (MonoInvocation *frame)
782 MonoInvocation child_frame;
783 MonoMethodHeader *header;
784 MonoMethodSignature *signature;
786 const unsigned char *endfinally_ip;
787 register const unsigned char *ip;
788 register stackval *sp;
789 void **locals_pointers;
790 void **args_pointers;
791 unsigned char tail_recursion = 0;
792 unsigned char unaligned_address = 0;
793 unsigned char volatile_address = 0;
794 vtallocation *vtalloc = NULL;
797 if (!frame->method->klass->inited)
798 init_class (frame->method->klass);
802 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
803 if (!frame->method->addr) {
804 frame->ex = (MonoException*)get_exception_missing_method ();
808 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
809 ves_pinvoke_method (frame);
811 ICallMethod icall = (ICallMethod)frame->method->addr;
818 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
819 if (!frame->method->addr) {
820 frame->ex = (MonoException*)get_exception_missing_method ();
824 ves_pinvoke_method (frame);
829 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
830 ves_runtime_method (frame);
835 header = ((MonoMethodNormal *)frame->method)->header;
836 signature = frame->method->signature;
837 image = frame->method->klass->image;
840 * with alloca we get the expected huge performance gain
841 * stackval *stack = g_new0(stackval, header->max_stack);
844 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
846 if (header->num_locals) {
847 int i, align, size, offset = 0;
849 frame->locals = alloca (header->locals_size);
850 locals_pointers = alloca (sizeof(void*) * header->num_locals);
852 * yes, we do it unconditionally, because it needs to be done for
853 * some cases anyway and checking for that would be even slower.
855 memset (frame->locals, 0, header->locals_size);
856 for (i = 0; i < header->num_locals; ++i) {
857 locals_pointers [i] = frame->locals + offset;
858 size = mono_type_size (header->locals [i], &align);
860 offset &= ~(align - 1);
865 * Copy args from stack_args to args.
867 if (signature->params_size) {
868 int i, align, size, offset = 0;
869 int has_this = signature->hasthis;
871 frame->args = alloca (signature->params_size);
872 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
875 this_arg = args_pointers [0] = frame->args;
876 *this_arg = frame->obj;
877 offset += sizeof (gpointer);
879 for (i = 0; i < signature->param_count; ++i) {
880 args_pointers [i + has_this] = frame->args + offset;
881 stackval_to_data (signature->params [i], frame->stack_args + i, frame->args + offset);
882 size = mono_type_size (signature->params [i], &align);
884 offset &= ~(align - 1);
889 child_frame.parent = frame;
890 frame->child = &child_frame;
897 * using while (ip < end) may result in a 15% performance drop,
898 * but it may be useful for debug
902 /*g_assert (sp >= stack);*/
908 dump_stack (frame->stack, sp);
911 g_print ("0x%04x: %s\n", ip-header->code,
912 *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
922 G_BREAKPOINT (); /* this is not portable... */
928 int n = (*ip)-CEE_LDARG_0;
930 vt_alloc (ARG_TYPE (signature, n), sp);
931 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
939 int n = (*ip)-CEE_LDLOC_0;
941 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
943 sp->data.i = *(gint32*) LOCAL_POS (n);
947 vt_alloc (LOCAL_TYPE (header, n), sp);
948 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
957 int n = (*ip)-CEE_STLOC_0;
960 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
961 gint32 *p = (gint32*)LOCAL_POS (n);
965 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
972 vt_alloc (ARG_TYPE (signature, *ip), sp);
973 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
977 CASE (CEE_LDARGA_S) {
982 t = ARG_TYPE (signature, *ip);
983 c = mono_class_from_mono_type (t);
984 sp->data.vt.klass = c;
985 sp->data.vt.vt = ARG_POS (*ip);
988 sp->type = VAL_VALUETA;
999 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1005 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1006 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1010 CASE (CEE_LDLOCA_S) {
1015 t = LOCAL_TYPE (header, *ip);
1016 c = mono_class_from_mono_type (t);
1017 sp->data.vt.klass = c;
1018 sp->data.p = LOCAL_POS (*ip);
1021 sp->type = VAL_VALUETA;
1032 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1040 sp->data.vt.klass = NULL;
1043 CASE (CEE_LDC_I4_M1)
1059 sp->data.i = (*ip) - CEE_LDC_I4_0;
1066 sp->data.i = *(gint8 *)ip;
1073 sp->data.i = read32 (ip);
1080 sp->data.i = read64 (ip);
1087 sp->type = VAL_DOUBLE;
1096 sp->type = VAL_DOUBLE;
1097 readr8(ip, &sp->data.f);
1101 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1103 if (sp [-1].type == VAL_VALUET) {
1104 MonoClass *c = sp [-1].data.vt.klass;
1105 vt_alloc (&c->byval_arg, sp);
1106 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1118 CASE (CEE_JMP) ves_abort(); BREAK;
1119 CASE (CEE_CALLVIRT) /* Fall through */
1120 CASE (CEE_CALLI) /* Fall through */
1122 MonoMethodSignature *csignature;
1124 stackval *endsp = sp;
1126 int virtual = *ip == CEE_CALLVIRT;
1127 int calli = *ip == CEE_CALLI;
1130 * We ignore tail recursion for now.
1137 token = read32 (ip);
1140 unsigned char *code;
1143 /* check the signature we put in mono_create_method_pointer () */
1144 g_assert (code [2] == 'M' && code [3] == 'o');
1145 child_frame.method = *(gpointer*)(code + sizeof (gpointer));
1146 csignature = child_frame.method->signature;
1148 child_frame.method = mono_get_method (image, token, NULL);
1149 if (!child_frame.method)
1150 THROW_EX (get_exception_missing_method (), ip -5);
1151 csignature = child_frame.method->signature;
1153 stackval *this_arg = &sp [-csignature->param_count-1];
1154 if (!this_arg->data.p)
1155 THROW_EX (get_exception_null_reference(), ip - 5);
1156 child_frame.method = get_virtual_method (child_frame.method, this_arg);
1159 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1160 /* decrement by the actual number of args */
1161 if (csignature->param_count) {
1162 sp -= csignature->param_count;
1163 child_frame.stack_args = sp;
1165 child_frame.stack_args = NULL;
1167 if (csignature->hasthis) {
1168 g_assert (sp >= frame->stack);
1171 * It may also be a TP from LD(S)FLDA
1172 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1174 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1175 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1177 child_frame.obj = sp->data.p;
1179 child_frame.obj = NULL;
1181 if (csignature->ret->type != MONO_TYPE_VOID) {
1182 vt_alloc (csignature->ret, &retval);
1183 child_frame.retval = &retval;
1185 child_frame.retval = NULL;
1188 child_frame.ex = NULL;
1189 child_frame.ex_handler = NULL;
1191 ves_exec_method (&child_frame);
1193 while (endsp > sp) {
1198 if (child_frame.ex) {
1200 * An exception occurred, need to run finally, fault and catch handlers..
1202 frame->ex = child_frame.ex;
1203 goto handle_finally;
1206 /* need to handle typedbyref ... */
1207 if (csignature->ret->type != MONO_TYPE_VOID) {
1214 if (signature->ret->type != MONO_TYPE_VOID) {
1216 if (sp->type == VAL_VALUET) {
1217 /* the caller has already allocated the memory */
1218 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1221 *frame->retval = *sp;
1224 if (sp > frame->stack)
1225 g_warning ("more values on stack: %d", sp-frame->stack);
1229 CASE (CEE_BR_S) /* Fall through */
1231 if (*ip == CEE_BR) {
1233 ip += (gint32) read32(ip);
1237 ip += (signed char) *ip;
1241 CASE (CEE_BRFALSE) /* Fall through */
1242 CASE (CEE_BRFALSE_S) {
1244 int near_jump = *ip == CEE_BRFALSE_S;
1248 case VAL_I32: result = sp->data.i == 0; break;
1249 case VAL_I64: result = sp->data.l == 0; break;
1250 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1251 default: result = sp->data.p == NULL; break;
1255 ip += (signed char)*ip;
1257 ip += (gint32) read32 (ip);
1259 ip += near_jump ? 1: 4;
1262 CASE (CEE_BRTRUE) /* Fall through */
1263 CASE (CEE_BRTRUE_S) {
1265 int near_jump = *ip == CEE_BRTRUE_S;
1269 case VAL_I32: result = sp->data.i != 0; break;
1270 case VAL_I64: result = sp->data.l != 0; break;
1271 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1272 default: result = sp->data.p != NULL; break;
1276 ip += (signed char)*ip;
1278 ip += (gint32) read32 (ip);
1280 ip += near_jump ? 1: 4;
1283 CASE (CEE_BEQ) /* Fall through */
1286 int near_jump = *ip == CEE_BEQ_S;
1289 if (sp->type == VAL_I32)
1290 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1291 else if (sp->type == VAL_I64)
1292 result = sp [0].data.l == sp [1].data.l;
1293 else if (sp->type == VAL_DOUBLE)
1294 result = sp [0].data.f == sp [1].data.f;
1296 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1299 ip += (signed char)*ip;
1301 ip += (gint32) read32 (ip);
1303 ip += near_jump ? 1: 4;
1306 CASE (CEE_BGE) /* Fall through */
1309 int near_jump = *ip == CEE_BGE_S;
1312 if (sp->type == VAL_I32)
1313 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1314 else if (sp->type == VAL_I64)
1315 result = sp [0].data.l >= sp [1].data.l;
1316 else if (sp->type == VAL_DOUBLE)
1317 result = sp [0].data.f >= sp [1].data.f;
1319 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1322 ip += (signed char)*ip;
1324 ip += (gint32) read32 (ip);
1326 ip += near_jump ? 1: 4;
1329 CASE (CEE_BGT) /* Fall through */
1332 int near_jump = *ip == CEE_BGT_S;
1335 if (sp->type == VAL_I32)
1336 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1337 else if (sp->type == VAL_I64)
1338 result = sp [0].data.l > sp [1].data.l;
1339 else if (sp->type == VAL_DOUBLE)
1340 result = sp [0].data.f > sp [1].data.f;
1342 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1345 ip += (signed char)*ip;
1347 ip += (gint32) read32 (ip);
1349 ip += near_jump ? 1: 4;
1352 CASE (CEE_BLT) /* Fall through */
1355 int near_jump = *ip == CEE_BLT_S;
1358 if (sp->type == VAL_I32)
1359 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1360 else if (sp->type == VAL_I64)
1361 result = sp[0].data.l < sp[1].data.l;
1362 else if (sp->type == VAL_DOUBLE)
1363 result = sp[0].data.f < sp[1].data.f;
1365 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1368 ip += 1 + (signed char)*ip;
1370 ip += 4 + (gint32) read32 (ip);
1373 ip += near_jump ? 1: 4;
1377 CASE (CEE_BLE) /* fall through */
1380 int near_jump = *ip == CEE_BLE_S;
1384 if (sp->type == VAL_I32)
1385 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1386 else if (sp->type == VAL_I64)
1387 result = sp [0].data.l <= sp [1].data.l;
1388 else if (sp->type == VAL_DOUBLE)
1389 result = sp [0].data.f <= sp [1].data.f;
1392 * FIXME: here and in other places GET_NATI on the left side
1393 * _will_ be wrong when we change the macro to work on 64 bits
1396 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1400 ip += (signed char)*ip;
1402 ip += (gint32) read32 (ip);
1404 ip += near_jump ? 1: 4;
1407 CASE (CEE_BNE_UN) /* Fall through */
1408 CASE (CEE_BNE_UN_S) {
1410 int near_jump = *ip == CEE_BNE_UN_S;
1413 if (sp->type == VAL_I32)
1414 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1415 else if (sp->type == VAL_I64)
1416 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1417 else if (sp->type == VAL_DOUBLE)
1418 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1419 (sp [0].data.f != sp [1].data.f);
1421 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1424 ip += (signed char)*ip;
1426 ip += (gint32) read32 (ip);
1428 ip += near_jump ? 1: 4;
1431 CASE (CEE_BGE_UN) /* Fall through */
1432 CASE (CEE_BGE_UN_S) {
1434 int near_jump = *ip == CEE_BGE_UN_S;
1437 if (sp->type == VAL_I32)
1438 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1439 else if (sp->type == VAL_I64)
1440 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1441 else if (sp->type == VAL_DOUBLE)
1442 result = !isless (sp [0].data.f,sp [1].data.f);
1444 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1447 ip += (signed char)*ip;
1449 ip += (gint32) read32 (ip);
1451 ip += near_jump ? 1: 4;
1454 CASE (CEE_BGT_UN) /* Fall through */
1455 CASE (CEE_BGT_UN_S) {
1457 int near_jump = *ip == CEE_BGT_UN_S;
1460 if (sp->type == VAL_I32)
1461 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1462 else if (sp->type == VAL_I64)
1463 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1464 else if (sp->type == VAL_DOUBLE)
1465 result = isgreater (sp [0].data.f, sp [1].data.f);
1467 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1470 ip += (signed char)*ip;
1472 ip += (gint32) read32 (ip);
1474 ip += near_jump ? 1: 4;
1477 CASE (CEE_BLE_UN) /* Fall through */
1478 CASE (CEE_BLE_UN_S) {
1480 int near_jump = *ip == CEE_BLE_UN_S;
1483 if (sp->type == VAL_I32)
1484 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1485 else if (sp->type == VAL_I64)
1486 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1487 else if (sp->type == VAL_DOUBLE)
1488 result = islessequal (sp [0].data.f, sp [1].data.f);
1490 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1493 ip += (signed char)*ip;
1495 ip += (gint32) read32 (ip);
1497 ip += near_jump ? 1: 4;
1500 CASE (CEE_BLT_UN) /* Fall through */
1501 CASE (CEE_BLT_UN_S) {
1503 int near_jump = *ip == CEE_BLT_UN_S;
1506 if (sp->type == VAL_I32)
1507 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1508 else if (sp->type == VAL_I64)
1509 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1510 else if (sp->type == VAL_DOUBLE)
1511 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1512 (sp [0].data.f < sp [1].data.f);
1514 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1517 ip += (signed char)*ip;
1519 ip += (gint32) read32 (ip);
1521 ip += near_jump ? 1: 4;
1526 const unsigned char *st;
1530 st = ip + sizeof (gint32) * n;
1532 if ((guint32)sp->data.i < n) {
1534 ip += sizeof (gint32) * (guint32)sp->data.i;
1535 offset = read32 (ip);
1544 sp[-1].type = VAL_I32;
1545 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1549 sp[-1].type = VAL_I32;
1550 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1554 sp[-1].type = VAL_I32;
1555 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1559 sp[-1].type = VAL_I32;
1560 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1562 CASE (CEE_LDIND_I4) /* Fall through */
1565 sp[-1].type = VAL_I32;
1566 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1570 sp[-1].type = VAL_I64;
1571 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1575 sp[-1].type = VAL_NATI;
1576 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1580 sp[-1].type = VAL_DOUBLE;
1581 sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1585 sp[-1].type = VAL_DOUBLE;
1586 sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1588 CASE (CEE_LDIND_REF)
1590 sp[-1].type = VAL_OBJ;
1591 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1592 sp[-1].data.vt.klass = NULL;
1594 CASE (CEE_STIND_REF) {
1602 CASE (CEE_STIND_I1) {
1607 *p = (gint8)sp[1].data.i;
1610 CASE (CEE_STIND_I2) {
1615 *p = (gint16)sp[1].data.i;
1618 CASE (CEE_STIND_I4) {
1626 CASE (CEE_STIND_I) {
1631 *p = (mono_i)sp[1].data.p;
1634 CASE (CEE_STIND_I8) {
1642 CASE (CEE_STIND_R4) {
1647 *p = (gfloat)sp[1].data.f;
1650 CASE (CEE_STIND_R8) {
1661 /* should probably consider the pointers as unsigned */
1662 if (sp->type == VAL_I32)
1663 sp [-1].data.i += GET_NATI (sp [0]);
1664 else if (sp->type == VAL_I64)
1665 sp [-1].data.l += sp [0].data.l;
1666 else if (sp->type == VAL_DOUBLE)
1667 sp [-1].data.f += sp [0].data.f;
1669 char *p = sp [-1].data.p;
1670 p += GET_NATI (sp [0]);
1677 /* should probably consider the pointers as unsigned */
1678 if (sp->type == VAL_I32)
1679 sp [-1].data.i -= GET_NATI (sp [0]);
1680 else if (sp->type == VAL_I64)
1681 sp [-1].data.l -= sp [0].data.l;
1682 else if (sp->type == VAL_DOUBLE)
1683 sp [-1].data.f -= sp [0].data.f;
1685 char *p = sp [-1].data.p;
1686 p -= GET_NATI (sp [0]);
1693 if (sp->type == VAL_I32)
1694 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
1695 else if (sp->type == VAL_I64)
1696 sp [-1].data.l *= sp [0].data.l;
1697 else if (sp->type == VAL_DOUBLE)
1698 sp [-1].data.f *= sp [0].data.f;
1703 if (sp->type == VAL_I32) {
1704 if (GET_NATI (sp [0]) == 0)
1705 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1706 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
1707 } else if (sp->type == VAL_I64) {
1708 if (sp [0].data.l == 0)
1709 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1710 sp [-1].data.l /= sp [0].data.l;
1711 } else if (sp->type == VAL_DOUBLE) {
1712 /* set NaN is divisor is 0.0 */
1713 sp [-1].data.f /= sp [0].data.f;
1719 if (sp->type == VAL_I32) {
1721 if (GET_NATI (sp [0]) == 0)
1722 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1723 val = sp [-1].data.i;
1724 val /= (guint32)GET_NATI (sp [0]);
1725 sp [-1].data.i = val;
1726 } else if (sp->type == VAL_I64) {
1728 if (sp [0].data.l == 0)
1729 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1730 val = sp [-1].data.l;
1731 val /= (guint64)sp [0].data.l;
1732 sp [-1].data.l = val;
1733 } else if (sp->type == VAL_NATI) {
1735 if (GET_NATI (sp [0]) == 0)
1736 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1737 val = (mono_u)sp [-1].data.p;
1738 val /= (gulong)sp [0].data.p;
1739 sp [-1].data.p = (gpointer)val;
1745 if (sp->type == VAL_I32) {
1746 if (GET_NATI (sp [0]) == 0)
1747 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1748 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
1749 } else if (sp->type == VAL_I64) {
1750 if (sp [0].data.l == 0)
1751 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1752 sp [-1].data.l %= sp [0].data.l;
1753 } else if (sp->type == VAL_DOUBLE) {
1754 /* FIXME: what do we actually do here? */
1755 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
1757 if (GET_NATI (sp [0]) == 0)
1758 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1759 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
1765 if (sp->type == VAL_I32) {
1766 if (GET_NATI (sp [0]) == 0)
1767 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1768 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
1769 } else if (sp->type == VAL_I64) {
1770 if (sp [0].data.l == 0)
1771 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1772 (gulong)sp [-1].data.l %= (gulong)sp [0].data.l;
1773 } else if (sp->type == VAL_DOUBLE) {
1774 /* unspecified behaviour according to the spec */
1776 if (GET_NATI (sp [0]) == 0)
1777 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1778 (gulong)GET_NATI (sp [-1]) %= (gulong)GET_NATI (sp [0]);
1784 if (sp->type == VAL_I32)
1785 sp [-1].data.i &= GET_NATI (sp [0]);
1786 else if (sp->type == VAL_I64)
1787 sp [-1].data.l &= sp [0].data.l;
1789 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1794 if (sp->type == VAL_I32)
1795 sp [-1].data.i |= GET_NATI (sp [0]);
1796 else if (sp->type == VAL_I64)
1797 sp [-1].data.l |= sp [0].data.l;
1799 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1804 if (sp->type == VAL_I32)
1805 sp [-1].data.i ^= GET_NATI (sp [0]);
1806 else if (sp->type == VAL_I64)
1807 sp [-1].data.l ^= sp [0].data.l;
1809 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1814 if (sp->type == VAL_I32)
1815 sp [-1].data.i <<= GET_NATI (sp [0]);
1816 else if (sp->type == VAL_I64)
1817 sp [-1].data.l <<= GET_NATI (sp [0]);
1819 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1824 if (sp->type == VAL_I32)
1825 sp [-1].data.i >>= GET_NATI (sp [0]);
1826 else if (sp->type == VAL_I64)
1827 sp [-1].data.l >>= GET_NATI (sp [0]);
1829 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1834 if (sp->type == VAL_I32)
1835 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
1836 else if (sp->type == VAL_I64)
1837 (gulong)sp [-1].data.l >>= GET_NATI (sp [0]);
1839 (gulong)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1844 if (sp->type == VAL_I32)
1845 sp->data.i = - sp->data.i;
1846 else if (sp->type == VAL_I64)
1847 sp->data.l = - sp->data.l;
1848 else if (sp->type == VAL_DOUBLE)
1849 sp->data.f = - sp->data.f;
1850 else if (sp->type == VAL_NATI)
1851 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
1857 if (sp->type == VAL_I32)
1858 sp->data.i = ~ sp->data.i;
1859 else if (sp->type == VAL_I64)
1860 sp->data.l = ~ sp->data.l;
1861 else if (sp->type == VAL_NATI)
1862 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
1865 CASE (CEE_CONV_U1) /* fall through */
1866 CASE (CEE_CONV_I1) {
1868 switch (sp [-1].type) {
1870 sp [-1].data.i = (gint8)sp [-1].data.f;
1873 sp [-1].data.i = (gint8)sp [-1].data.l;
1878 sp [-1].data.i = (gint8)sp [-1].data.i;
1881 sp [-1].data.i = (gint8)sp [-1].data.nati;
1884 sp [-1].type = VAL_I32;
1887 CASE (CEE_CONV_U2) /* fall through */
1888 CASE (CEE_CONV_I2) {
1890 switch (sp [-1].type) {
1892 sp [-1].data.i = (gint16)sp [-1].data.f;
1895 sp [-1].data.i = (gint16)sp [-1].data.l;
1900 sp [-1].data.i = (gint16)sp [-1].data.i;
1903 sp [-1].data.i = (gint16)sp [-1].data.nati;
1906 sp [-1].type = VAL_I32;
1909 CASE (CEE_CONV_U4) /* Fall through */
1910 #if SIZEOF_VOID_P == 4
1911 CASE (CEE_CONV_I) /* Fall through */
1912 CASE (CEE_CONV_U) /* Fall through */
1914 CASE (CEE_CONV_I4) {
1916 switch (sp [-1].type) {
1918 sp [-1].data.i = (gint32)sp [-1].data.f;
1921 sp [-1].data.i = (gint32)sp [-1].data.l;
1928 sp [-1].data.i = (gint32)sp [-1].data.p;
1931 sp [-1].type = VAL_I32;
1934 #if SIZEOF_VOID_P == 8
1935 CASE (CEE_CONV_I) /* Fall through */
1939 switch (sp [-1].type) {
1941 sp [-1].data.l = (gint64)sp [-1].data.f;
1948 sp [-1].data.l = (gint64)sp [-1].data.i;
1951 sp [-1].data.l = (gint64)sp [-1].data.nati;
1954 sp [-1].type = VAL_I64;
1956 CASE (CEE_CONV_R4) /* Fall through */
1957 CASE (CEE_CONV_R8) {
1959 switch (sp [-1].type) {
1961 sp [-1].data.f = (double)sp [-1].data.f;
1964 sp [-1].data.f = (double)sp [-1].data.l;
1969 sp [-1].data.f = (double)sp [-1].data.i;
1972 sp [-1].data.f = (double)sp [-1].data.nati;
1975 sp [-1].type = VAL_DOUBLE;
1978 #if SIZEOF_VOID_P == 8
1979 CASE (CEE_CONV_U) /* Fall through */
1984 switch (sp [-1].type){
1986 sp [-1].data.l = (guint64)sp [-1].data.f;
1993 sp [-1].data.l = (guint64) sp [-1].data.i;
1996 sp [-1].data.l = (guint64) sp [-1].data.nati;
1999 sp [-1].type = VAL_I64;
2004 vtklass = mono_class_get (image, read32 (ip));
2007 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2016 token = read32 (ip);
2018 c = mono_class_get (image, token);
2019 addr = sp [-1].data.vt.vt;
2020 vt_alloc (&c->byval_arg, &sp [-1]);
2021 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2029 index = mono_metadata_token_index (read32 (ip));
2032 o = (MonoObject*)mono_ldstr (image, index);
2035 sp->data.vt.klass = NULL;
2042 MonoMethodSignature *csig;
2043 stackval *endsp = sp;
2049 token = read32 (ip);
2052 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2053 THROW_EX (get_exception_missing_method (), ip -5);
2055 csig = child_frame.method->signature;
2057 if (child_frame.method->klass->parent == mono_defaults.array_class) {
2058 sp -= csig->param_count;
2059 o = ves_array_create (child_frame.method->klass, csig, sp);
2060 goto array_constructed;
2063 o = mono_object_new (child_frame.method->klass);
2066 * First arg is the object.
2068 child_frame.obj = o;
2070 if (csig->param_count) {
2071 sp -= csig->param_count;
2072 child_frame.stack_args = sp;
2074 child_frame.stack_args = NULL;
2077 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2079 child_frame.ex = NULL;
2080 child_frame.ex_handler = NULL;
2082 ves_exec_method (&child_frame);
2084 while (endsp > sp) {
2089 if (child_frame.ex) {
2091 * An exception occurred, need to run finally, fault and catch handlers..
2093 frame->ex = child_frame.ex;
2094 goto handle_finally;
2097 * a constructor returns void, but we need to return the object we created
2102 sp->data.vt.klass = o->klass;
2106 CASE (CEE_CASTCLASS) /* Fall through */
2109 MonoClass *c , *oclass;
2111 int do_isinst = *ip == CEE_ISINST;
2112 gboolean found = FALSE;
2115 token = read32 (ip);
2116 c = mono_class_get (image, token);
2121 g_assert (sp [-1].type == VAL_OBJ);
2123 if ((o = sp [-1].data.p)) {
2127 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2128 if ((c->interface_id <= oclass->max_interface_id) &&
2129 oclass->interface_offsets [c->interface_id])
2132 if ((oclass->baseval - c->baseval) <= c->diffval) {
2133 sp [-1].data.vt.klass = c;
2140 sp [-1].data.p = NULL;
2141 sp [-1].data.vt.klass = NULL;
2143 THROW_EX (get_exception_invalid_cast (), ip - 1);
2149 CASE (CEE_CONV_R_UN)
2150 switch (sp [-1].type) {
2154 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2159 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2162 sp [-1].data.f = (double)(gulong)sp [-1].data.nati;
2165 sp [-1].type = VAL_DOUBLE;
2168 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2175 token = read32 (ip);
2177 c = mono_class_get (image, token);
2181 THROW_EX (get_exception_null_reference(), ip - 1);
2183 if (o->klass->type_token != c->type_token)
2184 THROW_EX (get_exception_invalid_cast (), ip - 1);
2186 sp [-1].type = VAL_MP;
2187 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2194 THROW_EX (sp->data.p, ip);
2196 CASE (CEE_LDFLDA) /* Fall through */
2199 MonoClassField *field;
2200 guint32 token, offset;
2201 int load_addr = *ip == CEE_LDFLDA;
2203 if (!sp [-1].data.p)
2204 THROW_EX (get_exception_null_reference (), ip);
2207 token = read32 (ip);
2210 if (sp [-1].type == VAL_OBJ) {
2211 obj = sp [-1].data.p;
2212 field = mono_class_get_field (obj->klass, token);
2213 offset = field->offset;
2214 } else { /* valuetype */
2215 /*g_assert (sp [-1].type == VAL_VALUETA); */
2216 obj = sp [-1].data.vt.vt;
2217 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2218 offset = field->offset - sizeof (MonoObject);
2221 sp [-1].type = VAL_TP;
2222 sp [-1].data.p = (char*)obj + offset;
2223 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2225 vt_alloc (field->type, &sp [-1]);
2226 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2233 MonoClassField *field;
2234 guint32 token, offset;
2237 token = read32 (ip);
2242 if (sp [0].type == VAL_OBJ) {
2243 obj = sp [0].data.p;
2244 field = mono_class_get_field (obj->klass, token);
2245 offset = field->offset;
2246 } else { /* valuetype */
2247 /*g_assert (sp->type == VAL_VALUETA); */
2248 obj = sp [0].data.vt.vt;
2249 field = mono_class_get_field (sp [0].data.vt.klass, token);
2250 offset = field->offset - sizeof (MonoObject);
2253 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2257 CASE (CEE_LDSFLD) /* Fall through */
2258 CASE (CEE_LDSFLDA) {
2260 MonoClassField *field;
2262 int load_addr = *ip == CEE_LDSFLDA;
2265 token = read32 (ip);
2268 /* need to handle fieldrefs */
2269 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2270 field = mono_field_from_memberref (image, token, &klass);
2274 klass = mono_class_get (image,
2275 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2278 field = mono_class_get_field (klass, token);
2283 sp->data.p = (char*)MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
2284 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2286 vt_alloc (field->type, sp);
2287 stackval_from_data (field->type, sp, (char*)MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2294 MonoClassField *field;
2298 token = read32 (ip);
2302 /* need to handle fieldrefs */
2303 klass = mono_class_get (image,
2304 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2307 field = mono_class_get_field (klass, token);
2309 stackval_to_data (field->type, sp, (char*)MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2316 vtklass = mono_class_get (image, read32 (ip));
2319 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2322 #if SIZEOF_VOID_P == 8
2323 CASE (CEE_CONV_OVF_I_UN)
2325 CASE (CEE_CONV_OVF_I8_UN) {
2326 switch (sp [-1].type) {
2328 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2329 THROW_EX (get_exception_overflow (), ip);
2330 sp [-1].data.l = (guint64)sp [-1].data.f;
2333 if (sp [-1].data.l < 0)
2334 THROW_EX (get_exception_overflow (), ip);
2339 /* Can't overflow */
2340 sp [-1].data.l = (guint64)sp [-1].data.i;
2343 if ((gint64)sp [-1].data.nati < 0)
2344 THROW_EX (get_exception_overflow (), ip);
2345 sp [-1].data.l = (guint64)sp [-1].data.nati;
2348 sp [-1].type = VAL_I64;
2352 #if SIZEOF_VOID_P == 8
2353 CASE (CEE_CONV_OVF_U_UN)
2355 CASE (CEE_CONV_OVF_U8_UN) {
2356 switch (sp [-1].type) {
2358 if (sp [-1].data.f < 0 || sp [-1].data.f > 18446744073709551615UL)
2359 THROW_EX (get_exception_overflow (), ip);
2360 sp [-1].data.l = (guint64)sp [-1].data.f;
2368 /* Can't overflow */
2369 sp [-1].data.l = (guint64)sp [-1].data.i;
2372 /* Can't overflow */
2373 sp [-1].data.l = (guint64)sp [-1].data.nati;
2376 sp [-1].type = VAL_I64;
2380 #if SIZEOF_VOID_P == 4
2381 CASE (CEE_CONV_OVF_I_UN)
2382 CASE (CEE_CONV_OVF_U_UN)
2384 CASE (CEE_CONV_OVF_I1_UN)
2385 CASE (CEE_CONV_OVF_I2_UN)
2386 CASE (CEE_CONV_OVF_I4_UN)
2387 CASE (CEE_CONV_OVF_U1_UN)
2388 CASE (CEE_CONV_OVF_U2_UN)
2389 CASE (CEE_CONV_OVF_U4_UN) {
2391 switch (sp [-1].type) {
2393 value = (guint64)sp [-1].data.f;
2396 value = (guint64)sp [-1].data.l;
2401 value = (guint64)sp [-1].data.i;
2404 value = (guint64)sp [-1].data.nati;
2408 case CEE_CONV_OVF_I1_UN:
2410 THROW_EX (get_exception_overflow (), ip);
2411 sp [-1].data.i = value;
2412 sp [-1].type = VAL_I32;
2414 case CEE_CONV_OVF_I2_UN:
2416 THROW_EX (get_exception_overflow (), ip);
2417 sp [-1].data.i = value;
2418 sp [-1].type = VAL_I32;
2420 #if SIZEOF_VOID_P == 4
2421 case CEE_CONV_OVF_I_UN: /* Fall through */
2423 case CEE_CONV_OVF_I4_UN:
2424 if (value > 2147483647)
2425 THROW_EX (get_exception_overflow (), ip);
2426 sp [-1].data.i = value;
2427 sp [-1].type = VAL_I32;
2429 case CEE_CONV_OVF_U1_UN:
2431 THROW_EX (get_exception_overflow (), ip);
2432 sp [-1].data.i = value;
2433 sp [-1].type = VAL_I32;
2435 case CEE_CONV_OVF_U2_UN:
2437 THROW_EX (get_exception_overflow (), ip);
2438 sp [-1].data.i = value;
2439 sp [-1].type = VAL_I32;
2441 #if SIZEOF_VOID_P == 4
2442 case CEE_CONV_OVF_U_UN: /* Fall through */
2444 case CEE_CONV_OVF_U4_UN:
2445 if (value > 4294967295U)
2446 THROW_EX (get_exception_overflow (), ip);
2447 sp [-1].data.i = value;
2448 sp [-1].type = VAL_I32;
2451 g_assert_not_reached ();
2461 token = read32 (ip);
2463 class = mono_class_get (image, token);
2464 g_assert (class != NULL);
2466 sp [-1].type = VAL_OBJ;
2467 sp [-1].data.p = mono_value_box (class, &sp [-1]);
2468 /* need to vt_free (sp); */
2480 token = read32 (ip);
2481 class = mono_class_get (image, token);
2482 o = (MonoObject*) mono_array_new (class, sp [-1].data.i);
2485 sp [-1].type = VAL_OBJ;
2495 g_assert (sp [-1].type == VAL_OBJ);
2499 THROW_EX (get_exception_null_reference (), ip - 1);
2501 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2503 sp [-1].type = VAL_I32;
2504 sp [-1].data.i = mono_array_length (o);
2508 CASE (CEE_LDELEMA) {
2510 guint32 esize, token;
2513 token = read32 (ip);
2517 g_assert (sp [0].type == VAL_OBJ);
2520 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2522 if (sp [1].data.nati >= mono_array_length (o))
2523 THROW_EX (get_exception_index_out_of_range (), ip - 5);
2525 /* check the array element corresponds to token */
2526 esize = mono_array_element_size (o->obj.klass);
2529 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
2530 sp->data.vt.klass = o->obj.klass->element_class;
2535 CASE (CEE_LDELEM_I1) /* fall through */
2536 CASE (CEE_LDELEM_U1) /* fall through */
2537 CASE (CEE_LDELEM_I2) /* fall through */
2538 CASE (CEE_LDELEM_U2) /* fall through */
2539 CASE (CEE_LDELEM_I4) /* fall through */
2540 CASE (CEE_LDELEM_U4) /* fall through */
2541 CASE (CEE_LDELEM_I8) /* fall through */
2542 CASE (CEE_LDELEM_I) /* fall through */
2543 CASE (CEE_LDELEM_R4) /* fall through */
2544 CASE (CEE_LDELEM_R8) /* fall through */
2545 CASE (CEE_LDELEM_REF) {
2551 g_assert (sp [0].type == VAL_OBJ);
2554 THROW_EX (get_exception_null_reference (), ip);
2556 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2558 aindex = sp [1].data.nati;
2559 if (aindex >= mono_array_length (o))
2560 THROW_EX (get_exception_index_out_of_range (), ip);
2563 * FIXME: throw get_exception_array_type_mismatch () if needed
2567 sp [0].data.i = mono_array_get (o, gint8, aindex);
2568 sp [0].type = VAL_I32;
2571 sp [0].data.i = mono_array_get (o, guint8, aindex);
2572 sp [0].type = VAL_I32;
2575 sp [0].data.i = mono_array_get (o, gint16, aindex);
2576 sp [0].type = VAL_I32;
2579 sp [0].data.i = mono_array_get (o, guint16, aindex);
2580 sp [0].type = VAL_I32;
2583 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
2584 sp [0].type = VAL_NATI;
2587 sp [0].data.i = mono_array_get (o, gint32, aindex);
2588 sp [0].type = VAL_I32;
2591 sp [0].data.i = mono_array_get (o, guint32, aindex);
2592 sp [0].type = VAL_I32;
2595 sp [0].data.l = mono_array_get (o, gint64, aindex);
2596 sp [0].type = VAL_I64;
2599 sp [0].data.f = mono_array_get (o, float, aindex);
2600 sp [0].type = VAL_DOUBLE;
2603 sp [0].data.f = mono_array_get (o, double, aindex);
2604 sp [0].type = VAL_DOUBLE;
2606 case CEE_LDELEM_REF:
2607 sp [0].data.p = mono_array_get (o, gpointer, aindex);
2608 sp [0].data.vt.klass = NULL;
2609 sp [0].type = VAL_OBJ;
2619 CASE (CEE_STELEM_I) /* fall through */
2620 CASE (CEE_STELEM_I1) /* fall through */
2621 CASE (CEE_STELEM_I2) /* fall through */
2622 CASE (CEE_STELEM_I4) /* fall through */
2623 CASE (CEE_STELEM_I8) /* fall through */
2624 CASE (CEE_STELEM_R4) /* fall through */
2625 CASE (CEE_STELEM_R8) /* fall through */
2626 CASE (CEE_STELEM_REF) {
2633 g_assert (sp [0].type == VAL_OBJ);
2636 THROW_EX (get_exception_null_reference (), ip);
2638 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2641 aindex = sp [1].data.nati;
2642 if (aindex >= mono_array_length (o))
2643 THROW_EX (get_exception_index_out_of_range (), ip);
2646 * FIXME: throw get_exception_array_type_mismatch () if needed
2650 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
2653 mono_array_set (o, gint8, aindex, sp [2].data.i);
2656 mono_array_set (o, gint16, aindex, sp [2].data.i);
2659 mono_array_set (o, gint32, aindex, sp [2].data.i);
2662 mono_array_set (o, gint64, aindex, sp [2].data.l);
2665 mono_array_set (o, float, aindex, sp [2].data.f);
2668 mono_array_set (o, double, aindex, sp [2].data.f);
2670 case CEE_STELEM_REF:
2671 g_assert (sp [2].type == VAL_OBJ);
2672 mono_array_set (o, gpointer, aindex, sp [2].data.p);
2696 CASE (CEE_UNUSED17) ves_abort(); BREAK;
2697 CASE (CEE_CONV_OVF_I1)
2698 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
2699 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
2700 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
2701 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
2702 CASE (CEE_CONV_OVF_U4)
2704 /* FIXME: handle other cases */
2705 if (sp [-1].type == VAL_I32) {
2706 /* defined as NOP */
2711 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2712 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
2719 CASE (CEE_UNUSED23) ves_abort(); BREAK;
2720 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
2722 if (!finite(sp [-1].data.f))
2723 THROW_EX (get_exception_arithmetic (), ip);
2726 CASE (CEE_UNUSED24) ves_abort(); BREAK;
2727 CASE (CEE_UNUSED25) ves_abort(); BREAK;
2728 CASE (CEE_MKREFANY) ves_abort(); BREAK;
2737 CASE (CEE_UNUSED67) ves_abort(); BREAK;
2738 CASE (CEE_LDTOKEN) {
2740 MonoClass *handle_class;
2742 handle = mono_ldtoken (image, read32 (ip), &handle_class);
2744 vt_alloc (&handle_class->byval_arg, sp);
2745 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
2749 CASE (CEE_CONV_OVF_I)
2752 /* FIXME: check overflow. */
2755 sp->data.p = (gpointer)(mono_i) sp->data.i;
2758 sp->data.p = (gpointer)(mono_i) sp->data.l;
2763 sp->data.p = (gpointer)(mono_i) sp->data.f;
2768 sp->type = VAL_NATI;
2771 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
2772 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
2773 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
2774 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
2775 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
2776 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
2777 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
2778 CASE (CEE_ENDFINALLY)
2782 * There was no exception, we continue normally at the target address.
2786 CASE (CEE_LEAVE) /* Fall through */
2789 if (*ip == CEE_LEAVE_S) {
2791 ip += (signed char) *ip;
2795 ip += (gint32) read32 (ip);
2799 * We may be either inside a try block or inside an handler.
2800 * In the first case there was no exception and we go on
2801 * executing the finally handlers and after that resume control
2803 * In the second case we need to clear the exception and
2804 * continue directly at the target ip.
2808 goto handle_finally;
2811 frame->ex_handler = NULL;
2843 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
2845 * Note: Exceptions thrown when executing a prefixed opcode need
2846 * to take into account the number of prefix bytes (usually the
2847 * throw point is just (ip - n_prefix_bytes).
2852 case CEE_ARGLIST: ves_abort(); break;
2858 if (sp->type == VAL_I32)
2859 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
2860 else if (sp->type == VAL_I64)
2861 result = sp [0].data.l == sp [1].data.l;
2862 else if (sp->type == VAL_DOUBLE) {
2863 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
2866 result = sp [0].data.f == sp [1].data.f;
2868 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
2870 sp->data.i = result;
2880 if (sp->type == VAL_I32)
2881 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
2882 else if (sp->type == VAL_I64)
2883 result = sp [0].data.l > sp [1].data.l;
2884 else if (sp->type == VAL_DOUBLE) {
2885 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
2888 result = sp [0].data.f > sp [1].data.f;
2890 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
2892 sp->data.i = result;
2902 if (sp->type == VAL_I32)
2903 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2904 else if (sp->type == VAL_I64)
2905 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2906 else if (sp->type == VAL_DOUBLE)
2907 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
2909 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
2911 sp->data.i = result;
2921 if (sp->type == VAL_I32)
2922 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
2923 else if (sp->type == VAL_I64)
2924 result = sp [0].data.l < sp [1].data.l;
2925 else if (sp->type == VAL_DOUBLE) {
2926 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
2929 result = sp [0].data.f < sp [1].data.f;
2931 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
2933 sp->data.i = result;
2943 if (sp->type == VAL_I32)
2944 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
2945 else if (sp->type == VAL_I64)
2946 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
2947 else if (sp->type == VAL_DOUBLE)
2948 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
2950 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
2952 sp->data.i = result;
2958 case CEE_LDVIRTFTN: {
2959 int virtual = *ip == CEE_LDVIRTFTN;
2963 token = read32 (ip);
2965 m = mono_get_method (image, token, NULL);
2967 THROW_EX (get_exception_missing_method (), ip - 5);
2971 THROW_EX (get_exception_null_reference (), ip - 5);
2972 m = get_virtual_method (m, sp);
2974 sp->type = VAL_NATI;
2975 sp->data.p = mono_create_method_pointer (m);
2976 sp->data.vt.klass = NULL;
2980 case CEE_UNUSED56: ves_abort(); break;
2984 arg_pos = read32 (ip);
2986 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
2987 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2999 t = ARG_TYPE (signature, anum);
3000 c = mono_class_from_mono_type (t);
3001 sp->data.vt.klass = c;
3002 sp->data.vt.vt = ARG_POS (anum);
3005 sp->type = VAL_VALUETA;
3016 arg_pos = read32 (ip);
3019 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3026 loc_pos = read32 (ip);
3028 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3029 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3039 loc_pos = read32 (ip);
3041 t = LOCAL_TYPE (header, loc_pos);
3042 c = mono_class_from_mono_type (t);
3043 sp->data.vt.vt = LOCAL_POS (loc_pos);
3044 sp->data.vt.klass = c;
3047 sp->type = VAL_VALUETA;
3057 loc_pos = read32 (ip);
3060 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3065 if (sp != frame->stack)
3066 THROW_EX (get_exception_execution_engine (), ip - 1);
3068 sp->data.p = alloca (sp->data.i);
3071 case CEE_UNUSED57: ves_abort(); break;
3072 case CEE_ENDFILTER: ves_abort(); break;
3073 case CEE_UNALIGNED_:
3075 unaligned_address = 1;
3079 volatile_address = 1;
3088 token = read32 (ip);
3091 * we ignore the value of token (I think we can as unspecified
3092 * behavior described in Partition II, 3.5).
3095 g_assert (sp->type = VAL_VALUETA);
3096 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3099 case CEE_UNUSED68: ves_abort(); break;
3102 if (!sp [0].data.p || !sp [1].data.p)
3103 THROW_EX (get_exception_null_reference(), ip - 1);
3105 /* FIXME: value and size may be int64... */
3106 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3111 THROW_EX (get_exception_null_reference(), ip - 1);
3113 /* FIXME: value and size may be int64... */
3114 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3116 case CEE_UNUSED69: ves_abort(); break;
3119 * need to clarify what this should actually do:
3120 * start the search from the last found handler in
3121 * this method or continue in the caller or what.
3122 * Also, do we need to run finally/fault handlers after a retrow?
3123 * Well, this implementation will follow the usual search
3124 * for an handler, considering the current ip as throw spot.
3125 * We need to NULL frame->ex_handler for the later code to
3126 * actually run the new found handler.
3128 frame->ex_handler = NULL;
3129 THROW_EX (frame->ex, ip - 1);
3131 case CEE_UNUSED: ves_abort(); break;
3136 token = read32 (ip);
3138 c = mono_class_get (image, token);
3140 sp->data.i = mono_class_value_size (c, NULL);
3144 case CEE_REFANYTYPE: ves_abort(); break;
3151 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3158 g_assert_not_reached ();
3160 * Exception handling code.
3161 * The exception object is stored in frame->ex.
3163 #define OFFSET_IN_CLAUSE(clause,offset) \
3164 ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
3170 MonoInvocation *inv;
3171 MonoMethodHeader *hd;
3172 MonoExceptionClause *clause;
3176 for (inv = frame; inv; inv = inv->parent) {
3177 hd = ((MonoMethodNormal*)inv->method)->header;
3178 ip_offset = inv->ip - hd->code;
3179 for (i = 0; i < hd->num_clauses; ++i) {
3180 clause = &hd->clauses [i];
3181 if (clause->flags <= 1 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3182 if (!clause->flags) {
3183 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3185 * OK, we found an handler, now we need to execute the finally
3186 * and fault blocks before branching to the handler code.
3188 inv->ex_handler = clause;
3190 * It seems that if the catch handler is found in the same method,
3191 * it gets executed before the finally handler.
3196 goto handle_finally;
3199 /* FIXME: handle filter clauses */
3206 * If we get here, no handler was found: print a stack trace.
3208 ex_obj = (MonoObject*)frame->ex;
3209 message = frame->ex->message? mono_string_to_utf8 (frame->ex->message): NULL;
3210 g_print ("Unhandled exception %s.%s %s.\n", ex_obj->klass->name_space, ex_obj->klass->name,
3211 message?message:"");
3220 MonoExceptionClause *clause;
3222 ip_offset = frame->ip - header->code;
3223 for (i = 0; i < header->num_clauses; ++i) {
3224 clause = &header->clauses [i];
3225 if (clause->flags == 2 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3226 ip = header->code + clause->handler_offset;
3231 * If an exception is set, we need to execute the fault handler, too,
3232 * otherwise, we continue normally.
3243 MonoExceptionClause *clause;
3245 ip_offset = frame->ip - header->code;
3246 for (i = 0; i < header->num_clauses; ++i) {
3247 clause = &header->clauses [i];
3248 if (clause->flags == 3 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3249 ip = header->code + clause->handler_offset;
3254 * If the handler for the exception was found in this method, we jump
3255 * to it right away, otherwise we return and let the caller run
3256 * the finally, fault and catch blocks.
3257 * This same code should be present in the endfault opcode, but it
3258 * is corrently not assigned in the ECMA specs: LAMESPEC.
3260 if (frame->ex_handler) {
3261 ip = header->code + frame->ex_handler->handler_offset;
3264 sp->data.p = frame->ex;
3275 ves_exec (MonoAssembly *assembly, int argc, char *argv[])
3277 MonoImage *image = assembly->image;
3278 MonoCLIImageInfo *iinfo;
3280 MonoInvocation call;
3283 iinfo = image->image_info;
3284 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3286 g_error ("No entry point method found in %s", image->name);
3288 if (method->signature->param_count) {
3290 stackval argv_array;
3291 MonoArray *arr = (MonoArray*)mono_array_new (mono_defaults.string_class, argc);
3292 argv_array.type = VAL_OBJ;
3293 argv_array.data.p = arr;
3294 argv_array.data.vt.klass = NULL;
3295 for (i=0; i < argc; ++i) {
3296 mono_array_set (arr, gpointer, i, mono_string_new (argv [i]));
3298 INIT_FRAME (&call, NULL, NULL, &argv_array, &result, method);
3300 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
3303 ves_exec_method (&call);
3304 mono_free_method (call.method);
3306 return result.data.i;
3313 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3314 "Usage is: mint [options] executable args...\n", VERSION);
3316 "Valid Options are:\n"
3318 "--debug method_name\n"
3319 "--opcode-count\n");
3325 test_load_class (MonoImage* image)
3327 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3331 for (i = 1; i <= t->rows; ++i) {
3332 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3333 mono_class_metadata_init (klass);
3349 typebuilder_fields[] = {
3350 {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
3351 {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
3352 {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
3353 {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
3354 {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
3355 {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
3356 {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
3357 {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
3358 {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
3363 modulebuilder_fields[] = {
3364 {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
3365 {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
3370 assemblybuilder_fields[] = {
3371 {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
3372 {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
3373 {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
3378 ctorbuilder_fields[] = {
3379 {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
3380 {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
3381 {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
3382 {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
3383 {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
3384 {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
3385 {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
3390 methodbuilder_fields[] = {
3391 {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
3392 {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
3393 {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
3394 {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
3395 {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
3396 {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
3397 {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
3398 {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
3399 {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
3400 {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
3401 {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
3402 {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
3403 {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
3404 {"ncharset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
3405 {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
3406 {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
3411 fieldbuilder_fields[] = {
3412 {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
3413 {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
3414 {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
3415 {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
3416 {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
3417 {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
3422 propertybuilder_fields[] = {
3423 {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
3424 {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
3425 {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
3426 {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
3427 {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
3428 {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
3429 {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
3430 {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
3435 emit_classes_to_check [] = {
3436 {"TypeBuilder", typebuilder_fields},
3437 {"ModuleBuilder", modulebuilder_fields},
3438 {"AssemblyBuilder", assemblybuilder_fields},
3439 {"ConstructorBuilder", ctorbuilder_fields},
3440 {"MethodBuilder", methodbuilder_fields},
3441 {"FieldBuilder", fieldbuilder_fields},
3442 {"PropertyBuilder", propertybuilder_fields},
3447 delegate_fields[] = {
3448 {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
3449 {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
3450 {"method", G_STRUCT_OFFSET (MonoDelegate, method)},
3451 {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
3456 system_classes_to_check [] = {
3457 {"Delegate", delegate_fields},
3466 static NameSpaceDesc
3467 namespaces_to_check[] = {
3468 {"System.Reflection.Emit", emit_classes_to_check},
3469 {"System", system_classes_to_check},
3474 check_corlib (MonoImage *corlib)
3477 MonoClassField *field;
3480 NameSpaceDesc *ndesc;
3482 for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
3483 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
3484 klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
3486 g_error ("Cannot find class %s", cdesc->name);
3487 mono_class_metadata_init (klass);
3488 for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
3489 field = mono_class_get_field_from_name (klass, fdesc->name);
3490 if (!field || (field->offset != fdesc->offset))
3491 g_error ("field %s mismatch in class %s (%ld != %ld)", fdesc->name, cdesc->name, (long) fdesc->offset, (long) (field?field->offset:-1));
3498 main (int argc, char *argv [])
3500 MonoAssembly *assembly;
3501 int retval = 0, i, ocount = 0;
3507 for (i = 1; i < argc && argv [i][0] == '-'; i++){
3508 if (strcmp (argv [i], "--trace") == 0)
3510 if (strcmp (argv [i], "--opcode-count") == 0)
3512 if (strcmp (argv [i], "--help") == 0)
3515 if (strcmp (argv [i], "--debug") == 0)
3516 db_methods = g_list_append (db_methods, argv [++i]);
3527 mono_install_handler (interp_ex_handler);
3529 mono_add_internal_call ("__array_Set", ves_array_set);
3530 mono_add_internal_call ("__array_Get", ves_array_get);
3532 assembly = mono_assembly_open (file, NULL, NULL);
3534 fprintf (stderr, "Can not open image %s\n", file);
3540 frame_thread_id = TlsAlloc ();
3541 TlsSetValue (frame_thread_id, NULL);
3544 test_load_class (assembly->image);
3546 check_corlib (mono_defaults.corlib);
3548 * skip the program name from the args.
3551 retval = ves_exec (assembly, argc - i, argv + i);
3553 mono_thread_cleanup();
3555 mono_assembly_close (assembly);
3559 fprintf (stderr, "opcode count: %ld\n", opcode_count);
3560 fprintf (stderr, "fcall count: %ld\n", fcall_count);