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/cli/types.h>*/
62 #define finite _finite
65 /* If true, then we output the opcodes as we interpret them */
66 static int global_tracing = 0;
67 static int global_no_pointers = 0;
69 static int debug_indent_level = 0;
72 * Pull the list of opcodes
74 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
78 #include "mono/cil/opcode.def"
83 #define GET_NATI(sp) ((sp).data.nati)
84 #define CSIZE(x) (sizeof (x) / 4)
86 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
88 (frame)->parent = (parent_frame); \
89 (frame)->obj = (obj_this); \
90 (frame)->stack_args = (method_args); \
91 (frame)->retval = (method_retval); \
92 (frame)->method = (mono_method); \
93 (frame)->ex_handler = NULL; \
95 (frame)->child = NULL; \
98 void ves_exec_method (MonoInvocation *frame);
100 typedef void (*ICallMethod) (MonoInvocation *frame);
102 static guint32 die_on_exception = 0;
103 static guint32 frame_thread_id = 0;
105 #define DEBUG_INTERP 1
108 static unsigned long opcode_count = 0;
109 static unsigned long fcall_count = 0;
110 static int break_on_method = 0;
111 static GList *db_methods = NULL;
118 for (h = 0; h < debug_indent_level; h++)
123 db_match_method (gpointer data, gpointer user_data)
125 MonoMethod *m = (MonoMethod*)user_data;
126 MonoMethodDesc *desc = data;
128 if (mono_method_desc_full_match (desc, m))
132 #define DEBUG_ENTER() \
134 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
135 if (break_on_method) tracing=2; \
136 break_on_method = 0; \
138 MonoClass *klass = frame->method->klass; \
139 char *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
140 debug_indent_level++; \
142 g_print ("(%d) Entering %s.%s::%s (", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
143 if (signature->hasthis) { \
144 if (global_no_pointers) { \
145 g_print ("this%s ", frame->obj ? "" : "=null"); \
147 g_print ("%p ", frame->obj); } \
149 g_print ("%s)\n", args); \
152 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
153 mono_profiler_method_enter (frame->method);
155 #define DEBUG_LEAVE() \
157 MonoClass *klass = frame->method->klass; \
159 if (signature->ret->type != MONO_TYPE_VOID) \
160 args = dump_stack (frame->retval, frame->retval + 1); \
162 args = g_strdup (""); \
164 g_print ("(%d) Leaving %s.%s::%s", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
165 g_print (" => %s\n", args); \
167 debug_indent_level--; \
169 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
170 mono_profiler_method_leave (frame->method);
174 #define DEBUG_ENTER()
175 #define DEBUG_LEAVE()
180 interp_ex_handler (MonoException *ex) {
181 MonoInvocation *frame = TlsGetValue (frame_thread_id);
183 longjmp (*(jmp_buf*)frame->locals, 1);
187 ves_real_abort (int line, MonoMethod *mh,
188 const unsigned char *ip, stackval *stack, stackval *sp)
190 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
191 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
192 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
193 ip-mm->header->code);
194 g_print ("0x%04x %02x\n",
195 ip-mm->header->code, *ip);
197 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
199 #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);
202 interp_create_remoting_trampoline (MonoMethod *method)
208 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
214 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
218 klass = obj->vtable->klass;
219 vtable = (MonoMethod **)obj->vtable->vtable;
221 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
222 return *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
225 g_assert (vtable [m->slot]);
227 return vtable [m->slot];
231 stackval_from_data (MonoType *type, stackval *result, char *data)
234 switch (type->type) {
235 case MONO_TYPE_OBJECT:
236 case MONO_TYPE_CLASS:
237 case MONO_TYPE_STRING:
238 case MONO_TYPE_ARRAY:
239 case MONO_TYPE_SZARRAY:
240 result->type = VAL_OBJ;
243 result->type = VAL_VALUETA;
246 result->data.p = *(gpointer*)data;
247 result->data.vt.klass = mono_class_from_mono_type (type);
250 switch (type->type) {
254 result->type = VAL_I32;
255 result->data.i = *(gint8*)data;
258 case MONO_TYPE_BOOLEAN:
259 result->type = VAL_I32;
260 result->data.i = *(guint8*)data;
263 result->type = VAL_I32;
264 result->data.i = *(gint16*)data;
268 result->type = VAL_I32;
269 result->data.i = *(guint16*)data;
272 result->type = VAL_I32;
273 result->data.i = *(gint32*)data;
278 result->type = VAL_TP;
279 result->data.p = *(gpointer*)data;
282 result->type = VAL_I32;
283 result->data.i = *(guint32*)data;
286 result->type = VAL_DOUBLE;
287 result->data.f = *(float*)data;
291 result->type = VAL_I64;
292 result->data.l = *(gint64*)data;
295 result->type = VAL_DOUBLE;
296 result->data.f = *(double*)data;
298 case MONO_TYPE_STRING:
299 case MONO_TYPE_SZARRAY:
300 case MONO_TYPE_CLASS:
301 case MONO_TYPE_OBJECT:
302 case MONO_TYPE_ARRAY:
303 result->type = VAL_OBJ;
304 result->data.p = *(gpointer*)data;
305 result->data.vt.klass = mono_class_from_mono_type (type);
307 case MONO_TYPE_VALUETYPE:
308 if (type->data.klass->enumtype) {
309 return stackval_from_data (type->data.klass->enum_basetype, result, data);
311 result->type = VAL_VALUET;
312 result->data.vt.klass = type->data.klass;
313 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
317 g_warning ("got type 0x%02x", type->type);
318 g_assert_not_reached ();
323 stackval_to_data (MonoType *type, stackval *val, char *data)
326 gpointer *p = (gpointer*)data;
330 switch (type->type) {
333 guint8 *p = (guint8*)data;
337 case MONO_TYPE_BOOLEAN: {
338 guint8 *p = (guint8*)data;
339 *p = (val->data.i != 0);
344 case MONO_TYPE_CHAR: {
345 guint16 *p = (guint16*)data;
349 #if SIZEOF_VOID_P == 4
355 gint32 *p = (gint32*)data;
359 #if SIZEOF_VOID_P == 8
365 gint64 *p = (gint64*)data;
370 float *p = (float*)data;
375 double *p = (double*)data;
379 case MONO_TYPE_STRING:
380 case MONO_TYPE_SZARRAY:
381 case MONO_TYPE_CLASS:
382 case MONO_TYPE_OBJECT:
383 case MONO_TYPE_ARRAY:
384 case MONO_TYPE_PTR: {
385 gpointer *p = (gpointer*)data;
389 case MONO_TYPE_VALUETYPE:
390 if (type->data.klass->enumtype) {
391 return stackval_to_data (type->data.klass->enum_basetype, val, data);
393 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
397 g_warning ("got type %x", type->type);
398 g_assert_not_reached ();
403 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
406 guint32 *lower_bounds;
409 lengths = alloca (sizeof (guint32) * klass->rank * 2);
410 for (i = 0; i < sig->param_count; ++i) {
411 lengths [i] = values->data.i;
414 if (klass->rank == sig->param_count) {
415 /* Only lengths provided. */
418 /* lower bounds are first. */
419 lower_bounds = lengths;
420 lengths += klass->rank;
422 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
426 ves_array_set (MonoInvocation *frame)
428 stackval *sp = frame->stack_args;
432 gint32 i, t, pos, esize;
438 ac = o->vtable->klass;
440 g_assert (ac->rank >= 1);
443 if (ao->bounds != NULL) {
444 pos -= ao->bounds [0].lower_bound;
445 for (i = 1; i < ac->rank; i++) {
446 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
447 ao->bounds [i].length) {
448 g_warning ("wrong array index");
449 g_assert_not_reached ();
451 pos = pos*ao->bounds [i].length + sp [i].data.i -
452 ao->bounds [i].lower_bound;
456 esize = mono_array_element_size (ac);
457 ea = mono_array_addr_with_size (ao, esize, pos);
459 mt = frame->method->signature->params [ac->rank];
460 stackval_to_data (mt, &sp [ac->rank], ea);
464 ves_array_get (MonoInvocation *frame)
466 stackval *sp = frame->stack_args;
470 gint32 i, pos, esize;
476 ac = o->vtable->klass;
478 g_assert (ac->rank >= 1);
481 if (ao->bounds != NULL) {
482 pos -= ao->bounds [0].lower_bound;
483 for (i = 1; i < ac->rank; i++)
484 pos = pos*ao->bounds [i].length + sp [i].data.i -
485 ao->bounds [i].lower_bound;
488 esize = mono_array_element_size (ac);
489 ea = mono_array_addr_with_size (ao, esize, pos);
491 mt = frame->method->signature->ret;
492 stackval_from_data (mt, frame->retval, ea);
496 ves_array_element_address (MonoInvocation *frame)
498 stackval *sp = frame->stack_args;
502 gint32 i, pos, esize;
507 ac = o->vtable->klass;
509 g_assert (ac->rank >= 1);
512 if (ao->bounds != NULL) {
513 pos -= ao->bounds [0].lower_bound;
514 for (i = 1; i < ac->rank; i++)
515 pos = pos*ao->bounds [i].length + sp [i].data.i -
516 ao->bounds [i].lower_bound;
519 esize = mono_array_element_size (ac);
520 ea = mono_array_addr_with_size (ao, esize, pos);
522 frame->retval->type = VAL_TP;
523 frame->retval->data.p = ea;
527 ves_pinvoke_method (MonoInvocation *frame)
533 TlsSetValue (frame_thread_id, frame->args);
536 if (!frame->method->info)
537 frame->method->info = mono_create_trampoline (frame->method, 0);
538 func = (MonoPIFunc)frame->method->info;
541 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
542 * locals will point to the jmp_buf, while args will point to the previous
543 * MonoInvocation frame: this is needed to make exception searching work across
544 * managed/unmanaged boundaries.
546 frame->locals = (char*)&env;
547 frame->args = (char*)TlsGetValue (frame_thread_id);
548 TlsSetValue (frame_thread_id, frame);
550 func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
551 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
552 TlsSetValue (frame_thread_id, frame->args);
557 * runtime specifies that the implementation of the method is automatically
558 * provided by the runtime and is primarily used for the methods of delegates.
561 ves_runtime_method (MonoInvocation *frame)
563 const char *name = frame->method->name;
564 MonoObject *obj = (MonoObject*)frame->obj;
565 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
568 mono_class_init (mono_defaults.multicastdelegate_class);
570 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
571 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
572 delegate->delegate.target = frame->stack_args[0].data.p;
573 delegate->delegate.method_ptr = frame->stack_args[1].data.p;
574 delegate->delegate.method_info = mono_method_get_object (mono_object_domain(delegate), mono_method_pointer_get (delegate->delegate.method_ptr));
577 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
578 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
584 code = (guchar*)delegate->delegate.method_ptr;
585 method = mono_method_pointer_get (code);
587 /* FIXME: check for NULL method */
588 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
589 ves_exec_method (&call);
592 method->addr = mono_create_trampoline (method, 1);
594 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
595 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, delegate->target, frame->stack_args);
596 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
598 delegate = delegate->prev;
602 g_error ("Don't know how to exec runtime method %s.%s::%s",
603 frame->method->klass->name_space, frame->method->klass->name,
604 frame->method->name);
608 dump_stack (stackval *stack, stackval *sp)
611 GString *str = g_string_new ("");
614 return g_string_free (str, FALSE);
618 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
619 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
620 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
622 if (!global_no_pointers)
623 g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
625 g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
629 MonoObject *obj = s->data.p;
630 if (obj && obj->klass == mono_defaults.string_class) {
631 char *str = mono_string_to_utf8 ((MonoString*)obj);
632 printf ("\"%s\" ", str);
639 if (!global_no_pointers)
640 g_string_sprintfa (str, "[%p] ", s->data.p);
642 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
647 return g_string_free (str, FALSE);
651 dump_frame (MonoInvocation *inv)
653 GString *str = g_string_new ("");
656 for (i = 0; inv; inv = inv->parent, ++i) {
657 MonoClass *k = inv->method->klass;
660 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
661 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
665 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
667 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
670 opname = mono_opcode_names [codep];
671 codep = inv->ip - hd->code;
673 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
674 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
675 k->name_space, k->name, inv->method->name, args);
678 return g_string_free (str, FALSE);
681 static CRITICAL_SECTION metadata_lock;
684 INLINE_STRING_LENGTH = 1,
687 INLINE_TYPE_ELEMENT_TYPE
691 calc_offsets (MonoImage *image, MonoMethod *method)
693 int i, align, size, offset = 0;
694 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
695 MonoMethodSignature *signature = method->signature;
696 int hasthis = signature->hasthis;
697 register const unsigned char *ip, *end;
698 const MonoOpcode *opcode;
702 MonoDomain *domain = mono_domain_get ();
705 mono_profiler_method_jit (method); /* sort of... */
706 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
707 for (i = 0; i < header->num_locals; ++i) {
708 size = mono_type_size (header->locals [i], &align);
710 offset &= ~(align - 1);
711 offsets [2 + i] = offset;
714 offsets [0] = offset;
717 offset += sizeof (gpointer) - 1;
718 offset &= ~(sizeof (gpointer) - 1);
719 offsets [2 + header->num_locals] = offset;
720 offset += sizeof (gpointer);
722 for (i = 0; i < signature->param_count; ++i) {
723 size = mono_type_size (signature->params [i], &align);
725 offset &= ~(align - 1);
726 offsets [2 + hasthis + header->num_locals + i] = offset;
729 offsets [1] = offset;
731 EnterCriticalSection (&metadata_lock);
732 /* intern the strings in the method. */
734 end = ip + header->code_size;
741 opcode = &mono_opcodes [i];
742 switch (opcode->argument) {
746 case MonoInlineString:
747 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
751 class = mono_class_get (image, read32 (ip + 1));
752 mono_class_init (class);
753 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
754 mono_class_vtable (domain, class);
757 case MonoInlineField:
758 token = read32 (ip + 1);
759 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
760 mono_field_from_memberref (image, token, &class);
762 class = mono_class_get (image,
763 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
765 mono_class_init (class);
766 mono_class_vtable (domain, class);
769 case MonoInlineMethod:
770 m = mono_get_method (image, read32 (ip + 1), NULL);
771 mono_class_init (m->klass);
772 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
773 mono_class_vtable (domain, m->klass);
778 case MonoShortInlineR:
780 case MonoInlineBrTarget:
786 case MonoShortInlineVar:
787 case MonoShortInlineI:
788 case MonoShortInlineBrTarget:
791 case MonoInlineSwitch: {
804 g_assert_not_reached ();
808 method->info = offsets;
811 * We store the inline info in addr, since it's unused for IL methods.
813 if (method->klass == mono_defaults.string_class) {
814 if (strcmp (method->name, "get_Length") == 0)
815 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
816 } else if (method->klass == mono_defaults.array_class) {
817 if (strcmp (method->name, "get_Length") == 0)
818 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
819 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
820 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
821 } else if (method->klass == mono_defaults.monotype_class) {
822 if (strcmp (method->name, "GetElementType") == 0)
823 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
825 LeaveCriticalSection (&metadata_lock);
826 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
829 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
830 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
832 #define ARG_POS(n) (args_pointers [(n)])
833 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
834 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
836 #define THROW_EX(exception,ex_ip) \
839 frame->ip = (ex_ip); \
840 stack_trace = dump_frame (frame); \
841 frame->ex = (MonoException*)(exception); \
842 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
843 g_free (stack_trace); \
844 goto handle_exception; \
847 typedef struct _vtallocation vtallocation;
849 struct _vtallocation {
852 char data [MONO_ZERO_LEN_ARRAY];
856 * we don't use vtallocation->next, yet
858 #define vt_alloc(vtype,sp) \
859 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
860 if (!(vtype)->byref) { \
862 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
863 if (!vtalloc || vtalloc->size <= size) { \
864 vtalloc = alloca (sizeof (vtallocation) + size); \
865 vtalloc->size = size; \
866 g_assert (size < 10000); \
868 (sp)->data.vt.vt = vtalloc->data; \
871 (sp)->data.vt.klass = (vtype)->data.klass; \
875 #define vt_free(sp) \
877 if ((sp)->type == VAL_VALUET) { \
878 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
883 verify_method (MonoMethod *m)
885 GSList *errors, *tmp;
886 MonoVerifyInfo *info;
888 errors = mono_method_verify (m, MONO_VERIFY_ALL);
890 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
891 for (tmp = errors; tmp; tmp = tmp->next) {
893 g_print ("%s\n", info->message);
897 mono_free_verify_list (errors);
900 #define MYGUINT64_MAX 18446744073709551615UL
901 #define MYGINT64_MAX 9223372036854775807LL
902 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
904 #define MYGUINT32_MAX 4294967295U
905 #define MYGINT32_MAX 2147483647
906 #define MYGINT32_MIN (-MYGINT32_MAX -1)
908 #define CHECK_ADD_OVERFLOW(a,b) \
909 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
910 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
912 #define CHECK_ADD_OVERFLOW_UN(a,b) \
913 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
915 #define CHECK_ADD_OVERFLOW64(a,b) \
916 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
917 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
919 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
920 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
923 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
926 MonoInvocation frame;
927 MonoObject *retval = NULL;
928 MonoMethodSignature *sig = method->signature;
929 MonoClass *klass = mono_class_from_mono_type (sig->ret);
930 int i, type, isobject = 0;
933 stackval *args = alloca (sizeof (stackval) * sig->param_count);
935 /* FIXME: Set frame for execption handling. */
937 switch (sig->ret->type) {
940 case MONO_TYPE_STRING:
941 case MONO_TYPE_OBJECT:
942 case MONO_TYPE_CLASS:
943 case MONO_TYPE_ARRAY:
944 case MONO_TYPE_SZARRAY:
947 case MONO_TYPE_VALUETYPE:
948 retval = mono_object_new (mono_domain_get (), klass);
949 ret = ((char*)retval) + sizeof (MonoObject);
950 if (!sig->ret->data.klass->enumtype)
951 result.data.vt.vt = ret;
954 retval = mono_object_new (mono_domain_get (), klass);
955 ret = ((char*)retval) + sizeof (MonoObject);
959 for (i = 0; i < sig->param_count; ++i) {
960 if (sig->params [i]->byref) {
961 args [i].type = VAL_POINTER;
962 args [i].data.p = params [i];
965 type = sig->params [i]->type;
970 case MONO_TYPE_BOOLEAN:
971 args [i].type = VAL_I32;
972 args [i].data.i = *(MonoBoolean*)params [i];
973 args [i].data.vt.klass = NULL;
978 args [i].type = VAL_I32;
979 args [i].data.i = *(gint16*)params [i];
980 args [i].data.vt.klass = NULL;
982 #if SIZEOF_VOID_P == 4
983 case MONO_TYPE_U: /* use VAL_POINTER? */
988 args [i].type = VAL_I32;
989 args [i].data.i = *(gint32*)params [i];
990 args [i].data.vt.klass = NULL;
992 #if SIZEOF_VOID_P == 8
998 args [i].type = VAL_I64;
999 args [i].data.l = *(gint64*)params [i];
1000 args [i].data.vt.klass = NULL;
1002 case MONO_TYPE_VALUETYPE:
1003 if (sig->params [i]->data.klass->enumtype) {
1004 type = sig->params [i]->data.klass->enum_basetype->type;
1007 g_warning ("generic valutype %s not handled in runtime invoke", sig->params [i]->data.klass->name);
1010 case MONO_TYPE_STRING:
1011 case MONO_TYPE_CLASS:
1012 case MONO_TYPE_ARRAY:
1013 case MONO_TYPE_SZARRAY:
1014 case MONO_TYPE_OBJECT:
1015 args [i].type = VAL_OBJ;
1016 args [i].data.p = params [i];
1017 args [i].data.vt.klass = NULL;
1020 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1024 INIT_FRAME(&frame,NULL,obj,args,&result,method);
1025 ves_exec_method (&frame);
1026 if (sig->ret->type == MONO_TYPE_VOID)
1029 return result.data.p;
1030 stackval_to_data (sig->ret, &result, ret);
1035 * Need to optimize ALU ops when natural int == int32
1037 * IDEA: if we maintain a stack of ip, sp to be checked
1038 * in the return opcode, we could inline simple methods that don't
1039 * use the stack or local variables....
1041 * The {,.S} versions of many opcodes can/should be merged to reduce code
1046 ves_exec_method (MonoInvocation *frame)
1048 MonoDomain *domain = mono_domain_get ();
1049 MonoInvocation child_frame;
1050 MonoMethodHeader *header;
1051 MonoMethodSignature *signature;
1053 GSList *finally_ips = NULL;
1054 const unsigned char *endfinally_ip;
1055 register const unsigned char *ip;
1056 register stackval *sp;
1057 void **args_pointers;
1059 gint il_ins_count = -1;
1060 gint tracing = global_tracing;
1061 unsigned char tail_recursion = 0;
1062 unsigned char unaligned_address = 0;
1063 unsigned char volatile_address = 0;
1064 vtallocation *vtalloc = NULL;
1067 signature = frame->method->signature;
1071 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1072 if (!frame->method->addr) {
1073 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1077 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1078 ves_pinvoke_method (frame);
1080 ICallMethod icall = (ICallMethod)frame->method->addr;
1084 goto handle_exception;
1089 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1090 if (!frame->method->addr) {
1091 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1095 ves_pinvoke_method (frame);
1097 goto handle_exception;
1102 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1103 ves_runtime_method (frame);
1105 goto handle_exception;
1110 /*verify_method (frame->method);*/
1112 header = ((MonoMethodNormal *)frame->method)->header;
1113 image = frame->method->klass->image;
1115 if (!frame->method->info)
1116 calc_offsets (image, frame->method);
1117 offsets = frame->method->info;
1120 * with alloca we get the expected huge performance gain
1121 * stackval *stack = g_new0(stackval, header->max_stack);
1123 g_assert (header->max_stack < 10000);
1124 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1126 if (header->num_locals) {
1127 g_assert (offsets [0] < 10000);
1128 frame->locals = alloca (offsets [0]);
1130 * yes, we do it unconditionally, because it needs to be done for
1131 * some cases anyway and checking for that would be even slower.
1133 memset (frame->locals, 0, offsets [0]);
1136 * Copy args from stack_args to args.
1138 if (signature->param_count || signature->hasthis) {
1140 int has_this = signature->hasthis;
1142 g_assert (offsets [1] < 10000);
1143 frame->args = alloca (offsets [1]);
1144 g_assert ((signature->param_count + has_this) < 1000);
1145 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1148 this_arg = args_pointers [0] = frame->args;
1149 *this_arg = frame->obj;
1151 for (i = 0; i < signature->param_count; ++i) {
1152 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1153 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this]);
1157 child_frame.parent = frame;
1158 frame->child = &child_frame;
1165 * using while (ip < end) may result in a 15% performance drop,
1166 * but it may be useful for debug
1170 /*g_assert (sp >= stack);*/
1175 if (sp > frame->stack) {
1177 ins = dump_stack (frame->stack, sp);
1178 g_print ("(%d) stack: %s\n", GetCurrentThreadId(), ins);
1182 ins = mono_disasm_code_one (NULL, frame->method, ip);
1183 g_print ("(%d) %s", GetCurrentThreadId(), ins);
1186 if (il_ins_count > 0)
1187 if (!(--il_ins_count))
1197 G_BREAKPOINT (); /* this is not portable... */
1202 CASE (CEE_LDARG_3) {
1203 int n = (*ip)-CEE_LDARG_0;
1205 vt_alloc (ARG_TYPE (signature, n), sp);
1206 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
1213 CASE (CEE_LDLOC_3) {
1214 int n = (*ip)-CEE_LDLOC_0;
1216 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1218 sp->data.i = *(gint32*) LOCAL_POS (n);
1222 vt_alloc (LOCAL_TYPE (header, n), sp);
1223 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1231 CASE (CEE_STLOC_3) {
1232 int n = (*ip)-CEE_STLOC_0;
1235 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1236 gint32 *p = (gint32*)LOCAL_POS (n);
1240 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1247 vt_alloc (ARG_TYPE (signature, *ip), sp);
1248 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1252 CASE (CEE_LDARGA_S) {
1257 t = ARG_TYPE (signature, *ip);
1258 c = mono_class_from_mono_type (t);
1259 sp->data.vt.klass = c;
1260 sp->data.vt.vt = ARG_POS (*ip);
1263 sp->type = VAL_VALUETA;
1274 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1280 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1281 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1285 CASE (CEE_LDLOCA_S) {
1290 t = LOCAL_TYPE (header, *ip);
1291 c = mono_class_from_mono_type (t);
1292 sp->data.vt.klass = c;
1293 sp->data.p = LOCAL_POS (*ip);
1296 sp->type = VAL_VALUETA;
1307 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1315 sp->data.vt.klass = NULL;
1318 CASE (CEE_LDC_I4_M1)
1334 sp->data.i = (*ip) - CEE_LDC_I4_0;
1341 sp->data.i = *(const gint8 *)ip;
1348 sp->data.i = read32 (ip);
1355 sp->data.l = read64 (ip);
1362 sp->type = VAL_DOUBLE;
1371 sp->type = VAL_DOUBLE;
1372 readr8(ip, &sp->data.f);
1376 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1378 if (sp [-1].type == VAL_VALUET) {
1379 MonoClass *c = sp [-1].data.vt.klass;
1380 vt_alloc (&c->byval_arg, sp);
1381 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1393 CASE (CEE_JMP) ves_abort(); BREAK;
1394 CASE (CEE_CALLVIRT) /* Fall through */
1395 CASE (CEE_CALLI) /* Fall through */
1397 MonoMethodSignature *csignature;
1399 stackval *endsp = sp;
1401 int virtual = *ip == CEE_CALLVIRT;
1402 int calli = *ip == CEE_CALLI;
1405 * We ignore tail recursion for now.
1412 token = read32 (ip);
1415 unsigned char *code;
1418 child_frame.method = mono_method_pointer_get (code);
1419 /* check for NULL with native code */
1420 csignature = child_frame.method->signature;
1422 child_frame.method = mono_get_method (image, token, NULL);
1423 if (!child_frame.method)
1424 THROW_EX (mono_get_exception_missing_method (), ip -5);
1425 csignature = child_frame.method->signature;
1427 stackval *this_arg = &sp [-csignature->param_count-1];
1428 if (!this_arg->data.p)
1429 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1430 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1431 if (!child_frame.method)
1432 THROW_EX (mono_get_exception_missing_method (), ip -5);
1435 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1436 /* decrement by the actual number of args */
1437 if (csignature->param_count) {
1438 sp -= csignature->param_count;
1439 child_frame.stack_args = sp;
1441 child_frame.stack_args = NULL;
1443 if (csignature->hasthis) {
1444 g_assert (sp >= frame->stack);
1447 * It may also be a TP from LD(S)FLDA
1448 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1450 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1451 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1453 child_frame.obj = sp->data.p;
1455 child_frame.obj = NULL;
1457 if (csignature->ret->type != MONO_TYPE_VOID) {
1458 vt_alloc (csignature->ret, &retval);
1459 child_frame.retval = &retval;
1461 child_frame.retval = NULL;
1464 child_frame.ex = NULL;
1465 child_frame.ex_handler = NULL;
1467 if (csignature->hasthis && sp->type == VAL_OBJ &&
1468 ((MonoObject *)sp->data.p)->vtable->klass ==
1469 mono_defaults.transparent_proxy_class) {
1470 /* implement remoting */
1471 g_assert_not_reached ();
1473 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1474 case INLINE_STRING_LENGTH:
1475 retval.type = VAL_I32;
1476 retval.data.i = ((MonoString*)sp->data.p)->length;
1477 //g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);
1479 case INLINE_ARRAY_LENGTH:
1480 retval.type = VAL_I32;
1481 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1483 case INLINE_ARRAY_RANK:
1484 retval.type = VAL_I32;
1485 retval.data.i = mono_object_class (sp->data.p)->rank;
1487 case INLINE_TYPE_ELEMENT_TYPE:
1488 retval.type = VAL_OBJ;
1490 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1491 retval.data.vt.klass = NULL;
1492 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1493 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1494 else if (c->element_class)
1495 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1497 retval.data.p = NULL;
1501 ves_exec_method (&child_frame);
1505 while (endsp > sp) {
1510 if (child_frame.ex) {
1512 * An exception occurred, need to run finally, fault and catch handlers..
1514 frame->ex = child_frame.ex;
1515 goto handle_finally;
1518 /* need to handle typedbyref ... */
1519 if (csignature->ret->type != MONO_TYPE_VOID) {
1526 if (signature->ret->type != MONO_TYPE_VOID) {
1528 if (sp->type == VAL_VALUET) {
1529 /* the caller has already allocated the memory */
1530 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1533 *frame->retval = *sp;
1536 if (sp > frame->stack)
1537 g_warning ("more values on stack: %d", sp-frame->stack);
1541 CASE (CEE_BR_S) /* Fall through */
1543 if (*ip == CEE_BR) {
1545 ip += (gint32) read32(ip);
1549 ip += (signed char) *ip;
1553 CASE (CEE_BRFALSE) /* Fall through */
1554 CASE (CEE_BRFALSE_S) {
1556 int near_jump = *ip == CEE_BRFALSE_S;
1560 case VAL_I32: result = sp->data.i == 0; break;
1561 case VAL_I64: result = sp->data.l == 0; break;
1562 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1563 default: result = sp->data.p == NULL; break;
1567 ip += (signed char)*ip;
1569 ip += (gint32) read32 (ip);
1571 ip += near_jump ? 1: 4;
1574 CASE (CEE_BRTRUE) /* Fall through */
1575 CASE (CEE_BRTRUE_S) {
1577 int near_jump = *ip == CEE_BRTRUE_S;
1581 case VAL_I32: result = sp->data.i != 0; break;
1582 case VAL_I64: result = sp->data.l != 0; break;
1583 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1584 default: result = sp->data.p != NULL; break;
1588 ip += (signed char)*ip;
1590 ip += (gint32) read32 (ip);
1592 ip += near_jump ? 1: 4;
1595 CASE (CEE_BEQ) /* Fall through */
1598 int near_jump = *ip == CEE_BEQ_S;
1601 if (sp->type == VAL_I32)
1602 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1603 else if (sp->type == VAL_I64)
1604 result = sp [0].data.l == sp [1].data.l;
1605 else if (sp->type == VAL_DOUBLE)
1606 result = sp [0].data.f == sp [1].data.f;
1608 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1611 ip += (signed char)*ip;
1613 ip += (gint32) read32 (ip);
1615 ip += near_jump ? 1: 4;
1618 CASE (CEE_BGE) /* Fall through */
1621 int near_jump = *ip == CEE_BGE_S;
1624 if (sp->type == VAL_I32)
1625 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1626 else if (sp->type == VAL_I64)
1627 result = sp [0].data.l >= sp [1].data.l;
1628 else if (sp->type == VAL_DOUBLE)
1629 result = sp [0].data.f >= sp [1].data.f;
1631 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1634 ip += (signed char)*ip;
1636 ip += (gint32) read32 (ip);
1638 ip += near_jump ? 1: 4;
1641 CASE (CEE_BGT) /* Fall through */
1644 int near_jump = *ip == CEE_BGT_S;
1647 if (sp->type == VAL_I32)
1648 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1649 else if (sp->type == VAL_I64)
1650 result = sp [0].data.l > sp [1].data.l;
1651 else if (sp->type == VAL_DOUBLE)
1652 result = sp [0].data.f > sp [1].data.f;
1654 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1657 ip += (signed char)*ip;
1659 ip += (gint32) read32 (ip);
1661 ip += near_jump ? 1: 4;
1664 CASE (CEE_BLT) /* Fall through */
1667 int near_jump = *ip == CEE_BLT_S;
1670 if (sp->type == VAL_I32)
1671 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1672 else if (sp->type == VAL_I64)
1673 result = sp[0].data.l < sp[1].data.l;
1674 else if (sp->type == VAL_DOUBLE)
1675 result = sp[0].data.f < sp[1].data.f;
1677 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1680 ip += 1 + (signed char)*ip;
1682 ip += 4 + (gint32) read32 (ip);
1685 ip += near_jump ? 1: 4;
1689 CASE (CEE_BLE) /* fall through */
1692 int near_jump = *ip == CEE_BLE_S;
1696 if (sp->type == VAL_I32)
1697 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1698 else if (sp->type == VAL_I64)
1699 result = sp [0].data.l <= sp [1].data.l;
1700 else if (sp->type == VAL_DOUBLE)
1701 result = sp [0].data.f <= sp [1].data.f;
1704 * FIXME: here and in other places GET_NATI on the left side
1705 * _will_ be wrong when we change the macro to work on 64 bits
1708 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1712 ip += (signed char)*ip;
1714 ip += (gint32) read32 (ip);
1716 ip += near_jump ? 1: 4;
1719 CASE (CEE_BNE_UN) /* Fall through */
1720 CASE (CEE_BNE_UN_S) {
1722 int near_jump = *ip == CEE_BNE_UN_S;
1725 if (sp->type == VAL_I32)
1726 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1727 else if (sp->type == VAL_I64)
1728 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1729 else if (sp->type == VAL_DOUBLE)
1730 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1731 (sp [0].data.f != sp [1].data.f);
1733 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1736 ip += (signed char)*ip;
1738 ip += (gint32) read32 (ip);
1740 ip += near_jump ? 1: 4;
1743 CASE (CEE_BGE_UN) /* Fall through */
1744 CASE (CEE_BGE_UN_S) {
1746 int near_jump = *ip == CEE_BGE_UN_S;
1749 if (sp->type == VAL_I32)
1750 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1751 else if (sp->type == VAL_I64)
1752 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1753 else if (sp->type == VAL_DOUBLE)
1754 result = !isless (sp [0].data.f,sp [1].data.f);
1756 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1759 ip += (signed char)*ip;
1761 ip += (gint32) read32 (ip);
1763 ip += near_jump ? 1: 4;
1766 CASE (CEE_BGT_UN) /* Fall through */
1767 CASE (CEE_BGT_UN_S) {
1769 int near_jump = *ip == CEE_BGT_UN_S;
1772 if (sp->type == VAL_I32)
1773 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1774 else if (sp->type == VAL_I64)
1775 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1776 else if (sp->type == VAL_DOUBLE)
1777 result = isgreater (sp [0].data.f, sp [1].data.f);
1779 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1782 ip += (signed char)*ip;
1784 ip += (gint32) read32 (ip);
1786 ip += near_jump ? 1: 4;
1789 CASE (CEE_BLE_UN) /* Fall through */
1790 CASE (CEE_BLE_UN_S) {
1792 int near_jump = *ip == CEE_BLE_UN_S;
1795 if (sp->type == VAL_I32)
1796 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1797 else if (sp->type == VAL_I64)
1798 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1799 else if (sp->type == VAL_DOUBLE)
1800 result = islessequal (sp [0].data.f, sp [1].data.f);
1802 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1805 ip += (signed char)*ip;
1807 ip += (gint32) read32 (ip);
1809 ip += near_jump ? 1: 4;
1812 CASE (CEE_BLT_UN) /* Fall through */
1813 CASE (CEE_BLT_UN_S) {
1815 int near_jump = *ip == CEE_BLT_UN_S;
1818 if (sp->type == VAL_I32)
1819 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1820 else if (sp->type == VAL_I64)
1821 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1822 else if (sp->type == VAL_DOUBLE)
1823 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1824 (sp [0].data.f < sp [1].data.f);
1826 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1829 ip += (signed char)*ip;
1831 ip += (gint32) read32 (ip);
1833 ip += near_jump ? 1: 4;
1838 const unsigned char *st;
1842 st = ip + sizeof (gint32) * n;
1844 if ((guint32)sp->data.i < n) {
1846 ip += sizeof (gint32) * (guint32)sp->data.i;
1847 offset = read32 (ip);
1856 sp[-1].type = VAL_I32;
1857 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1861 sp[-1].type = VAL_I32;
1862 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1866 sp[-1].type = VAL_I32;
1867 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1871 sp[-1].type = VAL_I32;
1872 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1874 CASE (CEE_LDIND_I4) /* Fall through */
1877 sp[-1].type = VAL_I32;
1878 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1882 sp[-1].type = VAL_I64;
1883 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1887 sp[-1].type = VAL_NATI;
1888 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1892 sp[-1].type = VAL_DOUBLE;
1893 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
1897 sp[-1].type = VAL_DOUBLE;
1898 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
1900 CASE (CEE_LDIND_REF)
1902 sp[-1].type = VAL_OBJ;
1903 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1904 sp[-1].data.vt.klass = NULL;
1906 CASE (CEE_STIND_REF) {
1914 CASE (CEE_STIND_I1) {
1919 *p = (gint8)sp[1].data.i;
1922 CASE (CEE_STIND_I2) {
1927 *p = (gint16)sp[1].data.i;
1930 CASE (CEE_STIND_I4) {
1938 CASE (CEE_STIND_I) {
1943 *p = (mono_i)sp[1].data.p;
1946 CASE (CEE_STIND_I8) {
1954 CASE (CEE_STIND_R4) {
1959 *p = (gfloat)sp[1].data.f;
1962 CASE (CEE_STIND_R8) {
1973 /* should probably consider the pointers as unsigned */
1974 if (sp->type == VAL_I32)
1975 sp [-1].data.i += GET_NATI (sp [0]);
1976 else if (sp->type == VAL_I64)
1977 sp [-1].data.l += sp [0].data.l;
1978 else if (sp->type == VAL_DOUBLE)
1979 sp [-1].data.f += sp [0].data.f;
1981 char *p = sp [-1].data.p;
1982 p += GET_NATI (sp [0]);
1989 /* should probably consider the pointers as unsigned */
1990 if (sp->type == VAL_I32)
1991 sp [-1].data.i -= GET_NATI (sp [0]);
1992 else if (sp->type == VAL_I64)
1993 sp [-1].data.l -= sp [0].data.l;
1994 else if (sp->type == VAL_DOUBLE)
1995 sp [-1].data.f -= sp [0].data.f;
1997 char *p = sp [-1].data.p;
1998 p -= GET_NATI (sp [0]);
2005 if (sp->type == VAL_I32)
2006 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
2007 else if (sp->type == VAL_I64)
2008 sp [-1].data.l *= sp [0].data.l;
2009 else if (sp->type == VAL_DOUBLE)
2010 sp [-1].data.f *= sp [0].data.f;
2015 if (sp->type == VAL_I32) {
2016 if (GET_NATI (sp [0]) == 0)
2017 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2018 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2019 } else if (sp->type == VAL_I64) {
2020 if (sp [0].data.l == 0)
2021 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2022 sp [-1].data.l /= sp [0].data.l;
2023 } else if (sp->type == VAL_DOUBLE) {
2024 /* set NaN is divisor is 0.0 */
2025 sp [-1].data.f /= sp [0].data.f;
2031 if (sp->type == VAL_I32) {
2033 if (GET_NATI (sp [0]) == 0)
2034 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2035 val = sp [-1].data.i;
2036 val /= (guint32)GET_NATI (sp [0]);
2037 sp [-1].data.i = val;
2038 } else if (sp->type == VAL_I64) {
2040 if (sp [0].data.l == 0)
2041 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2042 val = sp [-1].data.l;
2043 val /= (guint64)sp [0].data.l;
2044 sp [-1].data.l = val;
2045 } else if (sp->type == VAL_NATI) {
2047 if (GET_NATI (sp [0]) == 0)
2048 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2049 val = (mono_u)sp [-1].data.p;
2050 val /= (mono_u)sp [0].data.p;
2051 sp [-1].data.p = (gpointer)val;
2057 if (sp->type == VAL_I32) {
2058 if (GET_NATI (sp [0]) == 0)
2059 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2060 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2061 } else if (sp->type == VAL_I64) {
2062 if (sp [0].data.l == 0)
2063 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2064 sp [-1].data.l %= sp [0].data.l;
2065 } else if (sp->type == VAL_DOUBLE) {
2066 /* FIXME: what do we actually do here? */
2067 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2069 if (GET_NATI (sp [0]) == 0)
2070 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2071 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2077 if (sp->type == VAL_I32) {
2078 if (GET_NATI (sp [0]) == 0)
2079 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2080 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2081 } else if (sp->type == VAL_I64) {
2082 if (sp [0].data.l == 0)
2083 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2084 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2085 } else if (sp->type == VAL_DOUBLE) {
2086 /* unspecified behaviour according to the spec */
2088 if (GET_NATI (sp [0]) == 0)
2089 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2090 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2096 if (sp->type == VAL_I32)
2097 sp [-1].data.i &= GET_NATI (sp [0]);
2098 else if (sp->type == VAL_I64)
2099 sp [-1].data.l &= sp [0].data.l;
2101 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2106 if (sp->type == VAL_I32)
2107 sp [-1].data.i |= GET_NATI (sp [0]);
2108 else if (sp->type == VAL_I64)
2109 sp [-1].data.l |= sp [0].data.l;
2111 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2116 if (sp->type == VAL_I32)
2117 sp [-1].data.i ^= GET_NATI (sp [0]);
2118 else if (sp->type == VAL_I64)
2119 sp [-1].data.l ^= sp [0].data.l;
2121 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2126 if (sp [-1].type == VAL_I32)
2127 sp [-1].data.i <<= GET_NATI (sp [0]);
2128 else if (sp [-1].type == VAL_I64)
2129 sp [-1].data.l <<= GET_NATI (sp [0]);
2131 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2136 if (sp [-1].type == VAL_I32)
2137 sp [-1].data.i >>= GET_NATI (sp [0]);
2138 else if (sp [-1].type == VAL_I64)
2139 sp [-1].data.l >>= GET_NATI (sp [0]);
2141 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2146 if (sp [-1].type == VAL_I32)
2147 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2148 else if (sp [-1].type == VAL_I64)
2149 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2151 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2156 if (sp->type == VAL_I32)
2157 sp->data.i = - sp->data.i;
2158 else if (sp->type == VAL_I64)
2159 sp->data.l = - sp->data.l;
2160 else if (sp->type == VAL_DOUBLE)
2161 sp->data.f = - sp->data.f;
2162 else if (sp->type == VAL_NATI)
2163 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2169 if (sp->type == VAL_I32)
2170 sp->data.i = ~ sp->data.i;
2171 else if (sp->type == VAL_I64)
2172 sp->data.l = ~ sp->data.l;
2173 else if (sp->type == VAL_NATI)
2174 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2177 CASE (CEE_CONV_U1) /* fall through */
2178 CASE (CEE_CONV_I1) {
2180 switch (sp [-1].type) {
2182 sp [-1].data.i = (gint8)sp [-1].data.f;
2185 sp [-1].data.i = (gint8)sp [-1].data.l;
2190 sp [-1].data.i = (gint8)sp [-1].data.i;
2193 sp [-1].data.i = (gint8)sp [-1].data.nati;
2196 sp [-1].type = VAL_I32;
2199 CASE (CEE_CONV_U2) /* fall through */
2200 CASE (CEE_CONV_I2) {
2202 switch (sp [-1].type) {
2204 sp [-1].data.i = (gint16)sp [-1].data.f;
2207 sp [-1].data.i = (gint16)sp [-1].data.l;
2212 sp [-1].data.i = (gint16)sp [-1].data.i;
2215 sp [-1].data.i = (gint16)sp [-1].data.nati;
2218 sp [-1].type = VAL_I32;
2221 CASE (CEE_CONV_U4) /* Fall through */
2222 #if SIZEOF_VOID_P == 4
2223 CASE (CEE_CONV_I) /* Fall through */
2224 CASE (CEE_CONV_U) /* Fall through */
2226 CASE (CEE_CONV_I4) {
2228 switch (sp [-1].type) {
2230 sp [-1].data.i = (gint32)sp [-1].data.f;
2233 sp [-1].data.i = (gint32)sp [-1].data.l;
2240 sp [-1].data.i = (gint32)sp [-1].data.p;
2243 sp [-1].type = VAL_I32;
2246 #if SIZEOF_VOID_P == 8
2247 CASE (CEE_CONV_I) /* Fall through */
2251 switch (sp [-1].type) {
2253 sp [-1].data.l = (gint64)sp [-1].data.f;
2260 sp [-1].data.l = (gint64)sp [-1].data.i;
2263 sp [-1].data.l = (gint64)sp [-1].data.nati;
2266 sp [-1].type = VAL_I64;
2268 CASE (CEE_CONV_R4) /* Fall through */
2269 CASE (CEE_CONV_R8) {
2271 switch (sp [-1].type) {
2273 sp [-1].data.f = (double)sp [-1].data.f;
2276 sp [-1].data.f = (double)sp [-1].data.l;
2281 sp [-1].data.f = (double)sp [-1].data.i;
2284 sp [-1].data.f = (double)sp [-1].data.nati;
2287 sp [-1].type = VAL_DOUBLE;
2290 #if SIZEOF_VOID_P == 8
2291 CASE (CEE_CONV_U) /* Fall through */
2296 switch (sp [-1].type){
2298 sp [-1].data.l = (guint64)sp [-1].data.f;
2305 sp [-1].data.l = (guint64) sp [-1].data.i;
2308 sp [-1].data.l = (guint64) sp [-1].data.nati;
2311 sp [-1].type = VAL_I64;
2316 vtklass = mono_class_get (image, read32 (ip));
2319 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2328 token = read32 (ip);
2330 c = mono_class_get (image, token);
2331 addr = sp [-1].data.vt.vt;
2332 vt_alloc (&c->byval_arg, &sp [-1]);
2333 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2341 str_index = mono_metadata_token_index (read32 (ip));
2344 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2347 sp->data.vt.klass = NULL;
2354 MonoClass *newobj_class;
2355 MonoMethodSignature *csig;
2356 stackval valuetype_this;
2357 stackval *endsp = sp;
2364 token = read32 (ip);
2367 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2368 THROW_EX (mono_get_exception_missing_method (), ip -5);
2370 csig = child_frame.method->signature;
2371 newobj_class = child_frame.method->klass;
2372 /*if (profiling_classes) {
2373 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2375 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2379 if (newobj_class->parent == mono_defaults.array_class) {
2380 sp -= csig->param_count;
2381 o = ves_array_create (domain, newobj_class, csig, sp);
2382 goto array_constructed;
2386 * First arg is the object.
2388 if (newobj_class->valuetype) {
2390 vt_alloc (&newobj_class->byval_arg, &valuetype_this);
2391 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2392 zero = valuetype_this.data.vt.vt;
2393 child_frame.obj = valuetype_this.data.vt.vt;
2395 memset (&valuetype_this, 0, sizeof (stackval));
2396 zero = &valuetype_this;
2397 child_frame.obj = &valuetype_this;
2399 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero);
2401 if (newobj_class != mono_defaults.string_class) {
2402 o = mono_object_new (domain, newobj_class);
2403 child_frame.obj = o;
2405 child_frame.retval = &retval;
2409 if (csig->param_count) {
2410 sp -= csig->param_count;
2411 child_frame.stack_args = sp;
2413 child_frame.stack_args = NULL;
2416 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2418 child_frame.ex = NULL;
2419 child_frame.ex_handler = NULL;
2421 ves_exec_method (&child_frame);
2423 while (endsp > sp) {
2428 if (child_frame.ex) {
2430 * An exception occurred, need to run finally, fault and catch handlers..
2432 frame->ex = child_frame.ex;
2433 goto handle_finally;
2436 * a constructor returns void, but we need to return the object we created
2439 if (newobj_class->valuetype && !newobj_class->enumtype) {
2440 *sp = valuetype_this;
2441 } else if (newobj_class == mono_defaults.string_class) {
2446 sp->data.vt.klass = newobj_class;
2451 CASE (CEE_CASTCLASS) /* Fall through */
2455 MonoClass *c , *oclass;
2457 int do_isinst = *ip == CEE_ISINST;
2458 gboolean found = FALSE;
2461 token = read32 (ip);
2462 c = mono_class_get (image, token);
2464 g_assert (sp [-1].type == VAL_OBJ);
2466 if ((o = sp [-1].data.p)) {
2471 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2472 if ((c->interface_id <= oclass->max_interface_id) &&
2473 vt->interface_offsets [c->interface_id])
2476 if (oclass == mono_defaults.transparent_proxy_class) {
2477 /* fixme: add check for IRemotingTypeInfo */
2478 MonoRealProxy *rp = ((MonoTransparentProxy *)o)->rp;
2480 type = rp->class_to_proxy->type;
2481 oclass = mono_class_from_mono_type (type);
2483 /* handle array casts */
2484 if (oclass->rank && oclass->rank == c->rank) {
2485 if ((oclass->element_class->baseval - c->element_class->baseval) <= c->element_class->diffval) {
2486 sp [-1].data.vt.klass = c;
2489 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2490 sp [-1].data.vt.klass = c;
2497 sp [-1].data.p = NULL;
2498 sp [-1].data.vt.klass = NULL;
2500 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2506 CASE (CEE_CONV_R_UN)
2507 switch (sp [-1].type) {
2511 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2516 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2519 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2522 sp [-1].type = VAL_DOUBLE;
2525 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2532 token = read32 (ip);
2534 c = mono_class_get (image, token);
2538 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2540 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2541 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2543 sp [-1].type = VAL_MP;
2544 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2551 frame->ex_handler = NULL;
2552 THROW_EX (sp->data.p, ip);
2554 CASE (CEE_LDFLDA) /* Fall through */
2557 MonoClassField *field;
2558 guint32 token, offset;
2559 int load_addr = *ip == CEE_LDFLDA;
2561 if (!sp [-1].data.p)
2562 THROW_EX (mono_get_exception_null_reference (), ip);
2565 token = read32 (ip);
2568 if (sp [-1].type == VAL_OBJ) {
2569 obj = sp [-1].data.p;
2570 /* if we access a field from our parent and the parent was
2571 * defined in another assembly, we get a memberref.
2573 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2574 field = mono_field_from_memberref (image, token, NULL);
2576 field = mono_class_get_field (obj->vtable->klass, token);
2577 offset = field->offset;
2578 } else { /* valuetype */
2579 /*g_assert (sp [-1].type == VAL_VALUETA); */
2580 obj = sp [-1].data.vt.vt;
2581 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2582 offset = field->offset - sizeof (MonoObject);
2585 sp [-1].type = VAL_TP;
2586 sp [-1].data.p = (char*)obj + offset;
2587 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2589 vt_alloc (field->type, &sp [-1]);
2590 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2597 MonoClassField *field;
2598 guint32 token, offset;
2603 THROW_EX (mono_get_exception_null_reference (), ip);
2606 token = read32 (ip);
2609 if (sp [0].type == VAL_OBJ) {
2610 obj = sp [0].data.p;
2611 /* if we access a field from our parent and the parent was
2612 * defined in another assembly, we get a memberref.
2614 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2615 field = mono_field_from_memberref (image, token, NULL);
2617 field = mono_class_get_field (obj->vtable->klass, token);
2618 offset = field->offset;
2619 } else { /* valuetype */
2620 /*g_assert (sp->type == VAL_VALUETA); */
2621 obj = sp [0].data.vt.vt;
2622 field = mono_class_get_field (sp [0].data.vt.klass, token);
2623 offset = field->offset - sizeof (MonoObject);
2626 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2630 CASE (CEE_LDSFLD) /* Fall through */
2631 CASE (CEE_LDSFLDA) {
2634 MonoClassField *field;
2636 int load_addr = *ip == CEE_LDSFLDA;
2640 token = read32 (ip);
2643 /* need to handle fieldrefs */
2644 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2645 field = mono_field_from_memberref (image, token, &klass);
2647 klass = mono_class_get (image,
2648 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2649 field = mono_class_get_field (klass, token);
2653 vt = mono_class_vtable (domain, klass);
2654 addr = (char*)(vt->data) + field->offset;
2659 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2661 vt_alloc (field->type, sp);
2662 stackval_from_data (field->type, sp, addr);
2670 MonoClassField *field;
2675 token = read32 (ip);
2679 /* need to handle fieldrefs */
2680 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2681 field = mono_field_from_memberref (image, token, &klass);
2683 klass = mono_class_get (image,
2684 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2685 field = mono_class_get_field (klass, token);
2689 vt = mono_class_vtable (domain, klass);
2690 addr = (char*)(vt->data) + field->offset;
2692 stackval_to_data (field->type, sp, addr);
2699 vtklass = mono_class_get (image, read32 (ip));
2702 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2705 #if SIZEOF_VOID_P == 8
2706 CASE (CEE_CONV_OVF_I_UN)
2708 CASE (CEE_CONV_OVF_I8_UN) {
2709 switch (sp [-1].type) {
2711 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2712 THROW_EX (mono_get_exception_overflow (), ip);
2713 sp [-1].data.l = (guint64)sp [-1].data.f;
2716 if (sp [-1].data.l < 0)
2717 THROW_EX (mono_get_exception_overflow (), ip);
2722 /* Can't overflow */
2723 sp [-1].data.l = (guint64)sp [-1].data.i;
2726 if ((gint64)sp [-1].data.nati < 0)
2727 THROW_EX (mono_get_exception_overflow (), ip);
2728 sp [-1].data.l = (guint64)sp [-1].data.nati;
2731 sp [-1].type = VAL_I64;
2735 #if SIZEOF_VOID_P == 8
2736 CASE (CEE_CONV_OVF_U_UN)
2738 CASE (CEE_CONV_OVF_U8_UN) {
2739 switch (sp [-1].type) {
2741 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
2742 THROW_EX (mono_get_exception_overflow (), ip);
2743 sp [-1].data.l = (guint64)sp [-1].data.f;
2751 /* Can't overflow */
2752 sp [-1].data.l = (guint64)sp [-1].data.i;
2755 /* Can't overflow */
2756 sp [-1].data.l = (guint64)sp [-1].data.nati;
2759 sp [-1].type = VAL_I64;
2763 #if SIZEOF_VOID_P == 4
2764 CASE (CEE_CONV_OVF_I_UN)
2765 CASE (CEE_CONV_OVF_U_UN)
2767 CASE (CEE_CONV_OVF_I1_UN)
2768 CASE (CEE_CONV_OVF_I2_UN)
2769 CASE (CEE_CONV_OVF_I4_UN)
2770 CASE (CEE_CONV_OVF_U1_UN)
2771 CASE (CEE_CONV_OVF_U2_UN)
2772 CASE (CEE_CONV_OVF_U4_UN) {
2774 switch (sp [-1].type) {
2776 value = (guint64)sp [-1].data.f;
2779 value = (guint64)sp [-1].data.l;
2784 value = (guint64)sp [-1].data.i;
2787 value = (guint64)sp [-1].data.nati;
2791 case CEE_CONV_OVF_I1_UN:
2793 THROW_EX (mono_get_exception_overflow (), ip);
2794 sp [-1].data.i = value;
2795 sp [-1].type = VAL_I32;
2797 case CEE_CONV_OVF_I2_UN:
2799 THROW_EX (mono_get_exception_overflow (), ip);
2800 sp [-1].data.i = value;
2801 sp [-1].type = VAL_I32;
2803 #if SIZEOF_VOID_P == 4
2804 case CEE_CONV_OVF_I_UN: /* Fall through */
2806 case CEE_CONV_OVF_I4_UN:
2807 if (value > 2147483647)
2808 THROW_EX (mono_get_exception_overflow (), ip);
2809 sp [-1].data.i = value;
2810 sp [-1].type = VAL_I32;
2812 case CEE_CONV_OVF_U1_UN:
2814 THROW_EX (mono_get_exception_overflow (), ip);
2815 sp [-1].data.i = value;
2816 sp [-1].type = VAL_I32;
2818 case CEE_CONV_OVF_U2_UN:
2820 THROW_EX (mono_get_exception_overflow (), ip);
2821 sp [-1].data.i = value;
2822 sp [-1].type = VAL_I32;
2824 #if SIZEOF_VOID_P == 4
2825 case CEE_CONV_OVF_U_UN: /* Fall through */
2827 case CEE_CONV_OVF_U4_UN:
2828 if (value > 4294967295U)
2829 THROW_EX (mono_get_exception_overflow (), ip);
2830 sp [-1].data.i = value;
2831 sp [-1].type = VAL_I32;
2834 g_assert_not_reached ();
2844 token = read32 (ip);
2846 class = mono_class_get (image, token);
2847 g_assert (class != NULL);
2849 sp [-1].type = VAL_OBJ;
2850 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
2851 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
2853 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
2854 /* need to vt_free (sp); */
2866 token = read32 (ip);
2867 class = mono_class_get (image, token);
2868 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
2871 sp [-1].type = VAL_OBJ;
2873 /*if (profiling_classes) {
2874 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
2876 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
2886 g_assert (sp [-1].type == VAL_OBJ);
2890 THROW_EX (mono_get_exception_null_reference (), ip - 1);
2892 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2894 sp [-1].type = VAL_I32;
2895 sp [-1].data.i = mono_array_length (o);
2899 CASE (CEE_LDELEMA) {
2901 guint32 esize, token;
2904 token = read32 (ip);
2908 g_assert (sp [0].type == VAL_OBJ);
2911 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2913 if (sp [1].data.nati >= mono_array_length (o))
2914 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
2916 /* check the array element corresponds to token */
2917 esize = mono_array_element_size (o->obj.vtable->klass);
2920 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
2921 sp->data.vt.klass = o->obj.vtable->klass->element_class;
2926 CASE (CEE_LDELEM_I1) /* fall through */
2927 CASE (CEE_LDELEM_U1) /* fall through */
2928 CASE (CEE_LDELEM_I2) /* fall through */
2929 CASE (CEE_LDELEM_U2) /* fall through */
2930 CASE (CEE_LDELEM_I4) /* fall through */
2931 CASE (CEE_LDELEM_U4) /* fall through */
2932 CASE (CEE_LDELEM_I8) /* fall through */
2933 CASE (CEE_LDELEM_I) /* fall through */
2934 CASE (CEE_LDELEM_R4) /* fall through */
2935 CASE (CEE_LDELEM_R8) /* fall through */
2936 CASE (CEE_LDELEM_REF) {
2942 g_assert (sp [0].type == VAL_OBJ);
2945 THROW_EX (mono_get_exception_null_reference (), ip);
2947 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2949 aindex = sp [1].data.nati;
2950 if (aindex >= mono_array_length (o))
2951 THROW_EX (mono_get_exception_index_out_of_range (), ip);
2954 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
2958 sp [0].data.i = mono_array_get (o, gint8, aindex);
2959 sp [0].type = VAL_I32;
2962 sp [0].data.i = mono_array_get (o, guint8, aindex);
2963 sp [0].type = VAL_I32;
2966 sp [0].data.i = mono_array_get (o, gint16, aindex);
2967 sp [0].type = VAL_I32;
2970 sp [0].data.i = mono_array_get (o, guint16, aindex);
2971 sp [0].type = VAL_I32;
2974 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
2975 sp [0].type = VAL_NATI;
2978 sp [0].data.i = mono_array_get (o, gint32, aindex);
2979 sp [0].type = VAL_I32;
2982 sp [0].data.i = mono_array_get (o, guint32, aindex);
2983 sp [0].type = VAL_I32;
2986 sp [0].data.l = mono_array_get (o, gint64, aindex);
2987 sp [0].type = VAL_I64;
2990 sp [0].data.f = mono_array_get (o, float, aindex);
2991 sp [0].type = VAL_DOUBLE;
2994 sp [0].data.f = mono_array_get (o, double, aindex);
2995 sp [0].type = VAL_DOUBLE;
2997 case CEE_LDELEM_REF:
2998 sp [0].data.p = mono_array_get (o, gpointer, aindex);
2999 sp [0].data.vt.klass = NULL;
3000 sp [0].type = VAL_OBJ;
3010 CASE (CEE_STELEM_I) /* fall through */
3011 CASE (CEE_STELEM_I1) /* fall through */
3012 CASE (CEE_STELEM_I2) /* fall through */
3013 CASE (CEE_STELEM_I4) /* fall through */
3014 CASE (CEE_STELEM_I8) /* fall through */
3015 CASE (CEE_STELEM_R4) /* fall through */
3016 CASE (CEE_STELEM_R8) /* fall through */
3017 CASE (CEE_STELEM_REF) {
3024 g_assert (sp [0].type == VAL_OBJ);
3027 THROW_EX (mono_get_exception_null_reference (), ip);
3029 ac = o->obj.vtable->klass;
3030 g_assert (MONO_CLASS_IS_ARRAY (ac));
3032 aindex = sp [1].data.nati;
3033 if (aindex >= mono_array_length (o))
3034 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3037 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3041 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3044 mono_array_set (o, gint8, aindex, sp [2].data.i);
3047 mono_array_set (o, gint16, aindex, sp [2].data.i);
3050 mono_array_set (o, gint32, aindex, sp [2].data.i);
3053 mono_array_set (o, gint64, aindex, sp [2].data.l);
3056 mono_array_set (o, float, aindex, sp [2].data.f);
3059 mono_array_set (o, double, aindex, sp [2].data.f);
3061 case CEE_STELEM_REF:
3062 g_assert (sp [2].type == VAL_OBJ);
3063 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3087 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3088 CASE (CEE_CONV_OVF_I1)
3089 if (sp [-1].type == VAL_I32) {
3090 if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
3091 THROW_EX (mono_get_exception_overflow (), ip);
3092 sp [-1].data.i = (gint8)sp [-1].data.i;
3093 } else if (sp [-1].type == VAL_I64) {
3094 if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
3095 THROW_EX (mono_get_exception_overflow (), ip);
3096 sp [-1].data.i = (gint8)sp [-1].data.l;
3102 CASE (CEE_CONV_OVF_U1)
3103 if (sp [-1].type == VAL_I32) {
3104 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3105 THROW_EX (mono_get_exception_overflow (), ip);
3106 sp [-1].data.i = (gint8)sp [-1].data.i;
3107 } else if (sp [-1].type == VAL_I64) {
3108 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3109 THROW_EX (mono_get_exception_overflow (), ip);
3110 sp [-1].data.i = (gint8)sp [-1].data.l;
3116 CASE (CEE_CONV_OVF_I2)
3117 CASE (CEE_CONV_OVF_U2)
3119 /* FIXME: handle other cases */
3120 if (sp [-1].type == VAL_I32) {
3121 /* defined as NOP */
3126 CASE (CEE_CONV_OVF_I4)
3127 /* FIXME: handle other cases */
3128 if (sp [-1].type == VAL_I32) {
3129 /* defined as NOP */
3130 } else if(sp [-1].type == VAL_I64) {
3131 sp [-1].data.i = (gint32)sp [-1].data.l;
3132 sp [-1].type = VAL_I32;
3138 CASE (CEE_CONV_OVF_U4)
3139 /* FIXME: handle other cases */
3140 if (sp [-1].type == VAL_I32) {
3141 /* defined as NOP */
3142 } else if(sp [-1].type == VAL_I64) {
3143 sp [-1].data.i = (guint32)sp [-1].data.l;
3144 sp [-1].type = VAL_I32;
3150 CASE (CEE_CONV_OVF_I8)
3151 /* FIXME: handle other cases */
3152 if (sp [-1].type == VAL_I32) {
3153 sp [-1].data.l = (guint64)sp [-1].data.l;
3154 sp [-1].type = VAL_I64;
3155 } else if(sp [-1].type == VAL_I64) {
3156 /* defined as NOP */
3162 CASE (CEE_CONV_OVF_U8)
3163 /* FIXME: handle other cases */
3164 if (sp [-1].type == VAL_I32) {
3165 sp [-1].data.l = (guint64) sp [-1].data.i;
3166 sp [-1].type = VAL_I64;
3167 } else if(sp [-1].type == VAL_I64) {
3168 /* defined as NOP */
3180 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3181 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3183 if (!finite(sp [-1].data.f))
3184 THROW_EX (mono_get_exception_arithmetic (), ip);
3187 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3188 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3189 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3198 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3199 CASE (CEE_LDTOKEN) {
3201 MonoClass *handle_class;
3203 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3205 vt_alloc (&handle_class->byval_arg, sp);
3206 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
3210 CASE (CEE_CONV_OVF_I)
3213 /* FIXME: check overflow. */
3216 sp->data.p = (gpointer)(mono_i) sp->data.i;
3219 sp->data.p = (gpointer)(mono_i) sp->data.l;
3224 sp->data.p = (gpointer)(mono_i) sp->data.f;
3229 sp->type = VAL_NATI;
3232 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
3235 /* FIXME: check overflow */
3236 if (sp->type == VAL_I32) {
3237 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3238 THROW_EX (mono_get_exception_overflow (), ip);
3239 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3240 } else if (sp->type == VAL_I64) {
3241 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3242 THROW_EX (mono_get_exception_overflow (), ip);
3243 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3244 } else if (sp->type == VAL_DOUBLE)
3245 sp [-1].data.f += sp [0].data.f;
3247 char *p = sp [-1].data.p;
3248 p += GET_NATI (sp [0]);
3253 CASE (CEE_ADD_OVF_UN)
3255 /* FIXME: check overflow, make unsigned */
3256 if (sp->type == VAL_I32) {
3257 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3258 THROW_EX (mono_get_exception_overflow (), ip);
3259 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3260 } else if (sp->type == VAL_I64) {
3261 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3262 THROW_EX (mono_get_exception_overflow (), ip);
3263 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3264 } else if (sp->type == VAL_DOUBLE)
3265 sp [-1].data.f += sp [0].data.f;
3267 char *p = sp [-1].data.p;
3268 p += GET_NATI (sp [0]);
3276 /* FIXME: check overflow */
3277 if (sp->type == VAL_I32)
3278 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3279 else if (sp->type == VAL_I64)
3280 sp [-1].data.l *= sp [0].data.l;
3281 else if (sp->type == VAL_DOUBLE)
3282 sp [-1].data.f *= sp [0].data.f;
3284 CASE (CEE_MUL_OVF_UN)
3287 /* FIXME: check overflow, make unsigned */
3288 if (sp->type == VAL_I32)
3289 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3290 else if (sp->type == VAL_I64)
3291 sp [-1].data.l *= sp [0].data.l;
3292 else if (sp->type == VAL_DOUBLE)
3293 sp [-1].data.f *= sp [0].data.f;
3296 CASE (CEE_SUB_OVF_UN)
3299 /* FIXME: handle undeflow/unsigned */
3300 /* should probably consider the pointers as unsigned */
3301 if (sp->type == VAL_I32)
3302 sp [-1].data.i -= GET_NATI (sp [0]);
3303 else if (sp->type == VAL_I64)
3304 sp [-1].data.l -= sp [0].data.l;
3305 else if (sp->type == VAL_DOUBLE)
3306 sp [-1].data.f -= sp [0].data.f;
3308 char *p = sp [-1].data.p;
3309 p -= GET_NATI (sp [0]);
3313 CASE (CEE_ENDFINALLY)
3315 ip = finally_ips->data;
3316 finally_ips = g_slist_remove (finally_ips, ip);
3322 * There was no exception, we continue normally at the target address.
3326 CASE (CEE_LEAVE) /* Fall through */
3328 sp = frame->stack; /* empty the stack */
3330 if (*ip == CEE_LEAVE_S) {
3332 ip += (signed char) *ip;
3336 ip += (gint32) read32 (ip);
3341 * We may be either inside a try block or inside an handler.
3342 * In the first case there was no exception and we go on
3343 * executing the finally handlers and after that resume control
3345 * In the second case we need to clear the exception and
3346 * continue directly at the target ip.
3350 goto handle_finally;
3353 frame->ex_handler = NULL;
3357 frame->ex_handler = NULL;
3359 goto handle_finally;
3390 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3392 * Note: Exceptions thrown when executing a prefixed opcode need
3393 * to take into account the number of prefix bytes (usually the
3394 * throw point is just (ip - n_prefix_bytes).
3399 case CEE_ARGLIST: ves_abort(); break;
3405 if (sp->type == VAL_I32)
3406 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3407 else if (sp->type == VAL_I64)
3408 result = sp [0].data.l == sp [1].data.l;
3409 else if (sp->type == VAL_DOUBLE) {
3410 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3413 result = sp [0].data.f == sp [1].data.f;
3415 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3417 sp->data.i = result;
3427 if (sp->type == VAL_I32)
3428 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3429 else if (sp->type == VAL_I64)
3430 result = sp [0].data.l > sp [1].data.l;
3431 else if (sp->type == VAL_DOUBLE) {
3432 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3435 result = sp [0].data.f > sp [1].data.f;
3437 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3439 sp->data.i = result;
3449 if (sp->type == VAL_I32)
3450 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3451 else if (sp->type == VAL_I64)
3452 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3453 else if (sp->type == VAL_DOUBLE)
3454 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3456 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3458 sp->data.i = result;
3468 if (sp->type == VAL_I32)
3469 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3470 else if (sp->type == VAL_I64)
3471 result = sp [0].data.l < sp [1].data.l;
3472 else if (sp->type == VAL_DOUBLE) {
3473 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3476 result = sp [0].data.f < sp [1].data.f;
3478 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3480 sp->data.i = result;
3490 if (sp->type == VAL_I32)
3491 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3492 else if (sp->type == VAL_I64)
3493 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3494 else if (sp->type == VAL_DOUBLE)
3495 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3497 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3499 sp->data.i = result;
3505 case CEE_LDVIRTFTN: {
3506 int virtual = *ip == CEE_LDVIRTFTN;
3510 token = read32 (ip);
3512 m = mono_get_method (image, token, NULL);
3514 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3518 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3519 m = get_virtual_method (domain, m, sp);
3521 sp->type = VAL_NATI;
3522 sp->data.p = mono_create_method_pointer (m);
3523 sp->data.vt.klass = NULL;
3527 case CEE_UNUSED56: ves_abort(); break;
3531 arg_pos = read16 (ip);
3533 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
3534 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3546 t = ARG_TYPE (signature, anum);
3547 c = mono_class_from_mono_type (t);
3548 sp->data.vt.klass = c;
3549 sp->data.vt.vt = ARG_POS (anum);
3552 sp->type = VAL_VALUETA;
3562 arg_pos = read16 (ip);
3565 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3572 loc_pos = read16 (ip);
3574 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3575 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3585 loc_pos = read16 (ip);
3587 t = LOCAL_TYPE (header, loc_pos);
3588 c = mono_class_from_mono_type (t);
3589 sp->data.vt.vt = LOCAL_POS (loc_pos);
3590 sp->data.vt.klass = c;
3593 sp->type = VAL_VALUETA;
3603 loc_pos = read16 (ip);
3606 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3611 if (sp != frame->stack)
3612 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
3614 sp->data.p = alloca (sp->data.i);
3617 case CEE_UNUSED57: ves_abort(); break;
3618 case CEE_ENDFILTER: ves_abort(); break;
3619 case CEE_UNALIGNED_:
3621 unaligned_address = 1;
3625 volatile_address = 1;
3634 token = read32 (ip);
3637 * we ignore the value of token (I think we can as unspecified
3638 * behavior described in Partition II, 3.5).
3641 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
3642 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3645 case CEE_UNUSED68: ves_abort(); break;
3648 if (!sp [0].data.p || !sp [1].data.p)
3649 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3651 /* FIXME: value and size may be int64... */
3652 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3657 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3659 /* FIXME: value and size may be int64... */
3660 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3662 case CEE_UNUSED69: ves_abort(); break;
3665 * need to clarify what this should actually do:
3666 * start the search from the last found handler in
3667 * this method or continue in the caller or what.
3668 * Also, do we need to run finally/fault handlers after a retrow?
3669 * Well, this implementation will follow the usual search
3670 * for an handler, considering the current ip as throw spot.
3671 * We need to NULL frame->ex_handler for the later code to
3672 * actually run the new found handler.
3674 frame->ex_handler = NULL;
3675 THROW_EX (frame->ex, ip - 1);
3677 case CEE_UNUSED: ves_abort(); break;
3683 token = read32 (ip);
3685 type = mono_type_create_from_typespec (image, token);
3687 sp->data.i = mono_type_size (type, &align);
3688 mono_metadata_free_type (type);
3692 case CEE_REFANYTYPE: ves_abort(); break;
3699 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3706 g_assert_not_reached ();
3708 * Exception handling code.
3709 * The exception object is stored in frame->ex.
3716 MonoInvocation *inv;
3717 MonoMethodHeader *hd;
3718 MonoExceptionClause *clause;
3722 if (die_on_exception)
3725 for (inv = frame; inv; inv = inv->parent) {
3726 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
3728 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
3730 hd = ((MonoMethodNormal*)inv->method)->header;
3731 ip_offset = inv->ip - hd->code;
3732 for (i = 0; i < hd->num_clauses; ++i) {
3733 clause = &hd->clauses [i];
3734 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3735 if (!clause->flags) {
3736 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3738 * OK, we found an handler, now we need to execute the finally
3739 * and fault blocks before branching to the handler code.
3741 inv->ex_handler = clause;
3743 * It seems that if the catch handler is found in the same method,
3744 * it gets executed before the finally handler.
3749 goto handle_finally;
3752 /* FIXME: handle filter clauses */
3759 * If we get here, no handler was found: print a stack trace.
3762 ex_obj = (MonoObject*)frame->ex;
3763 mono_unhandled_exception (ex_obj);
3770 MonoExceptionClause *clause;
3772 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3776 ip_offset = frame->ip - header->code;
3778 for (i = 0; i < header->num_clauses; ++i) {
3779 clause = &header->clauses [i];
3780 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3781 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3782 ip = header->code + clause->handler_offset;
3783 finally_ips = g_slist_append (finally_ips, ip);
3788 ip = finally_ips->data;
3789 finally_ips = g_slist_remove (finally_ips, ip);
3794 * If an exception is set, we need to execute the fault handler, too,
3795 * otherwise, we continue normally.
3806 MonoExceptionClause *clause;
3808 ip_offset = frame->ip - header->code;
3809 for (i = 0; i < header->num_clauses; ++i) {
3810 clause = &header->clauses [i];
3811 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3812 ip = header->code + clause->handler_offset;
3817 * If the handler for the exception was found in this method, we jump
3818 * to it right away, otherwise we return and let the caller run
3819 * the finally, fault and catch blocks.
3820 * This same code should be present in the endfault opcode, but it
3821 * is corrently not assigned in the ECMA specs: LAMESPEC.
3823 if (frame->ex_handler) {
3824 ip = header->code + frame->ex_handler->handler_offset;
3827 sp->data.p = frame->ex;
3838 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3840 MonoImage *image = assembly->image;
3841 MonoCLIImageInfo *iinfo;
3843 MonoObject *exc = NULL;
3846 iinfo = image->image_info;
3847 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3849 g_error ("No entry point method found in %s", image->name);
3851 rval = mono_runtime_run_main (method, argc, argv, &exc);
3860 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3861 "Usage is: mint [options] executable args...\n", VERSION);
3863 "Valid Options are:\n"
3870 "--traceclassinit\n"
3871 "--noptr\t\t\tdon't print pointer addresses in trace output\n"
3874 "--debug method_name\n"
3876 "--opcode-count\n");
3882 test_load_class (MonoImage* image)
3884 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3888 for (i = 1; i <= t->rows; ++i) {
3889 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3890 mono_class_init (klass);
3895 static MonoException * segv_exception = NULL;
3898 segv_handler (int signum)
3900 signal (signum, segv_handler);
3901 mono_raise_exception (segv_exception);
3905 main (int argc, char *argv [])
3908 MonoAssembly *assembly;
3909 int retval = 0, i, ocount = 0;
3915 for (i = 1; i < argc && argv [i][0] == '-'; i++){
3916 if (strcmp (argv [i], "--trace") == 0)
3918 if (strcmp (argv [i], "--noptr") == 0)
3919 global_no_pointers = 1;
3920 if (strcmp (argv [i], "--traceops") == 0)
3922 if (strcmp (argv [i], "--dieonex") == 0)
3923 die_on_exception = 1;
3924 if (strcmp (argv [i], "--print-vtable") == 0)
3925 mono_print_vtable = TRUE;
3926 if (strcmp (argv [i], "--profile") == 0)
3927 mono_profiler_install_simple ();
3928 if (strcmp (argv [i], "--opcode-count") == 0)
3930 if (strcmp (argv [i], "--help") == 0)
3933 if (strcmp (argv [i], "--debug") == 0) {
3934 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
3936 g_error ("Invalid method name '%s'", argv [i]);
3937 db_methods = g_list_append (db_methods, desc);
3947 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
3948 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
3951 mono_add_internal_call ("System.Array::Set", ves_array_set);
3952 mono_add_internal_call ("System.Array::Get", ves_array_get);
3953 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
3955 frame_thread_id = TlsAlloc ();
3956 TlsSetValue (frame_thread_id, NULL);
3958 mono_install_runtime_invoke (interp_mono_runtime_invoke);
3959 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
3961 mono_install_handler (interp_ex_handler);
3963 InitializeCriticalSection (&metadata_lock);
3964 domain = mono_init (file);
3965 mono_runtime_init (domain);
3966 mono_thread_init (domain, NULL);
3967 mono_network_init ();
3969 assembly = mono_domain_assembly_open (domain, file);
3972 fprintf (stderr, "Can not open image %s\n", file);
3978 test_load_class (assembly->image);
3980 error = mono_verify_corlib ();
3982 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
3985 segv_exception = mono_get_exception_null_reference ();
3986 segv_exception->message = mono_string_new (domain, "Segmentation fault");
3987 signal (SIGSEGV, segv_handler);
3989 retval = ves_exec (domain, assembly, argc - i, argv + i);
3991 mono_profiler_shutdown ();
3993 mono_network_cleanup ();
3994 mono_thread_cleanup ();
3996 mono_domain_unload (domain, TRUE);
4000 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4001 fprintf (stderr, "fcall count: %ld\n", fcall_count);