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.
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/blob.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/io-layer/io-layer.h>
55 #include <mono/metadata/socket-io.h>
56 #include <mono/os/util.h>
58 /*#include <mono/cli/types.h>*/
64 #define finite _finite
67 /* If true, then we output the opcodes as we interpret them */
68 static int global_tracing = 0;
69 static int global_no_pointers = 0;
71 static int debug_indent_level = 0;
74 * Pull the list of opcodes
76 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
80 #include "mono/cil/opcode.def"
85 #define GET_NATI(sp) ((sp).data.nati)
86 #define CSIZE(x) (sizeof (x) / 4)
88 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
90 (frame)->parent = (parent_frame); \
91 (frame)->obj = (obj_this); \
92 (frame)->stack_args = (method_args); \
93 (frame)->retval = (method_retval); \
94 (frame)->method = (mono_method); \
95 (frame)->ex_handler = NULL; \
97 (frame)->child = NULL; \
100 void ves_exec_method (MonoInvocation *frame);
102 typedef void (*ICallMethod) (MonoInvocation *frame);
104 static guint32 die_on_exception = 0;
105 static guint32 frame_thread_id = 0;
107 #define DEBUG_INTERP 1
110 static unsigned long opcode_count = 0;
111 static unsigned long fcall_count = 0;
112 static int break_on_method = 0;
113 static GList *db_methods = NULL;
120 for (h = 0; h < debug_indent_level; h++)
125 db_match_method (gpointer data, gpointer user_data)
127 MonoMethod *m = (MonoMethod*)user_data;
128 MonoMethodDesc *desc = data;
130 if (mono_method_desc_full_match (desc, m))
134 #define DEBUG_ENTER() \
136 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
137 if (break_on_method) tracing=2; \
138 break_on_method = 0; \
140 MonoClass *klass = frame->method->klass; \
141 char *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
142 debug_indent_level++; \
144 g_print ("(%d) Entering %s.%s::%s (", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
145 if (signature->hasthis) { \
146 if (global_no_pointers) { \
147 g_print ("this%s ", frame->obj ? "" : "=null"); \
149 g_print ("%p ", frame->obj); } \
151 g_print ("%s)\n", args); \
154 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
155 mono_profiler_method_enter (frame->method);
157 #define DEBUG_LEAVE() \
159 MonoClass *klass = frame->method->klass; \
161 if (signature->ret->type != MONO_TYPE_VOID) \
162 args = dump_stack (frame->retval, frame->retval + 1); \
164 args = g_strdup (""); \
166 g_print ("(%d) Leaving %s.%s::%s", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
167 g_print (" => %s\n", args); \
169 debug_indent_level--; \
171 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
172 mono_profiler_method_leave (frame->method);
176 #define DEBUG_ENTER()
177 #define DEBUG_LEAVE()
182 interp_ex_handler (MonoException *ex) {
183 MonoInvocation *frame = TlsGetValue (frame_thread_id);
185 longjmp (*(jmp_buf*)frame->locals, 1);
189 ves_real_abort (int line, MonoMethod *mh,
190 const unsigned char *ip, stackval *stack, stackval *sp)
192 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
193 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
194 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
195 ip-mm->header->code);
196 g_print ("0x%04x %02x\n",
197 ip-mm->header->code, *ip);
199 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
201 #define ves_abort() do {ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp); THROW_EX (mono_get_exception_execution_engine (NULL), ip);} while (0);
204 interp_create_remoting_trampoline (MonoMethod *method)
210 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
216 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
220 klass = obj->vtable->klass;
221 vtable = (MonoMethod **)obj->vtable->vtable;
223 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
224 return *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
227 g_assert (vtable [m->slot]);
229 return vtable [m->slot];
233 stackval_from_data (MonoType *type, stackval *result, char *data)
236 switch (type->type) {
237 case MONO_TYPE_OBJECT:
238 case MONO_TYPE_CLASS:
239 case MONO_TYPE_STRING:
240 case MONO_TYPE_ARRAY:
241 case MONO_TYPE_SZARRAY:
242 result->type = VAL_OBJ;
245 result->type = VAL_VALUETA;
248 result->data.p = *(gpointer*)data;
249 result->data.vt.klass = mono_class_from_mono_type (type);
252 switch (type->type) {
256 result->type = VAL_I32;
257 result->data.i = *(gint8*)data;
260 case MONO_TYPE_BOOLEAN:
261 result->type = VAL_I32;
262 result->data.i = *(guint8*)data;
265 result->type = VAL_I32;
266 result->data.i = *(gint16*)data;
270 result->type = VAL_I32;
271 result->data.i = *(guint16*)data;
274 result->type = VAL_I32;
275 result->data.i = *(gint32*)data;
280 result->type = VAL_TP;
281 result->data.p = *(gpointer*)data;
284 result->type = VAL_I32;
285 result->data.i = *(guint32*)data;
288 result->type = VAL_DOUBLE;
289 result->data.f = *(float*)data;
293 result->type = VAL_I64;
294 result->data.l = *(gint64*)data;
297 result->type = VAL_DOUBLE;
298 result->data.f = *(double*)data;
300 case MONO_TYPE_STRING:
301 case MONO_TYPE_SZARRAY:
302 case MONO_TYPE_CLASS:
303 case MONO_TYPE_OBJECT:
304 case MONO_TYPE_ARRAY:
305 result->type = VAL_OBJ;
306 result->data.p = *(gpointer*)data;
307 result->data.vt.klass = mono_class_from_mono_type (type);
309 case MONO_TYPE_VALUETYPE:
310 if (type->data.klass->enumtype) {
311 return stackval_from_data (type->data.klass->enum_basetype, result, data);
313 result->type = VAL_VALUET;
314 result->data.vt.klass = type->data.klass;
315 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
319 g_warning ("got type 0x%02x", type->type);
320 g_assert_not_reached ();
325 stackval_to_data (MonoType *type, stackval *val, char *data)
328 gpointer *p = (gpointer*)data;
332 switch (type->type) {
335 guint8 *p = (guint8*)data;
339 case MONO_TYPE_BOOLEAN: {
340 guint8 *p = (guint8*)data;
341 *p = (val->data.i != 0);
346 case MONO_TYPE_CHAR: {
347 guint16 *p = (guint16*)data;
351 #if SIZEOF_VOID_P == 4
357 gint32 *p = (gint32*)data;
361 #if SIZEOF_VOID_P == 8
367 gint64 *p = (gint64*)data;
372 float *p = (float*)data;
377 double *p = (double*)data;
381 case MONO_TYPE_STRING:
382 case MONO_TYPE_SZARRAY:
383 case MONO_TYPE_CLASS:
384 case MONO_TYPE_OBJECT:
385 case MONO_TYPE_ARRAY:
386 case MONO_TYPE_PTR: {
387 gpointer *p = (gpointer*)data;
391 case MONO_TYPE_VALUETYPE:
392 if (type->data.klass->enumtype) {
393 return stackval_to_data (type->data.klass->enum_basetype, val, data);
395 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
399 g_warning ("got type %x", type->type);
400 g_assert_not_reached ();
405 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
408 guint32 *lower_bounds;
411 lengths = alloca (sizeof (guint32) * klass->rank * 2);
412 for (i = 0; i < sig->param_count; ++i) {
413 lengths [i] = values->data.i;
416 if (klass->rank == sig->param_count) {
417 /* Only lengths provided. */
420 /* lower bounds are first. */
421 lower_bounds = lengths;
422 lengths += klass->rank;
424 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
428 ves_array_set (MonoInvocation *frame)
430 stackval *sp = frame->stack_args;
434 gint32 i, t, pos, esize;
440 ac = o->vtable->klass;
442 g_assert (ac->rank >= 1);
445 if (ao->bounds != NULL) {
446 pos -= ao->bounds [0].lower_bound;
447 for (i = 1; i < ac->rank; i++) {
448 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
449 ao->bounds [i].length) {
450 g_warning ("wrong array index");
451 g_assert_not_reached ();
453 pos = pos*ao->bounds [i].length + sp [i].data.i -
454 ao->bounds [i].lower_bound;
458 esize = mono_array_element_size (ac);
459 ea = mono_array_addr_with_size (ao, esize, pos);
461 mt = frame->method->signature->params [ac->rank];
462 stackval_to_data (mt, &sp [ac->rank], ea);
466 ves_array_get (MonoInvocation *frame)
468 stackval *sp = frame->stack_args;
472 gint32 i, pos, esize;
478 ac = o->vtable->klass;
480 g_assert (ac->rank >= 1);
483 if (ao->bounds != NULL) {
484 pos -= ao->bounds [0].lower_bound;
485 for (i = 1; i < ac->rank; i++)
486 pos = pos*ao->bounds [i].length + sp [i].data.i -
487 ao->bounds [i].lower_bound;
490 esize = mono_array_element_size (ac);
491 ea = mono_array_addr_with_size (ao, esize, pos);
493 mt = frame->method->signature->ret;
494 stackval_from_data (mt, frame->retval, ea);
498 ves_array_element_address (MonoInvocation *frame)
500 stackval *sp = frame->stack_args;
504 gint32 i, pos, esize;
509 ac = o->vtable->klass;
511 g_assert (ac->rank >= 1);
514 if (ao->bounds != NULL) {
515 pos -= ao->bounds [0].lower_bound;
516 for (i = 1; i < ac->rank; i++)
517 pos = pos*ao->bounds [i].length + sp [i].data.i -
518 ao->bounds [i].lower_bound;
521 esize = mono_array_element_size (ac);
522 ea = mono_array_addr_with_size (ao, esize, pos);
524 frame->retval->type = VAL_TP;
525 frame->retval->data.p = ea;
529 ves_pinvoke_method (MonoInvocation *frame)
535 TlsSetValue (frame_thread_id, frame->args);
538 if (!frame->method->info)
539 frame->method->info = mono_create_trampoline (frame->method, 0);
540 func = (MonoPIFunc)frame->method->info;
543 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
544 * locals will point to the jmp_buf, while args will point to the previous
545 * MonoInvocation frame: this is needed to make exception searching work across
546 * managed/unmanaged boundaries.
548 frame->locals = (char*)&env;
549 frame->args = (char*)TlsGetValue (frame_thread_id);
550 TlsSetValue (frame_thread_id, frame);
552 func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
553 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
554 TlsSetValue (frame_thread_id, frame->args);
559 * runtime specifies that the implementation of the method is automatically
560 * provided by the runtime and is primarily used for the methods of delegates.
563 ves_runtime_method (MonoInvocation *frame)
565 const char *name = frame->method->name;
566 MonoObject *obj = (MonoObject*)frame->obj;
567 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
570 mono_class_init (mono_defaults.multicastdelegate_class);
572 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
573 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
574 delegate->delegate.target = frame->stack_args[0].data.p;
575 delegate->delegate.method_ptr = frame->stack_args[1].data.p;
576 delegate->delegate.method_info = mono_method_get_object (mono_object_domain(delegate), mono_method_pointer_get (delegate->delegate.method_ptr));
579 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
580 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
586 code = (guchar*)delegate->delegate.method_ptr;
587 method = mono_method_pointer_get (code);
589 /* FIXME: check for NULL method */
590 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
591 ves_exec_method (&call);
594 method->addr = mono_create_trampoline (method, 1);
596 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
597 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, delegate->target, frame->stack_args);
598 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
600 delegate = delegate->prev;
604 g_error ("Don't know how to exec runtime method %s.%s::%s",
605 frame->method->klass->name_space, frame->method->klass->name,
606 frame->method->name);
610 dump_stack (stackval *stack, stackval *sp)
613 GString *str = g_string_new ("");
616 return g_string_free (str, FALSE);
620 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
621 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
622 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
624 if (!global_no_pointers)
625 g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
627 g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
630 MonoObject *obj = s->data.p;
631 if (global_no_pointers && obj && obj->vtable) {
632 MonoClass *klass = mono_object_class (obj);
633 if (klass == mono_defaults.string_class) {
634 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
635 g_string_sprintfa (str, "[str:%s] ", utf8);
638 } else if (klass == mono_defaults.sbyte_class) {
639 g_string_sprintfa (str, "[b:%d] ",
640 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
642 } else if (klass == mono_defaults.int16_class) {
643 g_string_sprintfa (str, "[b:%d] ",
644 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
646 } else if (klass == mono_defaults.int32_class) {
647 g_string_sprintfa (str, "[b:%d] ",
648 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
650 } else if (klass == mono_defaults.byte_class) {
651 g_string_sprintfa (str, "[b:%u] ",
652 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
654 } else if (klass == mono_defaults.char_class
655 || klass == mono_defaults.uint16_class) {
656 g_string_sprintfa (str, "[b:%u] ",
657 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
659 } else if (klass == mono_defaults.uint32_class) {
660 g_string_sprintfa (str, "[b:%u] ",
661 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
663 } else if (klass == mono_defaults.int64_class) {
664 g_string_sprintfa (str, "[b:%lld] ",
665 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
667 } else if (klass == mono_defaults.uint64_class) {
668 g_string_sprintfa (str, "[b:%llu] ",
669 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
671 } else if (klass == mono_defaults.double_class) {
672 g_string_sprintfa (str, "[b:%0.5f] ",
673 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
675 } else if (klass == mono_defaults.single_class) {
676 g_string_sprintfa (str, "[b:%0.5f] ",
677 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
679 } else if (klass == mono_defaults.boolean_class) {
680 g_string_sprintfa (str, "[b:%s] ",
681 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
689 if (!global_no_pointers)
690 g_string_sprintfa (str, "[%p] ", s->data.p);
692 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
697 return g_string_free (str, FALSE);
701 dump_frame (MonoInvocation *inv)
703 GString *str = g_string_new ("");
706 for (i = 0; inv; inv = inv->parent, ++i) {
707 MonoClass *k = inv->method->klass;
710 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
711 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
715 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
717 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
720 opname = mono_opcode_names [codep];
721 codep = inv->ip - hd->code;
723 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
724 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
725 k->name_space, k->name, inv->method->name, args);
728 return g_string_free (str, FALSE);
731 static CRITICAL_SECTION metadata_lock;
734 INLINE_STRING_LENGTH = 1,
737 INLINE_TYPE_ELEMENT_TYPE
741 calc_offsets (MonoImage *image, MonoMethod *method)
743 int i, align, size, offset = 0;
744 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
745 MonoMethodSignature *signature = method->signature;
746 int hasthis = signature->hasthis;
747 register const unsigned char *ip, *end;
748 const MonoOpcode *opcode;
752 MonoDomain *domain = mono_domain_get ();
755 mono_profiler_method_jit (method); /* sort of... */
756 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
757 for (i = 0; i < header->num_locals; ++i) {
758 size = mono_type_size (header->locals [i], &align);
760 offset &= ~(align - 1);
761 offsets [2 + i] = offset;
764 offsets [0] = offset;
767 offset += sizeof (gpointer) - 1;
768 offset &= ~(sizeof (gpointer) - 1);
769 offsets [2 + header->num_locals] = offset;
770 offset += sizeof (gpointer);
772 for (i = 0; i < signature->param_count; ++i) {
773 size = mono_type_size (signature->params [i], &align);
775 offset &= ~(align - 1);
776 offsets [2 + hasthis + header->num_locals + i] = offset;
779 offsets [1] = offset;
781 EnterCriticalSection (&metadata_lock);
782 /* intern the strings in the method. */
784 end = ip + header->code_size;
791 opcode = &mono_opcodes [i];
792 switch (opcode->argument) {
796 case MonoInlineString:
797 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
801 class = mono_class_get (image, read32 (ip + 1));
802 mono_class_init (class);
803 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
804 mono_class_vtable (domain, class);
807 case MonoInlineField:
808 token = read32 (ip + 1);
809 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
810 mono_field_from_memberref (image, token, &class);
812 class = mono_class_get (image,
813 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
815 mono_class_init (class);
816 mono_class_vtable (domain, class);
819 case MonoInlineMethod:
820 m = mono_get_method (image, read32 (ip + 1), NULL);
821 mono_class_init (m->klass);
822 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
823 mono_class_vtable (domain, m->klass);
828 case MonoShortInlineR:
830 case MonoInlineBrTarget:
836 case MonoShortInlineVar:
837 case MonoShortInlineI:
838 case MonoShortInlineBrTarget:
841 case MonoInlineSwitch: {
854 g_assert_not_reached ();
858 method->info = offsets;
861 * We store the inline info in addr, since it's unused for IL methods.
863 if (method->klass == mono_defaults.string_class) {
864 if (strcmp (method->name, "get_Length") == 0)
865 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
866 } else if (method->klass == mono_defaults.array_class) {
867 if (strcmp (method->name, "get_Length") == 0)
868 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
869 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
870 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
871 } else if (method->klass == mono_defaults.monotype_class) {
872 if (strcmp (method->name, "GetElementType") == 0)
873 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
875 LeaveCriticalSection (&metadata_lock);
876 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
879 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
880 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
882 #define ARG_POS(n) (args_pointers [(n)])
883 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
884 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
886 #define THROW_EX(exception,ex_ip) \
889 frame->ip = (ex_ip); \
890 stack_trace = dump_frame (frame); \
891 frame->ex = (MonoException*)(exception); \
892 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
893 g_free (stack_trace); \
894 goto handle_exception; \
897 typedef struct _vtallocation vtallocation;
899 struct _vtallocation {
902 char data [MONO_ZERO_LEN_ARRAY];
906 * we don't use vtallocation->next, yet
908 #define vt_alloc(vtype,sp) \
909 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
910 if (!(vtype)->byref) { \
912 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
913 if (!vtalloc || vtalloc->size <= size) { \
914 vtalloc = alloca (sizeof (vtallocation) + size); \
915 vtalloc->size = size; \
916 g_assert (size < 10000); \
918 (sp)->data.vt.vt = vtalloc->data; \
921 (sp)->data.vt.klass = (vtype)->data.klass; \
925 #define vt_free(sp) \
927 if ((sp)->type == VAL_VALUET) { \
928 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
933 verify_method (MonoMethod *m)
935 GSList *errors, *tmp;
936 MonoVerifyInfo *info;
938 errors = mono_method_verify (m, MONO_VERIFY_ALL);
940 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
941 for (tmp = errors; tmp; tmp = tmp->next) {
943 g_print ("%s\n", info->message);
947 mono_free_verify_list (errors);
950 #define MYGUINT64_MAX 18446744073709551615UL
951 #define MYGINT64_MAX 9223372036854775807LL
952 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
954 #define MYGUINT32_MAX 4294967295U
955 #define MYGINT32_MAX 2147483647
956 #define MYGINT32_MIN (-MYGINT32_MAX -1)
958 #define CHECK_ADD_OVERFLOW(a,b) \
959 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
960 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
962 #define CHECK_ADD_OVERFLOW_UN(a,b) \
963 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
965 #define CHECK_ADD_OVERFLOW64(a,b) \
966 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
967 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
969 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
970 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
973 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
976 MonoInvocation frame;
977 MonoObject *retval = NULL;
978 MonoMethodSignature *sig = method->signature;
979 MonoClass *klass = mono_class_from_mono_type (sig->ret);
980 int i, type, isobject = 0;
983 stackval *args = alloca (sizeof (stackval) * sig->param_count);
985 /* FIXME: Set frame for execption handling. */
987 switch (sig->ret->type) {
990 case MONO_TYPE_STRING:
991 case MONO_TYPE_OBJECT:
992 case MONO_TYPE_CLASS:
993 case MONO_TYPE_ARRAY:
994 case MONO_TYPE_SZARRAY:
997 case MONO_TYPE_VALUETYPE:
998 retval = mono_object_new (mono_domain_get (), klass);
999 ret = ((char*)retval) + sizeof (MonoObject);
1000 if (!sig->ret->data.klass->enumtype)
1001 result.data.vt.vt = ret;
1004 retval = mono_object_new (mono_domain_get (), klass);
1005 ret = ((char*)retval) + sizeof (MonoObject);
1009 for (i = 0; i < sig->param_count; ++i) {
1010 if (sig->params [i]->byref) {
1011 args [i].type = VAL_POINTER;
1012 args [i].data.p = params [i];
1015 type = sig->params [i]->type;
1020 case MONO_TYPE_BOOLEAN:
1021 args [i].type = VAL_I32;
1022 args [i].data.i = *(MonoBoolean*)params [i];
1023 args [i].data.vt.klass = NULL;
1027 case MONO_TYPE_CHAR:
1028 args [i].type = VAL_I32;
1029 args [i].data.i = *(gint16*)params [i];
1030 args [i].data.vt.klass = NULL;
1032 #if SIZEOF_VOID_P == 4
1033 case MONO_TYPE_U: /* use VAL_POINTER? */
1038 args [i].type = VAL_I32;
1039 args [i].data.i = *(gint32*)params [i];
1040 args [i].data.vt.klass = NULL;
1042 #if SIZEOF_VOID_P == 8
1048 args [i].type = VAL_I64;
1049 args [i].data.l = *(gint64*)params [i];
1050 args [i].data.vt.klass = NULL;
1052 case MONO_TYPE_VALUETYPE:
1053 if (sig->params [i]->data.klass->enumtype) {
1054 type = sig->params [i]->data.klass->enum_basetype->type;
1057 g_warning ("generic valutype %s not handled in runtime invoke", sig->params [i]->data.klass->name);
1060 case MONO_TYPE_STRING:
1061 case MONO_TYPE_CLASS:
1062 case MONO_TYPE_ARRAY:
1063 case MONO_TYPE_SZARRAY:
1064 case MONO_TYPE_OBJECT:
1065 args [i].type = VAL_OBJ;
1066 args [i].data.p = params [i];
1067 args [i].data.vt.klass = NULL;
1070 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1074 INIT_FRAME(&frame,NULL,obj,args,&result,method);
1075 ves_exec_method (&frame);
1076 if (sig->ret->type == MONO_TYPE_VOID)
1079 return result.data.p;
1080 stackval_to_data (sig->ret, &result, ret);
1085 * Need to optimize ALU ops when natural int == int32
1087 * IDEA: if we maintain a stack of ip, sp to be checked
1088 * in the return opcode, we could inline simple methods that don't
1089 * use the stack or local variables....
1091 * The {,.S} versions of many opcodes can/should be merged to reduce code
1096 ves_exec_method (MonoInvocation *frame)
1098 MonoDomain *domain = mono_domain_get ();
1099 MonoInvocation child_frame;
1100 MonoMethodHeader *header;
1101 MonoMethodSignature *signature;
1103 GSList *finally_ips = NULL;
1104 const unsigned char *endfinally_ip;
1105 register const unsigned char *ip;
1106 register stackval *sp;
1107 void **args_pointers;
1109 gint il_ins_count = -1;
1110 gint tracing = global_tracing;
1111 unsigned char tail_recursion = 0;
1112 unsigned char unaligned_address = 0;
1113 unsigned char volatile_address = 0;
1114 vtallocation *vtalloc = NULL;
1117 signature = frame->method->signature;
1121 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1122 if (!frame->method->addr) {
1123 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1127 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1128 ves_pinvoke_method (frame);
1130 ICallMethod icall = (ICallMethod)frame->method->addr;
1134 goto handle_exception;
1139 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1140 if (!frame->method->addr) {
1141 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1145 ves_pinvoke_method (frame);
1147 goto handle_exception;
1152 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1153 ves_runtime_method (frame);
1155 goto handle_exception;
1160 /*verify_method (frame->method);*/
1162 header = ((MonoMethodNormal *)frame->method)->header;
1163 image = frame->method->klass->image;
1165 if (!frame->method->info)
1166 calc_offsets (image, frame->method);
1167 offsets = frame->method->info;
1170 * with alloca we get the expected huge performance gain
1171 * stackval *stack = g_new0(stackval, header->max_stack);
1173 g_assert (header->max_stack < 10000);
1174 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1176 if (header->num_locals) {
1177 g_assert (offsets [0] < 10000);
1178 frame->locals = alloca (offsets [0]);
1180 * yes, we do it unconditionally, because it needs to be done for
1181 * some cases anyway and checking for that would be even slower.
1183 memset (frame->locals, 0, offsets [0]);
1186 * Copy args from stack_args to args.
1188 if (signature->param_count || signature->hasthis) {
1190 int has_this = signature->hasthis;
1192 g_assert (offsets [1] < 10000);
1193 frame->args = alloca (offsets [1]);
1194 g_assert ((signature->param_count + has_this) < 1000);
1195 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1198 this_arg = args_pointers [0] = frame->args;
1199 *this_arg = frame->obj;
1201 for (i = 0; i < signature->param_count; ++i) {
1202 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1203 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this]);
1207 child_frame.parent = frame;
1208 frame->child = &child_frame;
1215 * using while (ip < end) may result in a 15% performance drop,
1216 * but it may be useful for debug
1220 /*g_assert (sp >= stack);*/
1225 if (sp > frame->stack) {
1227 ins = dump_stack (frame->stack, sp);
1228 g_print ("(%d) stack: %s\n", GetCurrentThreadId(), ins);
1232 ins = mono_disasm_code_one (NULL, frame->method, ip);
1233 g_print ("(%d) %s", GetCurrentThreadId(), ins);
1236 if (il_ins_count > 0)
1237 if (!(--il_ins_count))
1247 G_BREAKPOINT (); /* this is not portable... */
1252 CASE (CEE_LDARG_3) {
1253 int n = (*ip)-CEE_LDARG_0;
1255 vt_alloc (ARG_TYPE (signature, n), sp);
1256 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
1263 CASE (CEE_LDLOC_3) {
1264 int n = (*ip)-CEE_LDLOC_0;
1266 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1268 sp->data.i = *(gint32*) LOCAL_POS (n);
1272 vt_alloc (LOCAL_TYPE (header, n), sp);
1273 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1281 CASE (CEE_STLOC_3) {
1282 int n = (*ip)-CEE_STLOC_0;
1285 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1286 gint32 *p = (gint32*)LOCAL_POS (n);
1290 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1297 vt_alloc (ARG_TYPE (signature, *ip), sp);
1298 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1302 CASE (CEE_LDARGA_S) {
1307 t = ARG_TYPE (signature, *ip);
1308 c = mono_class_from_mono_type (t);
1309 sp->data.vt.klass = c;
1310 sp->data.vt.vt = ARG_POS (*ip);
1313 sp->type = VAL_VALUETA;
1324 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1330 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1331 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1335 CASE (CEE_LDLOCA_S) {
1340 t = LOCAL_TYPE (header, *ip);
1341 c = mono_class_from_mono_type (t);
1342 sp->data.vt.klass = c;
1343 sp->data.p = LOCAL_POS (*ip);
1346 sp->type = VAL_VALUETA;
1357 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1365 sp->data.vt.klass = NULL;
1368 CASE (CEE_LDC_I4_M1)
1384 sp->data.i = (*ip) - CEE_LDC_I4_0;
1391 sp->data.i = *(const gint8 *)ip;
1398 sp->data.i = read32 (ip);
1405 sp->data.l = read64 (ip);
1412 sp->type = VAL_DOUBLE;
1421 sp->type = VAL_DOUBLE;
1422 readr8(ip, &sp->data.f);
1426 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1428 if (sp [-1].type == VAL_VALUET) {
1429 MonoClass *c = sp [-1].data.vt.klass;
1430 vt_alloc (&c->byval_arg, sp);
1431 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1443 CASE (CEE_JMP) ves_abort(); BREAK;
1444 CASE (CEE_CALLVIRT) /* Fall through */
1445 CASE (CEE_CALLI) /* Fall through */
1447 MonoMethodSignature *csignature;
1449 stackval *endsp = sp;
1451 int virtual = *ip == CEE_CALLVIRT;
1452 int calli = *ip == CEE_CALLI;
1455 * We ignore tail recursion for now.
1462 token = read32 (ip);
1465 unsigned char *code;
1468 child_frame.method = mono_method_pointer_get (code);
1469 /* check for NULL with native code */
1470 csignature = child_frame.method->signature;
1472 child_frame.method = mono_get_method (image, token, NULL);
1473 if (!child_frame.method)
1474 THROW_EX (mono_get_exception_missing_method (), ip -5);
1475 csignature = child_frame.method->signature;
1477 stackval *this_arg = &sp [-csignature->param_count-1];
1478 if (!this_arg->data.p)
1479 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1480 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1481 if (!child_frame.method)
1482 THROW_EX (mono_get_exception_missing_method (), ip -5);
1485 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1486 /* decrement by the actual number of args */
1487 if (csignature->param_count) {
1488 sp -= csignature->param_count;
1489 child_frame.stack_args = sp;
1491 child_frame.stack_args = NULL;
1493 if (csignature->hasthis) {
1494 g_assert (sp >= frame->stack);
1497 * It may also be a TP from LD(S)FLDA
1498 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1500 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1501 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1503 child_frame.obj = sp->data.p;
1505 child_frame.obj = NULL;
1507 if (csignature->ret->type != MONO_TYPE_VOID) {
1508 vt_alloc (csignature->ret, &retval);
1509 child_frame.retval = &retval;
1511 child_frame.retval = NULL;
1514 child_frame.ex = NULL;
1515 child_frame.ex_handler = NULL;
1517 if (csignature->hasthis && sp->type == VAL_OBJ &&
1518 ((MonoObject *)sp->data.p)->vtable->klass ==
1519 mono_defaults.transparent_proxy_class) {
1520 /* implement remoting */
1521 g_assert_not_reached ();
1523 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1524 case INLINE_STRING_LENGTH:
1525 retval.type = VAL_I32;
1526 retval.data.i = ((MonoString*)sp->data.p)->length;
1527 //g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);
1529 case INLINE_ARRAY_LENGTH:
1530 retval.type = VAL_I32;
1531 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1533 case INLINE_ARRAY_RANK:
1534 retval.type = VAL_I32;
1535 retval.data.i = mono_object_class (sp->data.p)->rank;
1537 case INLINE_TYPE_ELEMENT_TYPE:
1538 retval.type = VAL_OBJ;
1540 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1541 retval.data.vt.klass = NULL;
1542 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1543 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1544 else if (c->element_class)
1545 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1547 retval.data.p = NULL;
1551 ves_exec_method (&child_frame);
1555 while (endsp > sp) {
1560 if (child_frame.ex) {
1562 * An exception occurred, need to run finally, fault and catch handlers..
1564 frame->ex = child_frame.ex;
1565 goto handle_finally;
1568 /* need to handle typedbyref ... */
1569 if (csignature->ret->type != MONO_TYPE_VOID) {
1576 if (signature->ret->type != MONO_TYPE_VOID) {
1578 if (sp->type == VAL_VALUET) {
1579 /* the caller has already allocated the memory */
1580 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1583 *frame->retval = *sp;
1586 if (sp > frame->stack)
1587 g_warning ("more values on stack: %d", sp-frame->stack);
1591 CASE (CEE_BR_S) /* Fall through */
1593 if (*ip == CEE_BR) {
1595 ip += (gint32) read32(ip);
1599 ip += (signed char) *ip;
1603 CASE (CEE_BRFALSE) /* Fall through */
1604 CASE (CEE_BRFALSE_S) {
1606 int near_jump = *ip == CEE_BRFALSE_S;
1610 case VAL_I32: result = sp->data.i == 0; break;
1611 case VAL_I64: result = sp->data.l == 0; break;
1612 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1613 default: result = sp->data.p == NULL; break;
1617 ip += (signed char)*ip;
1619 ip += (gint32) read32 (ip);
1621 ip += near_jump ? 1: 4;
1624 CASE (CEE_BRTRUE) /* Fall through */
1625 CASE (CEE_BRTRUE_S) {
1627 int near_jump = *ip == CEE_BRTRUE_S;
1631 case VAL_I32: result = sp->data.i != 0; break;
1632 case VAL_I64: result = sp->data.l != 0; break;
1633 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1634 default: result = sp->data.p != NULL; break;
1638 ip += (signed char)*ip;
1640 ip += (gint32) read32 (ip);
1642 ip += near_jump ? 1: 4;
1645 CASE (CEE_BEQ) /* Fall through */
1648 int near_jump = *ip == CEE_BEQ_S;
1651 if (sp->type == VAL_I32)
1652 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1653 else if (sp->type == VAL_I64)
1654 result = sp [0].data.l == sp [1].data.l;
1655 else if (sp->type == VAL_DOUBLE)
1656 result = sp [0].data.f == sp [1].data.f;
1658 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1661 ip += (signed char)*ip;
1663 ip += (gint32) read32 (ip);
1665 ip += near_jump ? 1: 4;
1668 CASE (CEE_BGE) /* Fall through */
1671 int near_jump = *ip == CEE_BGE_S;
1674 if (sp->type == VAL_I32)
1675 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1676 else if (sp->type == VAL_I64)
1677 result = sp [0].data.l >= sp [1].data.l;
1678 else if (sp->type == VAL_DOUBLE)
1679 result = sp [0].data.f >= sp [1].data.f;
1681 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1684 ip += (signed char)*ip;
1686 ip += (gint32) read32 (ip);
1688 ip += near_jump ? 1: 4;
1691 CASE (CEE_BGT) /* Fall through */
1694 int near_jump = *ip == CEE_BGT_S;
1697 if (sp->type == VAL_I32)
1698 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1699 else if (sp->type == VAL_I64)
1700 result = sp [0].data.l > sp [1].data.l;
1701 else if (sp->type == VAL_DOUBLE)
1702 result = sp [0].data.f > sp [1].data.f;
1704 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1707 ip += (signed char)*ip;
1709 ip += (gint32) read32 (ip);
1711 ip += near_jump ? 1: 4;
1714 CASE (CEE_BLT) /* Fall through */
1717 int near_jump = *ip == CEE_BLT_S;
1720 if (sp->type == VAL_I32)
1721 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1722 else if (sp->type == VAL_I64)
1723 result = sp[0].data.l < sp[1].data.l;
1724 else if (sp->type == VAL_DOUBLE)
1725 result = sp[0].data.f < sp[1].data.f;
1727 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1730 ip += 1 + (signed char)*ip;
1732 ip += 4 + (gint32) read32 (ip);
1735 ip += near_jump ? 1: 4;
1739 CASE (CEE_BLE) /* fall through */
1742 int near_jump = *ip == CEE_BLE_S;
1746 if (sp->type == VAL_I32)
1747 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1748 else if (sp->type == VAL_I64)
1749 result = sp [0].data.l <= sp [1].data.l;
1750 else if (sp->type == VAL_DOUBLE)
1751 result = sp [0].data.f <= sp [1].data.f;
1754 * FIXME: here and in other places GET_NATI on the left side
1755 * _will_ be wrong when we change the macro to work on 64 bits
1758 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1762 ip += (signed char)*ip;
1764 ip += (gint32) read32 (ip);
1766 ip += near_jump ? 1: 4;
1769 CASE (CEE_BNE_UN) /* Fall through */
1770 CASE (CEE_BNE_UN_S) {
1772 int near_jump = *ip == CEE_BNE_UN_S;
1775 if (sp->type == VAL_I32)
1776 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1777 else if (sp->type == VAL_I64)
1778 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1779 else if (sp->type == VAL_DOUBLE)
1780 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1781 (sp [0].data.f != sp [1].data.f);
1783 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1786 ip += (signed char)*ip;
1788 ip += (gint32) read32 (ip);
1790 ip += near_jump ? 1: 4;
1793 CASE (CEE_BGE_UN) /* Fall through */
1794 CASE (CEE_BGE_UN_S) {
1796 int near_jump = *ip == CEE_BGE_UN_S;
1799 if (sp->type == VAL_I32)
1800 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1801 else if (sp->type == VAL_I64)
1802 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1803 else if (sp->type == VAL_DOUBLE)
1804 result = !isless (sp [0].data.f,sp [1].data.f);
1806 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1809 ip += (signed char)*ip;
1811 ip += (gint32) read32 (ip);
1813 ip += near_jump ? 1: 4;
1816 CASE (CEE_BGT_UN) /* Fall through */
1817 CASE (CEE_BGT_UN_S) {
1819 int near_jump = *ip == CEE_BGT_UN_S;
1822 if (sp->type == VAL_I32)
1823 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1824 else if (sp->type == VAL_I64)
1825 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1826 else if (sp->type == VAL_DOUBLE)
1827 result = isgreater (sp [0].data.f, sp [1].data.f);
1829 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1832 ip += (signed char)*ip;
1834 ip += (gint32) read32 (ip);
1836 ip += near_jump ? 1: 4;
1839 CASE (CEE_BLE_UN) /* Fall through */
1840 CASE (CEE_BLE_UN_S) {
1842 int near_jump = *ip == CEE_BLE_UN_S;
1845 if (sp->type == VAL_I32)
1846 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1847 else if (sp->type == VAL_I64)
1848 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1849 else if (sp->type == VAL_DOUBLE)
1850 result = islessequal (sp [0].data.f, sp [1].data.f);
1852 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1855 ip += (signed char)*ip;
1857 ip += (gint32) read32 (ip);
1859 ip += near_jump ? 1: 4;
1862 CASE (CEE_BLT_UN) /* Fall through */
1863 CASE (CEE_BLT_UN_S) {
1865 int near_jump = *ip == CEE_BLT_UN_S;
1868 if (sp->type == VAL_I32)
1869 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1870 else if (sp->type == VAL_I64)
1871 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1872 else if (sp->type == VAL_DOUBLE)
1873 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1874 (sp [0].data.f < sp [1].data.f);
1876 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1879 ip += (signed char)*ip;
1881 ip += (gint32) read32 (ip);
1883 ip += near_jump ? 1: 4;
1888 const unsigned char *st;
1892 st = ip + sizeof (gint32) * n;
1894 if ((guint32)sp->data.i < n) {
1896 ip += sizeof (gint32) * (guint32)sp->data.i;
1897 offset = read32 (ip);
1906 sp[-1].type = VAL_I32;
1907 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1911 sp[-1].type = VAL_I32;
1912 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1916 sp[-1].type = VAL_I32;
1917 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1921 sp[-1].type = VAL_I32;
1922 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1924 CASE (CEE_LDIND_I4) /* Fall through */
1927 sp[-1].type = VAL_I32;
1928 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1932 sp[-1].type = VAL_I64;
1933 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1937 sp[-1].type = VAL_NATI;
1938 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1942 sp[-1].type = VAL_DOUBLE;
1943 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
1947 sp[-1].type = VAL_DOUBLE;
1948 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
1950 CASE (CEE_LDIND_REF)
1952 sp[-1].type = VAL_OBJ;
1953 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1954 sp[-1].data.vt.klass = NULL;
1956 CASE (CEE_STIND_REF) {
1964 CASE (CEE_STIND_I1) {
1969 *p = (gint8)sp[1].data.i;
1972 CASE (CEE_STIND_I2) {
1977 *p = (gint16)sp[1].data.i;
1980 CASE (CEE_STIND_I4) {
1988 CASE (CEE_STIND_I) {
1993 *p = (mono_i)sp[1].data.p;
1996 CASE (CEE_STIND_I8) {
2004 CASE (CEE_STIND_R4) {
2009 *p = (gfloat)sp[1].data.f;
2012 CASE (CEE_STIND_R8) {
2023 /* should probably consider the pointers as unsigned */
2024 if (sp->type == VAL_I32)
2025 sp [-1].data.i += GET_NATI (sp [0]);
2026 else if (sp->type == VAL_I64)
2027 sp [-1].data.l += sp [0].data.l;
2028 else if (sp->type == VAL_DOUBLE)
2029 sp [-1].data.f += sp [0].data.f;
2031 char *p = sp [-1].data.p;
2032 p += GET_NATI (sp [0]);
2039 /* should probably consider the pointers as unsigned */
2040 if (sp->type == VAL_I32)
2041 sp [-1].data.i -= GET_NATI (sp [0]);
2042 else if (sp->type == VAL_I64)
2043 sp [-1].data.l -= sp [0].data.l;
2044 else if (sp->type == VAL_DOUBLE)
2045 sp [-1].data.f -= sp [0].data.f;
2047 char *p = sp [-1].data.p;
2048 p -= GET_NATI (sp [0]);
2055 if (sp->type == VAL_I32)
2056 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
2057 else if (sp->type == VAL_I64)
2058 sp [-1].data.l *= sp [0].data.l;
2059 else if (sp->type == VAL_DOUBLE)
2060 sp [-1].data.f *= sp [0].data.f;
2065 if (sp->type == VAL_I32) {
2066 if (GET_NATI (sp [0]) == 0)
2067 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2068 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2069 } else if (sp->type == VAL_I64) {
2070 if (sp [0].data.l == 0)
2071 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2072 sp [-1].data.l /= sp [0].data.l;
2073 } else if (sp->type == VAL_DOUBLE) {
2074 /* set NaN is divisor is 0.0 */
2075 sp [-1].data.f /= sp [0].data.f;
2081 if (sp->type == VAL_I32) {
2083 if (GET_NATI (sp [0]) == 0)
2084 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2085 val = sp [-1].data.i;
2086 val /= (guint32)GET_NATI (sp [0]);
2087 sp [-1].data.i = val;
2088 } else if (sp->type == VAL_I64) {
2090 if (sp [0].data.l == 0)
2091 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2092 val = sp [-1].data.l;
2093 val /= (guint64)sp [0].data.l;
2094 sp [-1].data.l = val;
2095 } else if (sp->type == VAL_NATI) {
2097 if (GET_NATI (sp [0]) == 0)
2098 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2099 val = (mono_u)sp [-1].data.p;
2100 val /= (mono_u)sp [0].data.p;
2101 sp [-1].data.p = (gpointer)val;
2107 if (sp->type == VAL_I32) {
2108 if (GET_NATI (sp [0]) == 0)
2109 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2110 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2111 } else if (sp->type == VAL_I64) {
2112 if (sp [0].data.l == 0)
2113 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2114 sp [-1].data.l %= sp [0].data.l;
2115 } else if (sp->type == VAL_DOUBLE) {
2116 /* FIXME: what do we actually do here? */
2117 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2119 if (GET_NATI (sp [0]) == 0)
2120 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2121 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2127 if (sp->type == VAL_I32) {
2128 if (GET_NATI (sp [0]) == 0)
2129 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2130 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2131 } else if (sp->type == VAL_I64) {
2132 if (sp [0].data.l == 0)
2133 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2134 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2135 } else if (sp->type == VAL_DOUBLE) {
2136 /* unspecified behaviour according to the spec */
2138 if (GET_NATI (sp [0]) == 0)
2139 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2140 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2146 if (sp->type == VAL_I32)
2147 sp [-1].data.i &= GET_NATI (sp [0]);
2148 else if (sp->type == VAL_I64)
2149 sp [-1].data.l &= sp [0].data.l;
2151 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2156 if (sp->type == VAL_I32)
2157 sp [-1].data.i |= GET_NATI (sp [0]);
2158 else if (sp->type == VAL_I64)
2159 sp [-1].data.l |= sp [0].data.l;
2161 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2166 if (sp->type == VAL_I32)
2167 sp [-1].data.i ^= GET_NATI (sp [0]);
2168 else if (sp->type == VAL_I64)
2169 sp [-1].data.l ^= sp [0].data.l;
2171 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2176 if (sp [-1].type == VAL_I32)
2177 sp [-1].data.i <<= GET_NATI (sp [0]);
2178 else if (sp [-1].type == VAL_I64)
2179 sp [-1].data.l <<= GET_NATI (sp [0]);
2181 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2186 if (sp [-1].type == VAL_I32)
2187 sp [-1].data.i >>= GET_NATI (sp [0]);
2188 else if (sp [-1].type == VAL_I64)
2189 sp [-1].data.l >>= GET_NATI (sp [0]);
2191 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2196 if (sp [-1].type == VAL_I32)
2197 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2198 else if (sp [-1].type == VAL_I64)
2199 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2201 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2206 if (sp->type == VAL_I32)
2207 sp->data.i = - sp->data.i;
2208 else if (sp->type == VAL_I64)
2209 sp->data.l = - sp->data.l;
2210 else if (sp->type == VAL_DOUBLE)
2211 sp->data.f = - sp->data.f;
2212 else if (sp->type == VAL_NATI)
2213 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2219 if (sp->type == VAL_I32)
2220 sp->data.i = ~ sp->data.i;
2221 else if (sp->type == VAL_I64)
2222 sp->data.l = ~ sp->data.l;
2223 else if (sp->type == VAL_NATI)
2224 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2227 CASE (CEE_CONV_U1) /* fall through */
2228 CASE (CEE_CONV_I1) {
2230 switch (sp [-1].type) {
2232 sp [-1].data.i = (gint8)sp [-1].data.f;
2235 sp [-1].data.i = (gint8)sp [-1].data.l;
2240 sp [-1].data.i = (gint8)sp [-1].data.i;
2243 sp [-1].data.i = (gint8)sp [-1].data.nati;
2246 sp [-1].type = VAL_I32;
2249 CASE (CEE_CONV_U2) /* fall through */
2250 CASE (CEE_CONV_I2) {
2252 switch (sp [-1].type) {
2254 sp [-1].data.i = (gint16)sp [-1].data.f;
2257 sp [-1].data.i = (gint16)sp [-1].data.l;
2262 sp [-1].data.i = (gint16)sp [-1].data.i;
2265 sp [-1].data.i = (gint16)sp [-1].data.nati;
2268 sp [-1].type = VAL_I32;
2271 CASE (CEE_CONV_U4) /* Fall through */
2272 #if SIZEOF_VOID_P == 4
2273 CASE (CEE_CONV_I) /* Fall through */
2274 CASE (CEE_CONV_U) /* Fall through */
2276 CASE (CEE_CONV_I4) {
2278 switch (sp [-1].type) {
2280 sp [-1].data.i = (gint32)sp [-1].data.f;
2283 sp [-1].data.i = (gint32)sp [-1].data.l;
2290 sp [-1].data.i = (gint32)sp [-1].data.p;
2293 sp [-1].type = VAL_I32;
2296 #if SIZEOF_VOID_P == 8
2297 CASE (CEE_CONV_I) /* Fall through */
2301 switch (sp [-1].type) {
2303 sp [-1].data.l = (gint64)sp [-1].data.f;
2310 sp [-1].data.l = (gint64)sp [-1].data.i;
2313 sp [-1].data.l = (gint64)sp [-1].data.nati;
2316 sp [-1].type = VAL_I64;
2318 CASE (CEE_CONV_R4) /* Fall through */
2319 CASE (CEE_CONV_R8) {
2321 switch (sp [-1].type) {
2323 sp [-1].data.f = (double)sp [-1].data.f;
2326 sp [-1].data.f = (double)sp [-1].data.l;
2331 sp [-1].data.f = (double)sp [-1].data.i;
2334 sp [-1].data.f = (double)sp [-1].data.nati;
2337 sp [-1].type = VAL_DOUBLE;
2340 #if SIZEOF_VOID_P == 8
2341 CASE (CEE_CONV_U) /* Fall through */
2346 switch (sp [-1].type){
2348 sp [-1].data.l = (guint64)sp [-1].data.f;
2355 sp [-1].data.l = (guint64) sp [-1].data.i;
2358 sp [-1].data.l = (guint64) sp [-1].data.nati;
2361 sp [-1].type = VAL_I64;
2366 vtklass = mono_class_get (image, read32 (ip));
2369 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2378 token = read32 (ip);
2380 c = mono_class_get (image, token);
2381 addr = sp [-1].data.vt.vt;
2382 vt_alloc (&c->byval_arg, &sp [-1]);
2383 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2391 str_index = mono_metadata_token_index (read32 (ip));
2394 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2397 sp->data.vt.klass = NULL;
2404 MonoClass *newobj_class;
2405 MonoMethodSignature *csig;
2406 stackval valuetype_this;
2407 stackval *endsp = sp;
2414 token = read32 (ip);
2417 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2418 THROW_EX (mono_get_exception_missing_method (), ip -5);
2420 csig = child_frame.method->signature;
2421 newobj_class = child_frame.method->klass;
2422 /*if (profiling_classes) {
2423 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2425 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2429 if (newobj_class->parent == mono_defaults.array_class) {
2430 sp -= csig->param_count;
2431 o = ves_array_create (domain, newobj_class, csig, sp);
2432 goto array_constructed;
2436 * First arg is the object.
2438 if (newobj_class->valuetype) {
2440 vt_alloc (&newobj_class->byval_arg, &valuetype_this);
2441 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2442 zero = valuetype_this.data.vt.vt;
2443 child_frame.obj = valuetype_this.data.vt.vt;
2445 memset (&valuetype_this, 0, sizeof (stackval));
2446 zero = &valuetype_this;
2447 child_frame.obj = &valuetype_this;
2449 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero);
2451 if (newobj_class != mono_defaults.string_class) {
2452 o = mono_object_new (domain, newobj_class);
2453 child_frame.obj = o;
2455 child_frame.retval = &retval;
2459 if (csig->param_count) {
2460 sp -= csig->param_count;
2461 child_frame.stack_args = sp;
2463 child_frame.stack_args = NULL;
2466 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2468 child_frame.ex = NULL;
2469 child_frame.ex_handler = NULL;
2471 ves_exec_method (&child_frame);
2473 while (endsp > sp) {
2478 if (child_frame.ex) {
2480 * An exception occurred, need to run finally, fault and catch handlers..
2482 frame->ex = child_frame.ex;
2483 goto handle_finally;
2486 * a constructor returns void, but we need to return the object we created
2489 if (newobj_class->valuetype && !newobj_class->enumtype) {
2490 *sp = valuetype_this;
2491 } else if (newobj_class == mono_defaults.string_class) {
2496 sp->data.vt.klass = newobj_class;
2501 CASE (CEE_CASTCLASS) /* Fall through */
2505 MonoClass *c , *oclass;
2507 int do_isinst = *ip == CEE_ISINST;
2508 gboolean found = FALSE;
2511 token = read32 (ip);
2512 c = mono_class_get (image, token);
2514 g_assert (sp [-1].type == VAL_OBJ);
2516 if ((o = sp [-1].data.p)) {
2521 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2522 if ((c->interface_id <= oclass->max_interface_id) &&
2523 vt->interface_offsets [c->interface_id])
2526 if (oclass == mono_defaults.transparent_proxy_class) {
2527 /* fixme: add check for IRemotingTypeInfo */
2528 MonoRealProxy *rp = ((MonoTransparentProxy *)o)->rp;
2530 type = rp->class_to_proxy->type;
2531 oclass = mono_class_from_mono_type (type);
2533 /* handle array casts */
2534 if (oclass->rank && oclass->rank == c->rank) {
2535 if ((oclass->element_class->baseval - c->element_class->baseval) <= c->element_class->diffval) {
2536 sp [-1].data.vt.klass = c;
2539 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2540 sp [-1].data.vt.klass = c;
2547 sp [-1].data.p = NULL;
2548 sp [-1].data.vt.klass = NULL;
2550 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2556 CASE (CEE_CONV_R_UN)
2557 switch (sp [-1].type) {
2561 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2566 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2569 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2572 sp [-1].type = VAL_DOUBLE;
2575 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2582 token = read32 (ip);
2584 c = mono_class_get (image, token);
2588 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2590 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2591 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2593 sp [-1].type = VAL_MP;
2594 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2601 frame->ex_handler = NULL;
2602 THROW_EX (sp->data.p, ip);
2604 CASE (CEE_LDFLDA) /* Fall through */
2607 MonoClassField *field;
2608 guint32 token, offset;
2609 int load_addr = *ip == CEE_LDFLDA;
2611 if (!sp [-1].data.p)
2612 THROW_EX (mono_get_exception_null_reference (), ip);
2615 token = read32 (ip);
2618 if (sp [-1].type == VAL_OBJ) {
2619 obj = sp [-1].data.p;
2620 /* if we access a field from our parent and the parent was
2621 * defined in another assembly, we get a memberref.
2623 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2624 field = mono_field_from_memberref (image, token, NULL);
2626 field = mono_class_get_field (obj->vtable->klass, token);
2627 offset = field->offset;
2628 } else { /* valuetype */
2629 /*g_assert (sp [-1].type == VAL_VALUETA); */
2630 obj = sp [-1].data.vt.vt;
2631 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2632 offset = field->offset - sizeof (MonoObject);
2635 sp [-1].type = VAL_TP;
2636 sp [-1].data.p = (char*)obj + offset;
2637 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2639 vt_alloc (field->type, &sp [-1]);
2640 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2647 MonoClassField *field;
2648 guint32 token, offset;
2653 THROW_EX (mono_get_exception_null_reference (), ip);
2656 token = read32 (ip);
2659 if (sp [0].type == VAL_OBJ) {
2660 obj = sp [0].data.p;
2661 /* if we access a field from our parent and the parent was
2662 * defined in another assembly, we get a memberref.
2664 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2665 field = mono_field_from_memberref (image, token, NULL);
2667 field = mono_class_get_field (obj->vtable->klass, token);
2668 offset = field->offset;
2669 } else { /* valuetype */
2670 /*g_assert (sp->type == VAL_VALUETA); */
2671 obj = sp [0].data.vt.vt;
2672 field = mono_class_get_field (sp [0].data.vt.klass, token);
2673 offset = field->offset - sizeof (MonoObject);
2676 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2680 CASE (CEE_LDSFLD) /* Fall through */
2681 CASE (CEE_LDSFLDA) {
2684 MonoClassField *field;
2686 int load_addr = *ip == CEE_LDSFLDA;
2690 token = read32 (ip);
2693 /* need to handle fieldrefs */
2694 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2695 field = mono_field_from_memberref (image, token, &klass);
2697 klass = mono_class_get (image,
2698 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2699 field = mono_class_get_field (klass, token);
2703 vt = mono_class_vtable (domain, klass);
2704 addr = (char*)(vt->data) + field->offset;
2709 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2711 vt_alloc (field->type, sp);
2712 stackval_from_data (field->type, sp, addr);
2720 MonoClassField *field;
2725 token = read32 (ip);
2729 /* need to handle fieldrefs */
2730 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2731 field = mono_field_from_memberref (image, token, &klass);
2733 klass = mono_class_get (image,
2734 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2735 field = mono_class_get_field (klass, token);
2739 vt = mono_class_vtable (domain, klass);
2740 addr = (char*)(vt->data) + field->offset;
2742 stackval_to_data (field->type, sp, addr);
2749 vtklass = mono_class_get (image, read32 (ip));
2752 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2755 #if SIZEOF_VOID_P == 8
2756 CASE (CEE_CONV_OVF_I_UN)
2758 CASE (CEE_CONV_OVF_I8_UN) {
2759 switch (sp [-1].type) {
2761 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2762 THROW_EX (mono_get_exception_overflow (), ip);
2763 sp [-1].data.l = (guint64)sp [-1].data.f;
2766 if (sp [-1].data.l < 0)
2767 THROW_EX (mono_get_exception_overflow (), ip);
2772 /* Can't overflow */
2773 sp [-1].data.l = (guint64)sp [-1].data.i;
2776 if ((gint64)sp [-1].data.nati < 0)
2777 THROW_EX (mono_get_exception_overflow (), ip);
2778 sp [-1].data.l = (guint64)sp [-1].data.nati;
2781 sp [-1].type = VAL_I64;
2785 #if SIZEOF_VOID_P == 8
2786 CASE (CEE_CONV_OVF_U_UN)
2788 CASE (CEE_CONV_OVF_U8_UN) {
2789 switch (sp [-1].type) {
2791 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
2792 THROW_EX (mono_get_exception_overflow (), ip);
2793 sp [-1].data.l = (guint64)sp [-1].data.f;
2801 /* Can't overflow */
2802 sp [-1].data.l = (guint64)sp [-1].data.i;
2805 /* Can't overflow */
2806 sp [-1].data.l = (guint64)sp [-1].data.nati;
2809 sp [-1].type = VAL_I64;
2813 #if SIZEOF_VOID_P == 4
2814 CASE (CEE_CONV_OVF_I_UN)
2815 CASE (CEE_CONV_OVF_U_UN)
2817 CASE (CEE_CONV_OVF_I1_UN)
2818 CASE (CEE_CONV_OVF_I2_UN)
2819 CASE (CEE_CONV_OVF_I4_UN)
2820 CASE (CEE_CONV_OVF_U1_UN)
2821 CASE (CEE_CONV_OVF_U2_UN)
2822 CASE (CEE_CONV_OVF_U4_UN) {
2824 switch (sp [-1].type) {
2826 value = (guint64)sp [-1].data.f;
2829 value = (guint64)sp [-1].data.l;
2834 value = (guint64)sp [-1].data.i;
2837 value = (guint64)sp [-1].data.nati;
2841 case CEE_CONV_OVF_I1_UN:
2843 THROW_EX (mono_get_exception_overflow (), ip);
2844 sp [-1].data.i = value;
2845 sp [-1].type = VAL_I32;
2847 case CEE_CONV_OVF_I2_UN:
2849 THROW_EX (mono_get_exception_overflow (), ip);
2850 sp [-1].data.i = value;
2851 sp [-1].type = VAL_I32;
2853 #if SIZEOF_VOID_P == 4
2854 case CEE_CONV_OVF_I_UN: /* Fall through */
2856 case CEE_CONV_OVF_I4_UN:
2857 if (value > 2147483647)
2858 THROW_EX (mono_get_exception_overflow (), ip);
2859 sp [-1].data.i = value;
2860 sp [-1].type = VAL_I32;
2862 case CEE_CONV_OVF_U1_UN:
2864 THROW_EX (mono_get_exception_overflow (), ip);
2865 sp [-1].data.i = value;
2866 sp [-1].type = VAL_I32;
2868 case CEE_CONV_OVF_U2_UN:
2870 THROW_EX (mono_get_exception_overflow (), ip);
2871 sp [-1].data.i = value;
2872 sp [-1].type = VAL_I32;
2874 #if SIZEOF_VOID_P == 4
2875 case CEE_CONV_OVF_U_UN: /* Fall through */
2877 case CEE_CONV_OVF_U4_UN:
2878 if (value > 4294967295U)
2879 THROW_EX (mono_get_exception_overflow (), ip);
2880 sp [-1].data.i = value;
2881 sp [-1].type = VAL_I32;
2884 g_assert_not_reached ();
2894 token = read32 (ip);
2896 class = mono_class_get (image, token);
2897 g_assert (class != NULL);
2899 sp [-1].type = VAL_OBJ;
2900 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
2901 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
2903 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
2904 /* need to vt_free (sp); */
2916 token = read32 (ip);
2917 class = mono_class_get (image, token);
2918 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
2921 sp [-1].type = VAL_OBJ;
2923 /*if (profiling_classes) {
2924 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
2926 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
2936 g_assert (sp [-1].type == VAL_OBJ);
2940 THROW_EX (mono_get_exception_null_reference (), ip - 1);
2942 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2944 sp [-1].type = VAL_I32;
2945 sp [-1].data.i = mono_array_length (o);
2949 CASE (CEE_LDELEMA) {
2951 guint32 esize, token;
2954 token = read32 (ip);
2958 g_assert (sp [0].type == VAL_OBJ);
2961 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2963 if (sp [1].data.nati >= mono_array_length (o))
2964 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
2966 /* check the array element corresponds to token */
2967 esize = mono_array_element_size (o->obj.vtable->klass);
2970 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
2971 sp->data.vt.klass = o->obj.vtable->klass->element_class;
2976 CASE (CEE_LDELEM_I1) /* fall through */
2977 CASE (CEE_LDELEM_U1) /* fall through */
2978 CASE (CEE_LDELEM_I2) /* fall through */
2979 CASE (CEE_LDELEM_U2) /* fall through */
2980 CASE (CEE_LDELEM_I4) /* fall through */
2981 CASE (CEE_LDELEM_U4) /* fall through */
2982 CASE (CEE_LDELEM_I8) /* fall through */
2983 CASE (CEE_LDELEM_I) /* fall through */
2984 CASE (CEE_LDELEM_R4) /* fall through */
2985 CASE (CEE_LDELEM_R8) /* fall through */
2986 CASE (CEE_LDELEM_REF) {
2992 g_assert (sp [0].type == VAL_OBJ);
2995 THROW_EX (mono_get_exception_null_reference (), ip);
2997 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2999 aindex = sp [1].data.nati;
3000 if (aindex >= mono_array_length (o))
3001 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3004 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3008 sp [0].data.i = mono_array_get (o, gint8, aindex);
3009 sp [0].type = VAL_I32;
3012 sp [0].data.i = mono_array_get (o, guint8, aindex);
3013 sp [0].type = VAL_I32;
3016 sp [0].data.i = mono_array_get (o, gint16, aindex);
3017 sp [0].type = VAL_I32;
3020 sp [0].data.i = mono_array_get (o, guint16, aindex);
3021 sp [0].type = VAL_I32;
3024 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3025 sp [0].type = VAL_NATI;
3028 sp [0].data.i = mono_array_get (o, gint32, aindex);
3029 sp [0].type = VAL_I32;
3032 sp [0].data.i = mono_array_get (o, guint32, aindex);
3033 sp [0].type = VAL_I32;
3036 sp [0].data.l = mono_array_get (o, gint64, aindex);
3037 sp [0].type = VAL_I64;
3040 sp [0].data.f = mono_array_get (o, float, aindex);
3041 sp [0].type = VAL_DOUBLE;
3044 sp [0].data.f = mono_array_get (o, double, aindex);
3045 sp [0].type = VAL_DOUBLE;
3047 case CEE_LDELEM_REF:
3048 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3049 sp [0].data.vt.klass = NULL;
3050 sp [0].type = VAL_OBJ;
3060 CASE (CEE_STELEM_I) /* fall through */
3061 CASE (CEE_STELEM_I1) /* fall through */
3062 CASE (CEE_STELEM_I2) /* fall through */
3063 CASE (CEE_STELEM_I4) /* fall through */
3064 CASE (CEE_STELEM_I8) /* fall through */
3065 CASE (CEE_STELEM_R4) /* fall through */
3066 CASE (CEE_STELEM_R8) /* fall through */
3067 CASE (CEE_STELEM_REF) {
3074 g_assert (sp [0].type == VAL_OBJ);
3077 THROW_EX (mono_get_exception_null_reference (), ip);
3079 ac = o->obj.vtable->klass;
3080 g_assert (MONO_CLASS_IS_ARRAY (ac));
3082 aindex = sp [1].data.nati;
3083 if (aindex >= mono_array_length (o))
3084 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3087 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3091 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3094 mono_array_set (o, gint8, aindex, sp [2].data.i);
3097 mono_array_set (o, gint16, aindex, sp [2].data.i);
3100 mono_array_set (o, gint32, aindex, sp [2].data.i);
3103 mono_array_set (o, gint64, aindex, sp [2].data.l);
3106 mono_array_set (o, float, aindex, sp [2].data.f);
3109 mono_array_set (o, double, aindex, sp [2].data.f);
3111 case CEE_STELEM_REF:
3112 g_assert (sp [2].type == VAL_OBJ);
3113 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3137 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3138 CASE (CEE_CONV_OVF_I1)
3139 if (sp [-1].type == VAL_I32) {
3140 if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
3141 THROW_EX (mono_get_exception_overflow (), ip);
3142 sp [-1].data.i = (gint8)sp [-1].data.i;
3143 } else if (sp [-1].type == VAL_I64) {
3144 if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
3145 THROW_EX (mono_get_exception_overflow (), ip);
3146 sp [-1].data.i = (gint8)sp [-1].data.l;
3152 CASE (CEE_CONV_OVF_U1)
3153 if (sp [-1].type == VAL_I32) {
3154 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3155 THROW_EX (mono_get_exception_overflow (), ip);
3156 sp [-1].data.i = (gint8)sp [-1].data.i;
3157 } else if (sp [-1].type == VAL_I64) {
3158 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3159 THROW_EX (mono_get_exception_overflow (), ip);
3160 sp [-1].data.i = (gint8)sp [-1].data.l;
3166 CASE (CEE_CONV_OVF_I2)
3167 CASE (CEE_CONV_OVF_U2)
3169 /* FIXME: handle other cases */
3170 if (sp [-1].type == VAL_I32) {
3171 /* defined as NOP */
3176 CASE (CEE_CONV_OVF_I4)
3177 /* FIXME: handle other cases */
3178 if (sp [-1].type == VAL_I32) {
3179 /* defined as NOP */
3180 } else if(sp [-1].type == VAL_I64) {
3181 sp [-1].data.i = (gint32)sp [-1].data.l;
3182 sp [-1].type = VAL_I32;
3188 CASE (CEE_CONV_OVF_U4)
3189 /* FIXME: handle other cases */
3190 if (sp [-1].type == VAL_I32) {
3191 /* defined as NOP */
3192 } else if(sp [-1].type == VAL_I64) {
3193 sp [-1].data.i = (guint32)sp [-1].data.l;
3194 sp [-1].type = VAL_I32;
3200 CASE (CEE_CONV_OVF_I8)
3201 /* FIXME: handle other cases */
3202 if (sp [-1].type == VAL_I32) {
3203 sp [-1].data.l = (guint64)sp [-1].data.l;
3204 sp [-1].type = VAL_I64;
3205 } else if(sp [-1].type == VAL_I64) {
3206 /* defined as NOP */
3212 CASE (CEE_CONV_OVF_U8)
3213 /* FIXME: handle other cases */
3214 if (sp [-1].type == VAL_I32) {
3215 sp [-1].data.l = (guint64) sp [-1].data.i;
3216 sp [-1].type = VAL_I64;
3217 } else if(sp [-1].type == VAL_I64) {
3218 /* defined as NOP */
3230 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3231 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3233 if (!finite(sp [-1].data.f))
3234 THROW_EX (mono_get_exception_arithmetic (), ip);
3237 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3238 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3239 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3248 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3249 CASE (CEE_LDTOKEN) {
3251 MonoClass *handle_class;
3253 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3255 vt_alloc (&handle_class->byval_arg, sp);
3256 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
3260 CASE (CEE_CONV_OVF_I)
3263 /* FIXME: check overflow. */
3266 sp->data.p = (gpointer)(mono_i) sp->data.i;
3269 sp->data.p = (gpointer)(mono_i) sp->data.l;
3274 sp->data.p = (gpointer)(mono_i) sp->data.f;
3279 sp->type = VAL_NATI;
3282 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
3285 /* FIXME: check overflow */
3286 if (sp->type == VAL_I32) {
3287 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3288 THROW_EX (mono_get_exception_overflow (), ip);
3289 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3290 } else if (sp->type == VAL_I64) {
3291 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3292 THROW_EX (mono_get_exception_overflow (), ip);
3293 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3294 } else if (sp->type == VAL_DOUBLE)
3295 sp [-1].data.f += sp [0].data.f;
3297 char *p = sp [-1].data.p;
3298 p += GET_NATI (sp [0]);
3303 CASE (CEE_ADD_OVF_UN)
3305 /* FIXME: check overflow, make unsigned */
3306 if (sp->type == VAL_I32) {
3307 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3308 THROW_EX (mono_get_exception_overflow (), ip);
3309 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3310 } else if (sp->type == VAL_I64) {
3311 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3312 THROW_EX (mono_get_exception_overflow (), ip);
3313 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3314 } else if (sp->type == VAL_DOUBLE)
3315 sp [-1].data.f += sp [0].data.f;
3317 char *p = sp [-1].data.p;
3318 p += GET_NATI (sp [0]);
3326 /* FIXME: check overflow */
3327 if (sp->type == VAL_I32)
3328 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3329 else if (sp->type == VAL_I64)
3330 sp [-1].data.l *= sp [0].data.l;
3331 else if (sp->type == VAL_DOUBLE)
3332 sp [-1].data.f *= sp [0].data.f;
3334 CASE (CEE_MUL_OVF_UN)
3337 /* FIXME: check overflow, make unsigned */
3338 if (sp->type == VAL_I32)
3339 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3340 else if (sp->type == VAL_I64)
3341 sp [-1].data.l *= sp [0].data.l;
3342 else if (sp->type == VAL_DOUBLE)
3343 sp [-1].data.f *= sp [0].data.f;
3346 CASE (CEE_SUB_OVF_UN)
3349 /* FIXME: handle undeflow/unsigned */
3350 /* should probably consider the pointers as unsigned */
3351 if (sp->type == VAL_I32)
3352 sp [-1].data.i -= GET_NATI (sp [0]);
3353 else if (sp->type == VAL_I64)
3354 sp [-1].data.l -= sp [0].data.l;
3355 else if (sp->type == VAL_DOUBLE)
3356 sp [-1].data.f -= sp [0].data.f;
3358 char *p = sp [-1].data.p;
3359 p -= GET_NATI (sp [0]);
3363 CASE (CEE_ENDFINALLY)
3365 ip = finally_ips->data;
3366 finally_ips = g_slist_remove (finally_ips, ip);
3372 * There was no exception, we continue normally at the target address.
3376 CASE (CEE_LEAVE) /* Fall through */
3378 sp = frame->stack; /* empty the stack */
3380 if (*ip == CEE_LEAVE_S) {
3382 ip += (signed char) *ip;
3386 ip += (gint32) read32 (ip);
3391 * We may be either inside a try block or inside an handler.
3392 * In the first case there was no exception and we go on
3393 * executing the finally handlers and after that resume control
3395 * In the second case we need to clear the exception and
3396 * continue directly at the target ip.
3400 goto handle_finally;
3403 frame->ex_handler = NULL;
3407 frame->ex_handler = NULL;
3409 goto handle_finally;
3440 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3442 * Note: Exceptions thrown when executing a prefixed opcode need
3443 * to take into account the number of prefix bytes (usually the
3444 * throw point is just (ip - n_prefix_bytes).
3449 case CEE_ARGLIST: ves_abort(); break;
3455 if (sp->type == VAL_I32)
3456 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3457 else if (sp->type == VAL_I64)
3458 result = sp [0].data.l == sp [1].data.l;
3459 else if (sp->type == VAL_DOUBLE) {
3460 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3463 result = sp [0].data.f == sp [1].data.f;
3465 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3467 sp->data.i = result;
3477 if (sp->type == VAL_I32)
3478 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3479 else if (sp->type == VAL_I64)
3480 result = sp [0].data.l > sp [1].data.l;
3481 else if (sp->type == VAL_DOUBLE) {
3482 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3485 result = sp [0].data.f > sp [1].data.f;
3487 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3489 sp->data.i = result;
3499 if (sp->type == VAL_I32)
3500 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3501 else if (sp->type == VAL_I64)
3502 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3503 else if (sp->type == VAL_DOUBLE)
3504 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3506 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3508 sp->data.i = result;
3518 if (sp->type == VAL_I32)
3519 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3520 else if (sp->type == VAL_I64)
3521 result = sp [0].data.l < sp [1].data.l;
3522 else if (sp->type == VAL_DOUBLE) {
3523 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3526 result = sp [0].data.f < sp [1].data.f;
3528 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3530 sp->data.i = result;
3540 if (sp->type == VAL_I32)
3541 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3542 else if (sp->type == VAL_I64)
3543 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3544 else if (sp->type == VAL_DOUBLE)
3545 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3547 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3549 sp->data.i = result;
3555 case CEE_LDVIRTFTN: {
3556 int virtual = *ip == CEE_LDVIRTFTN;
3560 token = read32 (ip);
3562 m = mono_get_method (image, token, NULL);
3564 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3568 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3569 m = get_virtual_method (domain, m, sp);
3571 sp->type = VAL_NATI;
3572 sp->data.p = mono_create_method_pointer (m);
3573 sp->data.vt.klass = NULL;
3577 case CEE_UNUSED56: ves_abort(); break;
3581 arg_pos = read16 (ip);
3583 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
3584 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3596 t = ARG_TYPE (signature, anum);
3597 c = mono_class_from_mono_type (t);
3598 sp->data.vt.klass = c;
3599 sp->data.vt.vt = ARG_POS (anum);
3602 sp->type = VAL_VALUETA;
3612 arg_pos = read16 (ip);
3615 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3622 loc_pos = read16 (ip);
3624 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3625 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3635 loc_pos = read16 (ip);
3637 t = LOCAL_TYPE (header, loc_pos);
3638 c = mono_class_from_mono_type (t);
3639 sp->data.vt.vt = LOCAL_POS (loc_pos);
3640 sp->data.vt.klass = c;
3643 sp->type = VAL_VALUETA;
3653 loc_pos = read16 (ip);
3656 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3661 if (sp != frame->stack)
3662 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
3664 sp->data.p = alloca (sp->data.i);
3667 case CEE_UNUSED57: ves_abort(); break;
3668 case CEE_ENDFILTER: ves_abort(); break;
3669 case CEE_UNALIGNED_:
3671 unaligned_address = 1;
3675 volatile_address = 1;
3684 token = read32 (ip);
3687 * we ignore the value of token (I think we can as unspecified
3688 * behavior described in Partition II, 3.5).
3691 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
3692 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3695 case CEE_UNUSED68: ves_abort(); break;
3698 if (!sp [0].data.p || !sp [1].data.p)
3699 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3701 /* FIXME: value and size may be int64... */
3702 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3707 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3709 /* FIXME: value and size may be int64... */
3710 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3712 case CEE_UNUSED69: ves_abort(); break;
3715 * need to clarify what this should actually do:
3716 * start the search from the last found handler in
3717 * this method or continue in the caller or what.
3718 * Also, do we need to run finally/fault handlers after a retrow?
3719 * Well, this implementation will follow the usual search
3720 * for an handler, considering the current ip as throw spot.
3721 * We need to NULL frame->ex_handler for the later code to
3722 * actually run the new found handler.
3724 frame->ex_handler = NULL;
3725 THROW_EX (frame->ex, ip - 1);
3727 case CEE_UNUSED: ves_abort(); break;
3733 token = read32 (ip);
3735 type = mono_type_create_from_typespec (image, token);
3737 sp->data.i = mono_type_size (type, &align);
3738 mono_metadata_free_type (type);
3742 case CEE_REFANYTYPE: ves_abort(); break;
3749 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3756 g_assert_not_reached ();
3758 * Exception handling code.
3759 * The exception object is stored in frame->ex.
3766 MonoInvocation *inv;
3767 MonoMethodHeader *hd;
3768 MonoExceptionClause *clause;
3772 if (die_on_exception)
3775 for (inv = frame; inv; inv = inv->parent) {
3776 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
3778 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
3780 hd = ((MonoMethodNormal*)inv->method)->header;
3781 ip_offset = inv->ip - hd->code;
3782 for (i = 0; i < hd->num_clauses; ++i) {
3783 clause = &hd->clauses [i];
3784 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3785 if (!clause->flags) {
3786 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3788 * OK, we found an handler, now we need to execute the finally
3789 * and fault blocks before branching to the handler code.
3791 inv->ex_handler = clause;
3793 * It seems that if the catch handler is found in the same method,
3794 * it gets executed before the finally handler.
3799 goto handle_finally;
3802 /* FIXME: handle filter clauses */
3809 * If we get here, no handler was found: print a stack trace.
3812 ex_obj = (MonoObject*)frame->ex;
3813 mono_unhandled_exception (ex_obj);
3820 MonoExceptionClause *clause;
3822 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3826 ip_offset = frame->ip - header->code;
3828 for (i = 0; i < header->num_clauses; ++i) {
3829 clause = &header->clauses [i];
3830 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3831 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3832 ip = header->code + clause->handler_offset;
3833 finally_ips = g_slist_append (finally_ips, ip);
3838 ip = finally_ips->data;
3839 finally_ips = g_slist_remove (finally_ips, ip);
3844 * If an exception is set, we need to execute the fault handler, too,
3845 * otherwise, we continue normally.
3856 MonoExceptionClause *clause;
3858 ip_offset = frame->ip - header->code;
3859 for (i = 0; i < header->num_clauses; ++i) {
3860 clause = &header->clauses [i];
3861 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3862 ip = header->code + clause->handler_offset;
3867 * If the handler for the exception was found in this method, we jump
3868 * to it right away, otherwise we return and let the caller run
3869 * the finally, fault and catch blocks.
3870 * This same code should be present in the endfault opcode, but it
3871 * is corrently not assigned in the ECMA specs: LAMESPEC.
3873 if (frame->ex_handler) {
3874 ip = header->code + frame->ex_handler->handler_offset;
3877 sp->data.p = frame->ex;
3888 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3890 MonoImage *image = assembly->image;
3891 MonoCLIImageInfo *iinfo;
3893 MonoObject *exc = NULL;
3896 iinfo = image->image_info;
3897 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3899 g_error ("No entry point method found in %s", image->name);
3901 rval = mono_runtime_run_main (method, argc, argv, &exc);
3910 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3911 "Usage is: mint [options] executable args...\n", VERSION);
3913 "Valid Options are:\n"
3920 "--traceclassinit\n"
3921 "--noptr\t\t\tdon't print pointer addresses in trace output\n"
3924 "--debug method_name\n"
3926 "--opcode-count\n");
3932 test_load_class (MonoImage* image)
3934 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3938 for (i = 1; i <= t->rows; ++i) {
3939 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3940 mono_class_init (klass);
3945 static MonoException * segv_exception = NULL;
3948 segv_handler (int signum)
3950 signal (signum, segv_handler);
3951 mono_raise_exception (segv_exception);
3955 main (int argc, char *argv [])
3958 MonoAssembly *assembly;
3959 int retval = 0, i, ocount = 0;
3965 for (i = 1; i < argc && argv [i][0] == '-'; i++){
3966 if (strcmp (argv [i], "--trace") == 0)
3968 if (strcmp (argv [i], "--noptr") == 0)
3969 global_no_pointers = 1;
3970 if (strcmp (argv [i], "--traceops") == 0)
3972 if (strcmp (argv [i], "--dieonex") == 0)
3973 die_on_exception = 1;
3974 if (strcmp (argv [i], "--print-vtable") == 0)
3975 mono_print_vtable = TRUE;
3976 if (strcmp (argv [i], "--profile") == 0)
3977 mono_profiler_install_simple ();
3978 if (strcmp (argv [i], "--opcode-count") == 0)
3980 if (strcmp (argv [i], "--help") == 0)
3983 if (strcmp (argv [i], "--debug") == 0) {
3984 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
3986 g_error ("Invalid method name '%s'", argv [i]);
3987 db_methods = g_list_append (db_methods, desc);
3997 mono_set_rootdir (argv [0]);
3999 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
4000 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
4003 mono_add_internal_call ("System.Array::Set", ves_array_set);
4004 mono_add_internal_call ("System.Array::Get", ves_array_get);
4005 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
4007 frame_thread_id = TlsAlloc ();
4008 TlsSetValue (frame_thread_id, NULL);
4010 mono_install_runtime_invoke (interp_mono_runtime_invoke);
4011 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
4013 mono_install_handler (interp_ex_handler);
4015 InitializeCriticalSection (&metadata_lock);
4016 domain = mono_init (file);
4017 mono_runtime_init (domain);
4018 mono_thread_init (domain, NULL);
4019 mono_network_init ();
4021 assembly = mono_domain_assembly_open (domain, file);
4024 fprintf (stderr, "Can not open image %s\n", file);
4030 test_load_class (assembly->image);
4032 error = mono_verify_corlib ();
4034 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
4037 segv_exception = mono_get_exception_null_reference ();
4038 segv_exception->message = mono_string_new (domain, "Segmentation fault");
4039 signal (SIGSEGV, segv_handler);
4041 retval = ves_exec (domain, assembly, argc - i, argv + i);
4043 mono_profiler_shutdown ();
4045 mono_network_cleanup ();
4046 mono_thread_cleanup ();
4048 mono_domain_unload (domain, TRUE);
4052 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4053 fprintf (stderr, "fcall count: %ld\n", fcall_count);