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, 2002 Ximian, Inc.
25 #include <mono/os/gc_wrapper.h>
31 # define alloca __builtin_alloca
35 /* trim excessive headers */
36 #include <mono/metadata/image.h>
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/cil-coff.h>
39 #include <mono/metadata/mono-endian.h>
40 #include <mono/metadata/tabledefs.h>
41 #include <mono/metadata/blob.h>
42 #include <mono/metadata/tokentype.h>
43 #include <mono/metadata/loader.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/threadpool.h>
46 #include <mono/metadata/profiler-private.h>
47 #include <mono/metadata/appdomain.h>
48 #include <mono/metadata/reflection.h>
49 #include <mono/metadata/exception.h>
50 #include <mono/metadata/verify.h>
51 #include <mono/metadata/opcodes.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/io-layer/io-layer.h>
54 #include <mono/metadata/socket-io.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/os/util.h>
59 /*#include <mono/cli/types.h>*/
63 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
66 #define finite _finite
69 /* If true, then we output the opcodes as we interpret them */
70 static int global_tracing = 0;
71 static int global_no_pointers = 0;
73 static int debug_indent_level = 0;
76 * Pull the list of opcodes
78 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
82 #include "mono/cil/opcode.def"
87 #define GET_NATI(sp) ((sp).data.nati)
88 #define CSIZE(x) (sizeof (x) / 4)
90 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
92 (frame)->parent = (parent_frame); \
93 (frame)->obj = (obj_this); \
94 (frame)->stack_args = (method_args); \
95 (frame)->retval = (method_retval); \
96 (frame)->method = (mono_method); \
97 (frame)->ex_handler = NULL; \
99 (frame)->child = NULL; \
100 (frame)->invoke_trap = 0; \
103 void ves_exec_method (MonoInvocation *frame);
105 typedef void (*ICallMethod) (MonoInvocation *frame);
107 static guint32 die_on_exception = 0;
108 static guint32 frame_thread_id = 0;
110 #define DEBUG_INTERP 1
113 static unsigned long opcode_count = 0;
114 static unsigned long fcall_count = 0;
115 static int break_on_method = 0;
116 static GList *db_methods = NULL;
123 for (h = 0; h < debug_indent_level; h++)
128 db_match_method (gpointer data, gpointer user_data)
130 MonoMethod *m = (MonoMethod*)user_data;
131 MonoMethodDesc *desc = data;
133 if (mono_method_desc_full_match (desc, m))
137 #define DEBUG_ENTER() \
139 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
140 if (break_on_method) tracing=2; \
141 break_on_method = 0; \
143 char *mn, *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
144 debug_indent_level++; \
146 mn = mono_method_full_name (frame->method, FALSE); \
147 g_print ("(%d) Entering %s (", GetCurrentThreadId(), mn); \
149 if (signature->hasthis) { \
150 if (global_no_pointers) { \
151 g_print ("this%s ", frame->obj ? "" : "=null"); \
153 g_print ("%p ", frame->obj); } \
155 g_print ("%s)\n", args); \
158 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
159 mono_profiler_method_enter (frame->method);
161 #define DEBUG_LEAVE() \
164 if (signature->ret->type != MONO_TYPE_VOID) \
165 args = dump_stack (frame->retval, frame->retval + 1); \
167 args = g_strdup (""); \
169 mn = mono_method_full_name (frame->method, FALSE); \
170 g_print ("(%d) Leaving %s", GetCurrentThreadId(), mn); \
172 g_print (" => %s\n", args); \
174 debug_indent_level--; \
176 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
177 mono_profiler_method_leave (frame->method);
181 #define DEBUG_ENTER()
182 #define DEBUG_LEAVE()
187 interp_ex_handler (MonoException *ex) {
188 MonoInvocation *frame = TlsGetValue (frame_thread_id);
190 longjmp (*(jmp_buf*)frame->locals, 1);
194 ves_real_abort (int line, MonoMethod *mh,
195 const unsigned char *ip, stackval *stack, stackval *sp)
197 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
198 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
199 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
200 ip-mm->header->code);
201 g_print ("0x%04x %02x\n",
202 ip-mm->header->code, *ip);
204 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
206 #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);
209 interp_create_remoting_trampoline (MonoMethod *method)
211 return mono_marshal_get_remoting_invoke (method);
215 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
220 gboolean is_proxy = FALSE;
223 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
227 if ((klass = obj->vtable->klass) == mono_defaults.transparent_proxy_class) {
228 klass = ((MonoTransparentProxy *)obj)->klass;
231 vtable = (MonoMethod **)klass->vtable;
233 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
234 res = *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
236 res = vtable [m->slot];
241 return mono_marshal_get_remoting_invoke (res);
247 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
250 switch (type->type) {
251 case MONO_TYPE_OBJECT:
252 case MONO_TYPE_CLASS:
253 case MONO_TYPE_STRING:
254 case MONO_TYPE_ARRAY:
255 case MONO_TYPE_SZARRAY:
256 result->type = VAL_OBJ;
259 result->type = VAL_VALUETA;
262 result->data.p = *(gpointer*)data;
263 result->data.vt.klass = mono_class_from_mono_type (type);
266 switch (type->type) {
270 result->type = VAL_I32;
271 result->data.i = *(gint8*)data;
274 case MONO_TYPE_BOOLEAN:
275 result->type = VAL_I32;
276 result->data.i = *(guint8*)data;
279 result->type = VAL_I32;
280 result->data.i = *(gint16*)data;
284 result->type = VAL_I32;
285 result->data.i = *(guint16*)data;
288 result->type = VAL_I32;
289 result->data.i = *(gint32*)data;
294 result->type = VAL_TP;
295 result->data.p = *(gpointer*)data;
298 result->type = VAL_I32;
299 result->data.i = *(guint32*)data;
302 result->type = VAL_DOUBLE;
303 result->data.f = *(float*)data;
307 result->type = VAL_I64;
308 result->data.l = *(gint64*)data;
311 result->type = VAL_DOUBLE;
312 result->data.f = *(double*)data;
314 case MONO_TYPE_STRING:
315 case MONO_TYPE_SZARRAY:
316 case MONO_TYPE_CLASS:
317 case MONO_TYPE_OBJECT:
318 case MONO_TYPE_ARRAY:
319 result->type = VAL_OBJ;
320 result->data.p = *(gpointer*)data;
321 result->data.vt.klass = mono_class_from_mono_type (type);
323 case MONO_TYPE_VALUETYPE:
324 if (type->data.klass->enumtype) {
325 return stackval_from_data (type->data.klass->enum_basetype, result, data, pinvoke);
328 result->type = VAL_VALUET;
329 result->data.vt.klass = type->data.klass;
332 size = mono_class_native_size (type->data.klass, NULL);
334 size = mono_class_value_size (type->data.klass, NULL);
335 memcpy (result->data.vt.vt, data, size);
339 g_warning ("got type 0x%02x", type->type);
340 g_assert_not_reached ();
345 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
348 gpointer *p = (gpointer*)data;
352 //printf ("TODAT0 %p\n", data);
353 switch (type->type) {
356 guint8 *p = (guint8*)data;
360 case MONO_TYPE_BOOLEAN: {
361 guint8 *p = (guint8*)data;
362 *p = (val->data.i != 0);
367 case MONO_TYPE_CHAR: {
368 guint16 *p = (guint16*)data;
372 #if SIZEOF_VOID_P == 4
378 gint32 *p = (gint32*)data;
382 #if SIZEOF_VOID_P == 8
388 gint64 *p = (gint64*)data;
393 float *p = (float*)data;
398 double *p = (double*)data;
402 case MONO_TYPE_STRING:
403 case MONO_TYPE_SZARRAY:
404 case MONO_TYPE_CLASS:
405 case MONO_TYPE_OBJECT:
406 case MONO_TYPE_ARRAY:
407 case MONO_TYPE_PTR: {
408 gpointer *p = (gpointer*)data;
412 case MONO_TYPE_VALUETYPE:
413 if (type->data.klass->enumtype) {
414 return stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
419 size = mono_class_native_size (type->data.klass, NULL);
421 size = mono_class_value_size (type->data.klass, NULL);
423 memcpy (data, val->data.vt.vt, size);
427 g_warning ("got type %x", type->type);
428 g_assert_not_reached ();
433 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
436 guint32 *lower_bounds;
439 lengths = alloca (sizeof (guint32) * klass->rank * 2);
440 for (i = 0; i < sig->param_count; ++i) {
441 lengths [i] = values->data.i;
444 if (klass->rank == sig->param_count) {
445 /* Only lengths provided. */
448 /* lower bounds are first. */
449 lower_bounds = lengths;
450 lengths += klass->rank;
452 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
456 ves_array_set (MonoInvocation *frame)
458 stackval *sp = frame->stack_args;
462 gint32 i, t, pos, esize;
468 ac = o->vtable->klass;
470 g_assert (ac->rank >= 1);
473 if (ao->bounds != NULL) {
474 pos -= ao->bounds [0].lower_bound;
475 for (i = 1; i < ac->rank; i++) {
476 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
477 ao->bounds [i].length) {
478 g_warning ("wrong array index");
479 g_assert_not_reached ();
481 pos = pos*ao->bounds [i].length + sp [i].data.i -
482 ao->bounds [i].lower_bound;
486 esize = mono_array_element_size (ac);
487 ea = mono_array_addr_with_size (ao, esize, pos);
489 mt = frame->method->signature->params [ac->rank];
490 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
494 ves_array_get (MonoInvocation *frame)
496 stackval *sp = frame->stack_args;
500 gint32 i, pos, esize;
506 ac = o->vtable->klass;
508 g_assert (ac->rank >= 1);
511 if (ao->bounds != NULL) {
512 pos -= ao->bounds [0].lower_bound;
513 for (i = 1; i < ac->rank; i++)
514 pos = pos*ao->bounds [i].length + sp [i].data.i -
515 ao->bounds [i].lower_bound;
518 esize = mono_array_element_size (ac);
519 ea = mono_array_addr_with_size (ao, esize, pos);
521 mt = frame->method->signature->ret;
522 stackval_from_data (mt, frame->retval, ea, FALSE);
526 ves_array_element_address (MonoInvocation *frame)
528 stackval *sp = frame->stack_args;
532 gint32 i, pos, esize;
537 ac = o->vtable->klass;
539 g_assert (ac->rank >= 1);
542 if (ao->bounds != NULL) {
543 pos -= ao->bounds [0].lower_bound;
544 for (i = 1; i < ac->rank; i++)
545 pos = pos*ao->bounds [i].length + sp [i].data.i -
546 ao->bounds [i].lower_bound;
549 esize = mono_array_element_size (ac);
550 ea = mono_array_addr_with_size (ao, esize, pos);
552 frame->retval->type = VAL_TP;
553 frame->retval->data.p = ea;
557 interp_walk_stack (MonoStackWalk func, gpointer user_data)
559 MonoInvocation *frame = TlsGetValue (frame_thread_id);
561 MonoMethodHeader *hd;
564 gboolean managed = FALSE;
565 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
566 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
569 hd = ((MonoMethodNormal*)frame->method)->header;
570 il_offset = frame->ip - hd->code;
571 if (!frame->method->wrapper_type)
574 if (func (frame->method, -1, il_offset, managed, user_data))
576 frame = frame->parent;
581 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor)
587 TlsSetValue (frame_thread_id, frame->args);
592 if (!frame->method->info) {
593 func = frame->method->info = mono_create_trampoline (sig, string_ctor);
595 func = (MonoPIFunc)frame->method->info;
598 func = mono_create_trampoline (sig, string_ctor);
602 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
603 * locals will point to the jmp_buf, while args will point to the previous
604 * MonoInvocation frame: this is needed to make exception searching work across
605 * managed/unmanaged boundaries.
607 frame->locals = (char*)&env;
608 frame->args = (char*)TlsGetValue (frame_thread_id);
609 TlsSetValue (frame_thread_id, frame);
611 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
614 stackval_from_data (&mono_defaults.string_class->byval_arg,
615 frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
616 } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
617 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
619 TlsSetValue (frame_thread_id, frame->args);
624 * runtime specifies that the implementation of the method is automatically
625 * provided by the runtime and is primarily used for the methods of delegates.
628 ves_runtime_method (MonoInvocation *frame)
630 const char *name = frame->method->name;
631 MonoObject *obj = (MonoObject*)frame->obj;
632 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
637 mono_class_init (frame->method->klass);
639 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
640 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
641 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
644 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
651 code = (guchar*)delegate->delegate.method_ptr;
652 if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
654 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
655 ves_exec_method (&call);
660 g_assert_not_reached ();
663 delegate = delegate->prev;
667 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
668 nm = mono_marshal_get_delegate_begin_invoke (frame->method);
669 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
670 ves_exec_method (&call);
674 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
675 nm = mono_marshal_get_delegate_end_invoke (frame->method);
676 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
677 ves_exec_method (&call);
683 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
684 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
685 ves_array_set (frame);
688 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
689 ves_array_get (frame);
692 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
693 ves_array_element_address (frame);
698 g_error ("Don't know how to exec runtime method %s.%s::%s",
699 frame->method->klass->name_space, frame->method->klass->name,
700 frame->method->name);
704 dump_stack (stackval *stack, stackval *sp)
707 GString *str = g_string_new ("");
710 return g_string_free (str, FALSE);
714 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
715 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
716 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
718 if (!global_no_pointers)
719 g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
721 g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
724 MonoObject *obj = s->data.p;
725 if (global_no_pointers && obj && obj->vtable) {
726 MonoClass *klass = mono_object_class (obj);
727 if (klass == mono_defaults.string_class) {
728 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
729 g_string_sprintfa (str, "[str:%s] ", utf8);
732 } else if (klass == mono_defaults.sbyte_class) {
733 g_string_sprintfa (str, "[b:%d] ",
734 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
736 } else if (klass == mono_defaults.int16_class) {
737 g_string_sprintfa (str, "[b:%d] ",
738 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
740 } else if (klass == mono_defaults.int32_class) {
741 g_string_sprintfa (str, "[b:%d] ",
742 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
744 } else if (klass == mono_defaults.byte_class) {
745 g_string_sprintfa (str, "[b:%u] ",
746 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
748 } else if (klass == mono_defaults.char_class
749 || klass == mono_defaults.uint16_class) {
750 g_string_sprintfa (str, "[b:%u] ",
751 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
753 } else if (klass == mono_defaults.uint32_class) {
754 g_string_sprintfa (str, "[b:%u] ",
755 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
757 } else if (klass == mono_defaults.int64_class) {
758 g_string_sprintfa (str, "[b:%lld] ",
759 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
761 } else if (klass == mono_defaults.uint64_class) {
762 g_string_sprintfa (str, "[b:%llu] ",
763 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
765 } else if (klass == mono_defaults.double_class) {
766 g_string_sprintfa (str, "[b:%0.5f] ",
767 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
769 } else if (klass == mono_defaults.single_class) {
770 g_string_sprintfa (str, "[b:%0.5f] ",
771 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
773 } else if (klass == mono_defaults.boolean_class) {
774 g_string_sprintfa (str, "[b:%s] ",
775 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
783 if (!global_no_pointers)
784 g_string_sprintfa (str, "[%p] ", s->data.p);
786 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
791 return g_string_free (str, FALSE);
795 dump_frame (MonoInvocation *inv)
797 GString *str = g_string_new ("");
800 for (i = 0; inv; inv = inv->parent, ++i) {
801 MonoClass *k = inv->method->klass;
804 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
805 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
809 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
811 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
814 opname = mono_opcode_names [codep];
815 codep = inv->ip - hd->code;
817 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
818 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
819 k->name_space, k->name, inv->method->name, args);
822 return g_string_free (str, FALSE);
825 static CRITICAL_SECTION metadata_lock;
828 INLINE_STRING_LENGTH = 1,
831 INLINE_TYPE_ELEMENT_TYPE
835 calc_offsets (MonoImage *image, MonoMethod *method)
837 int i, align, size, offset = 0;
838 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
839 MonoMethodSignature *signature = method->signature;
840 int hasthis = signature->hasthis;
841 register const unsigned char *ip, *end;
842 const MonoOpcode *opcode;
846 MonoDomain *domain = mono_domain_get ();
849 mono_profiler_method_jit (method); /* sort of... */
850 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
851 for (i = 0; i < header->num_locals; ++i) {
852 size = mono_type_size (header->locals [i], &align);
854 offset &= ~(align - 1);
855 offsets [2 + i] = offset;
858 offsets [0] = offset;
861 offset += sizeof (gpointer) - 1;
862 offset &= ~(sizeof (gpointer) - 1);
863 offsets [2 + header->num_locals] = offset;
864 offset += sizeof (gpointer);
866 for (i = 0; i < signature->param_count; ++i) {
867 if (signature->pinvoke)
868 size = mono_type_native_stack_size (signature->params [i], &align);
870 size = mono_type_stack_size (signature->params [i], &align);
872 offset &= ~(align - 1);
873 offsets [2 + hasthis + header->num_locals + i] = offset;
876 offsets [1] = offset;
878 EnterCriticalSection (&metadata_lock);
879 /* intern the strings in the method. */
881 end = ip + header->code_size;
888 opcode = &mono_opcodes [i];
889 switch (opcode->argument) {
893 case MonoInlineString:
894 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
898 if (method->wrapper_type == MONO_WRAPPER_NONE) {
899 class = mono_class_get (image, read32 (ip + 1));
900 mono_class_init (class);
901 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
902 mono_class_vtable (domain, class);
906 case MonoInlineField:
907 token = read32 (ip + 1);
908 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
909 mono_field_from_memberref (image, token, &class);
911 class = mono_class_get (image,
912 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
914 mono_class_init (class);
915 mono_class_vtable (domain, class);
918 case MonoInlineMethod:
919 if (method->wrapper_type == MONO_WRAPPER_NONE) {
920 m = mono_get_method (image, read32 (ip + 1), NULL);
921 mono_class_init (m->klass);
922 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
923 mono_class_vtable (domain, m->klass);
929 case MonoShortInlineR:
931 case MonoInlineBrTarget:
937 case MonoShortInlineVar:
938 case MonoShortInlineI:
939 case MonoShortInlineBrTarget:
942 case MonoInlineSwitch: {
955 g_assert_not_reached ();
959 method->info = offsets;
962 * We store the inline info in addr, since it's unused for IL methods.
964 if (method->klass == mono_defaults.string_class) {
965 if (strcmp (method->name, "get_Length") == 0)
966 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
967 } else if (method->klass == mono_defaults.array_class) {
968 if (strcmp (method->name, "get_Length") == 0)
969 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
970 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
971 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
972 } else if (method->klass == mono_defaults.monotype_class) {
973 if (strcmp (method->name, "GetElementType") == 0)
974 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
976 LeaveCriticalSection (&metadata_lock);
977 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
980 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
981 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
983 #define ARG_POS(n) (args_pointers [(n)])
984 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
985 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
987 #define THROW_EX(exception,ex_ip) \
990 frame->ip = (ex_ip); \
991 stack_trace = dump_frame (frame); \
992 frame->ex = (MonoException*)(exception); \
993 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
994 g_free (stack_trace); \
995 goto handle_exception; \
998 typedef struct _vtallocation vtallocation;
1000 struct _vtallocation {
1003 char data [MONO_ZERO_LEN_ARRAY];
1007 * we don't use vtallocation->next, yet
1009 #define vt_alloc(vtype,sp,native) \
1010 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1011 if (!(vtype)->byref) { \
1014 if (native) size = mono_class_native_size ((vtype)->data.klass, &align); \
1015 else size = mono_class_value_size ((vtype)->data.klass, &align); \
1016 if (!vtalloc || vtalloc->size <= size) { \
1017 vtalloc = alloca (sizeof (vtallocation) + size); \
1018 vtalloc->size = size; \
1019 g_assert (size < 10000); \
1021 (sp)->data.vt.vt = vtalloc->data; \
1024 (sp)->data.vt.klass = (vtype)->data.klass; \
1028 #define vt_free(sp) \
1030 if ((sp)->type == VAL_VALUET) { \
1031 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
1036 verify_method (MonoMethod *m)
1038 GSList *errors, *tmp;
1039 MonoVerifyInfo *info;
1041 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1043 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1044 for (tmp = errors; tmp; tmp = tmp->next) {
1046 g_print ("%s\n", info->message);
1050 mono_free_verify_list (errors);
1053 #define MYGUINT64_MAX 18446744073709551615UL
1054 #define MYGINT64_MAX 9223372036854775807LL
1055 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1057 #define MYGUINT32_MAX 4294967295U
1058 #define MYGINT32_MAX 2147483647
1059 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1061 #define CHECK_ADD_OVERFLOW(a,b) \
1062 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1063 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1065 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1066 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1068 #define CHECK_ADD_OVERFLOW64(a,b) \
1069 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1070 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1072 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1073 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1075 /* Resolves to TRUE if the operands would overflow */
1076 #define CHECK_MUL_OVERFLOW(a,b) \
1077 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1078 (((gint32)(a) > 0) && ((gint32)(b) > 0)) || (((gint32)(a) < 0) && ((gint32)(b) < 0)) ? \
1079 (gint32)(b) > ((MYGINT32_MAX) / (gint32)(a)) : \
1080 (gint32)(b) < ((MYGINT32_MIN) / (gint32)(a))
1082 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1083 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1084 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1086 #define CHECK_MUL_OVERFLOW64(a,b) \
1087 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1088 (((gint64)(a) > 0) && ((gint64)(b) > 0)) || (((gint64)(a) < 0) && ((gint64)(b) < 0)) ? \
1089 (gint64)(b) > ((MYGINT64_MAX) / (gint64)(a)) : \
1090 (gint64)(b) < ((MYGINT64_MIN) / (gint64)(a))
1092 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1093 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1094 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1097 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1099 MonoInvocation frame, *parent;
1100 MonoObject *retval = NULL;
1101 MonoMethodSignature *sig = method->signature;
1102 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1103 int i, type, isobject = 0;
1106 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1108 /* FIXME: Set frame for execption handling. */
1110 switch (sig->ret->type) {
1111 case MONO_TYPE_VOID:
1113 case MONO_TYPE_STRING:
1114 case MONO_TYPE_OBJECT:
1115 case MONO_TYPE_CLASS:
1116 case MONO_TYPE_ARRAY:
1117 case MONO_TYPE_SZARRAY:
1120 case MONO_TYPE_VALUETYPE:
1121 retval = mono_object_new (mono_domain_get (), klass);
1122 ret = ((char*)retval) + sizeof (MonoObject);
1123 if (!sig->ret->data.klass->enumtype)
1124 result.data.vt.vt = ret;
1127 retval = mono_object_new (mono_domain_get (), klass);
1128 ret = ((char*)retval) + sizeof (MonoObject);
1132 for (i = 0; i < sig->param_count; ++i) {
1133 if (sig->params [i]->byref) {
1134 args [i].type = VAL_POINTER;
1135 args [i].data.p = params [i];
1138 type = sig->params [i]->type;
1143 case MONO_TYPE_BOOLEAN:
1144 args [i].type = VAL_I32;
1145 args [i].data.i = *(MonoBoolean*)params [i];
1146 args [i].data.vt.klass = NULL;
1150 case MONO_TYPE_CHAR:
1151 args [i].type = VAL_I32;
1152 args [i].data.i = *(gint16*)params [i];
1153 args [i].data.vt.klass = NULL;
1155 #if SIZEOF_VOID_P == 4
1156 case MONO_TYPE_U: /* use VAL_POINTER? */
1161 args [i].type = VAL_I32;
1162 args [i].data.i = *(gint32*)params [i];
1163 args [i].data.vt.klass = NULL;
1165 #if SIZEOF_VOID_P == 8
1171 args [i].type = VAL_I64;
1172 args [i].data.l = *(gint64*)params [i];
1173 args [i].data.vt.klass = NULL;
1175 case MONO_TYPE_VALUETYPE:
1176 if (sig->params [i]->data.klass->enumtype) {
1177 type = sig->params [i]->data.klass->enum_basetype->type;
1180 args [i].type = VAL_POINTER;
1181 args [i].data.p = params [i];
1182 args [i].data.vt.klass = NULL;
1185 case MONO_TYPE_STRING:
1186 case MONO_TYPE_CLASS:
1187 case MONO_TYPE_ARRAY:
1188 case MONO_TYPE_SZARRAY:
1189 case MONO_TYPE_OBJECT:
1190 args [i].type = VAL_OBJ;
1191 args [i].data.p = params [i];
1192 args [i].data.vt.klass = NULL;
1195 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1199 /* chain with managed parent if any */
1200 parent = TlsGetValue (frame_thread_id);
1201 INIT_FRAME(&frame,parent,obj,args,&result,method);
1203 frame.invoke_trap = 1;
1204 ves_exec_method (&frame);
1205 if (exc && frame.ex) {
1209 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1211 if (isobject || method->string_ctor)
1212 return result.data.p;
1213 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1218 * Need to optimize ALU ops when natural int == int32
1220 * IDEA: if we maintain a stack of ip, sp to be checked
1221 * in the return opcode, we could inline simple methods that don't
1222 * use the stack or local variables....
1224 * The {,.S} versions of many opcodes can/should be merged to reduce code
1229 ves_exec_method (MonoInvocation *frame)
1231 MonoDomain *domain = mono_domain_get ();
1232 MonoInvocation child_frame;
1233 MonoMethodHeader *header;
1234 MonoMethodSignature *signature;
1236 GSList *finally_ips = NULL;
1237 const unsigned char *endfinally_ip;
1238 register const unsigned char *ip;
1239 register stackval *sp;
1240 void **args_pointers;
1242 gint il_ins_count = -1;
1243 gint tracing = global_tracing;
1244 unsigned char tail_recursion = 0;
1245 unsigned char unaligned_address = 0;
1246 unsigned char volatile_address = 0;
1247 vtallocation *vtalloc = NULL;
1250 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1251 frame->method = mono_marshal_get_native_wrapper (frame->method);
1253 signature = frame->method->signature;
1257 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1258 if (!frame->method->addr) {
1259 /* ugly, but needed by the iflags setting in loader.c */
1260 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1261 ves_runtime_method (frame);
1263 goto handle_exception;
1267 if (frame->method->addr) {
1268 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1269 goto handle_exception;
1272 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1273 frame->method->string_ctor);
1275 goto handle_exception;
1280 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1281 ves_runtime_method (frame);
1283 goto handle_exception;
1288 /*verify_method (frame->method);*/
1290 header = ((MonoMethodNormal *)frame->method)->header;
1291 image = frame->method->klass->image;
1293 if (!frame->method->info)
1294 calc_offsets (image, frame->method);
1295 offsets = frame->method->info;
1298 * with alloca we get the expected huge performance gain
1299 * stackval *stack = g_new0(stackval, header->max_stack);
1301 g_assert (header->max_stack < 10000);
1302 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1304 if (header->num_locals) {
1305 g_assert (offsets [0] < 10000);
1306 frame->locals = alloca (offsets [0]);
1308 * yes, we do it unconditionally, because it needs to be done for
1309 * some cases anyway and checking for that would be even slower.
1311 memset (frame->locals, 0, offsets [0]);
1314 * Copy args from stack_args to args.
1316 if (signature->param_count || signature->hasthis) {
1318 int has_this = signature->hasthis;
1320 g_assert (offsets [1] < 10000);
1321 frame->args = alloca (offsets [1]);
1322 g_assert ((signature->param_count + has_this) < 1000);
1323 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1326 this_arg = args_pointers [0] = frame->args;
1327 *this_arg = frame->obj;
1329 for (i = 0; i < signature->param_count; ++i) {
1330 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1331 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1335 child_frame.parent = frame;
1336 frame->child = &child_frame;
1343 * using while (ip < end) may result in a 15% performance drop,
1344 * but it may be useful for debug
1348 /*g_assert (sp >= stack);*/
1352 char *ins, *discode;
1353 if (sp > frame->stack) {
1354 ins = dump_stack (frame->stack, sp);
1356 ins = g_strdup ("");
1359 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1360 discode [strlen (discode) - 1] = 0; /* no \n */
1361 g_print ("(%d) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1365 if (il_ins_count > 0)
1366 if (!(--il_ins_count))
1376 G_BREAKPOINT (); /* this is not portable... */
1381 CASE (CEE_LDARG_3) {
1382 int n = (*ip)-CEE_LDARG_0;
1384 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1385 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1392 CASE (CEE_LDLOC_3) {
1393 int n = (*ip)-CEE_LDLOC_0;
1395 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1397 sp->data.i = *(gint32*) LOCAL_POS (n);
1401 vt_alloc (LOCAL_TYPE (header, n), sp, FALSE);
1402 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1410 CASE (CEE_STLOC_3) {
1411 int n = (*ip)-CEE_STLOC_0;
1414 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1415 gint32 *p = (gint32*)LOCAL_POS (n);
1419 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1426 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1427 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1431 CASE (CEE_LDARGA_S) {
1436 t = ARG_TYPE (signature, *ip);
1437 c = mono_class_from_mono_type (t);
1438 sp->data.vt.klass = c;
1439 sp->data.vt.vt = ARG_POS (*ip);
1442 sp->type = VAL_VALUETA;
1453 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1459 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1460 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1464 CASE (CEE_LDLOCA_S) {
1469 t = LOCAL_TYPE (header, *ip);
1470 c = mono_class_from_mono_type (t);
1471 sp->data.vt.klass = c;
1472 sp->data.p = LOCAL_POS (*ip);
1475 sp->type = VAL_VALUETA;
1486 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1494 sp->data.vt.klass = NULL;
1497 CASE (CEE_LDC_I4_M1)
1513 sp->data.i = (*ip) - CEE_LDC_I4_0;
1520 sp->data.i = *(const gint8 *)ip;
1527 sp->data.i = read32 (ip);
1534 sp->data.l = read64 (ip);
1541 sp->type = VAL_DOUBLE;
1550 sp->type = VAL_DOUBLE;
1551 readr8(ip, &sp->data.f);
1555 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1557 if (sp [-1].type == VAL_VALUET) {
1558 MonoClass *c = sp [-1].data.vt.klass;
1559 vt_alloc (&c->byval_arg, sp, FALSE);
1560 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt, FALSE);
1572 CASE (CEE_JMP) ves_abort(); BREAK;
1573 CASE (CEE_CALLVIRT) /* Fall through */
1574 CASE (CEE_CALLI) /* Fall through */
1576 MonoMethodSignature *csignature;
1578 stackval *endsp = sp;
1580 int virtual = *ip == CEE_CALLVIRT;
1581 int calli = *ip == CEE_CALLI;
1582 unsigned char *code = NULL;
1585 * We ignore tail recursion for now.
1592 token = read32 (ip);
1598 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1599 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1600 child_frame.method = NULL;
1601 } else if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
1602 child_frame.method = ji->method;
1604 g_assert_not_reached ();
1608 child_frame.method = mono_get_method (image, token, NULL);
1609 if (!child_frame.method)
1610 THROW_EX (mono_get_exception_missing_method (), ip -5);
1611 csignature = child_frame.method->signature;
1613 stackval *this_arg = &sp [-csignature->param_count-1];
1614 if (!this_arg->data.p)
1615 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1616 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1617 if (!child_frame.method)
1618 THROW_EX (mono_get_exception_missing_method (), ip -5);
1622 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1623 /* decrement by the actual number of args */
1624 if (csignature->param_count) {
1625 sp -= csignature->param_count;
1626 child_frame.stack_args = sp;
1628 child_frame.stack_args = NULL;
1630 if (csignature->hasthis) {
1631 g_assert (sp >= frame->stack);
1634 * It may also be a TP from LD(S)FLDA
1635 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1637 if (sp->type == VAL_OBJ && child_frame.method &&
1638 child_frame.method->klass->valuetype) /* unbox it */
1639 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1641 child_frame.obj = sp->data.p;
1643 child_frame.obj = NULL;
1645 if (csignature->ret->type != MONO_TYPE_VOID) {
1646 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
1647 child_frame.retval = &retval;
1649 child_frame.retval = NULL;
1652 child_frame.ex = NULL;
1653 child_frame.ex_handler = NULL;
1655 if (!child_frame.method) {
1657 ves_pinvoke_method (&child_frame, csignature, code, FALSE);
1658 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
1659 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
1660 g_assert (child_frame.method);
1661 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
1662 ves_exec_method (&child_frame);
1664 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1665 case INLINE_STRING_LENGTH:
1666 retval.type = VAL_I32;
1667 retval.data.i = ((MonoString*)sp->data.p)->length;
1668 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
1670 case INLINE_ARRAY_LENGTH:
1671 retval.type = VAL_I32;
1672 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1674 case INLINE_ARRAY_RANK:
1675 retval.type = VAL_I32;
1676 retval.data.i = mono_object_class (sp->data.p)->rank;
1678 case INLINE_TYPE_ELEMENT_TYPE:
1679 retval.type = VAL_OBJ;
1681 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1682 retval.data.vt.klass = NULL;
1683 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1684 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1685 else if (c->element_class)
1686 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1688 retval.data.p = NULL;
1692 ves_exec_method (&child_frame);
1696 while (endsp > sp) {
1701 if (child_frame.ex) {
1703 * An exception occurred, need to run finally, fault and catch handlers..
1705 frame->ex = child_frame.ex;
1706 goto handle_finally;
1709 /* need to handle typedbyref ... */
1710 if (csignature->ret->type != MONO_TYPE_VOID) {
1717 if (signature->ret->type != MONO_TYPE_VOID) {
1719 if (sp->type == VAL_VALUET) {
1720 /* the caller has already allocated the memory */
1721 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt, signature->pinvoke);
1724 *frame->retval = *sp;
1727 if (sp > frame->stack)
1728 g_warning ("more values on stack: %d", sp-frame->stack);
1732 CASE (CEE_BR_S) /* Fall through */
1734 if (*ip == CEE_BR) {
1736 ip += (gint32) read32(ip);
1740 ip += (signed char) *ip;
1744 CASE (CEE_BRFALSE) /* Fall through */
1745 CASE (CEE_BRFALSE_S) {
1748 if (*ip == CEE_BRFALSE_S) {
1749 broffset = (signed char)ip [1];
1752 broffset = (gint32) read32 (ip + 1);
1757 case VAL_I32: result = sp->data.i == 0; break;
1758 case VAL_I64: result = sp->data.l == 0; break;
1759 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1760 default: result = sp->data.p == NULL; break;
1766 CASE (CEE_BRTRUE) /* Fall through */
1767 CASE (CEE_BRTRUE_S) {
1770 if (*ip == CEE_BRTRUE_S) {
1771 broffset = (signed char)ip [1];
1774 broffset = (gint32) read32 (ip + 1);
1779 case VAL_I32: result = sp->data.i != 0; break;
1780 case VAL_I64: result = sp->data.l != 0; break;
1781 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1782 default: result = sp->data.p != NULL; break;
1788 CASE (CEE_BEQ) /* Fall through */
1792 if (*ip == CEE_BEQ_S) {
1793 broffset = (signed char)ip [1];
1796 broffset = (gint32) read32 (ip + 1);
1800 if (sp->type == VAL_I32)
1801 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1802 else if (sp->type == VAL_I64)
1803 result = sp [0].data.l == sp [1].data.l;
1804 else if (sp->type == VAL_DOUBLE)
1805 result = sp [0].data.f == sp [1].data.f;
1807 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1812 CASE (CEE_BGE) /* Fall through */
1816 if (*ip == CEE_BGE_S) {
1817 broffset = (signed char)ip [1];
1820 broffset = (gint32) read32 (ip + 1);
1824 if (sp->type == VAL_I32)
1825 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1826 else if (sp->type == VAL_I64)
1827 result = sp [0].data.l >= sp [1].data.l;
1828 else if (sp->type == VAL_DOUBLE)
1829 result = sp [0].data.f >= sp [1].data.f;
1831 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1836 CASE (CEE_BGT) /* Fall through */
1840 if (*ip == CEE_BGT_S) {
1841 broffset = (signed char)ip [1];
1844 broffset = (gint32) read32 (ip + 1);
1848 if (sp->type == VAL_I32)
1849 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1850 else if (sp->type == VAL_I64)
1851 result = sp [0].data.l > sp [1].data.l;
1852 else if (sp->type == VAL_DOUBLE)
1853 result = sp [0].data.f > sp [1].data.f;
1855 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1860 CASE (CEE_BLT) /* Fall through */
1864 if (*ip == CEE_BLT_S) {
1865 broffset = (signed char)ip [1];
1868 broffset = (gint32) read32 (ip + 1);
1872 if (sp->type == VAL_I32)
1873 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1874 else if (sp->type == VAL_I64)
1875 result = sp[0].data.l < sp[1].data.l;
1876 else if (sp->type == VAL_DOUBLE)
1877 result = sp[0].data.f < sp[1].data.f;
1879 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1884 CASE (CEE_BLE) /* fall through */
1888 if (*ip == CEE_BLE_S) {
1889 broffset = (signed char)ip [1];
1892 broffset = (gint32) read32 (ip + 1);
1897 if (sp->type == VAL_I32)
1898 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1899 else if (sp->type == VAL_I64)
1900 result = sp [0].data.l <= sp [1].data.l;
1901 else if (sp->type == VAL_DOUBLE)
1902 result = sp [0].data.f <= sp [1].data.f;
1905 * FIXME: here and in other places GET_NATI on the left side
1906 * _will_ be wrong when we change the macro to work on 64 bits
1909 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1915 CASE (CEE_BNE_UN) /* Fall through */
1916 CASE (CEE_BNE_UN_S) {
1919 if (*ip == CEE_BNE_UN_S) {
1920 broffset = (signed char)ip [1];
1923 broffset = (gint32) read32 (ip + 1);
1927 if (sp->type == VAL_I32)
1928 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1929 else if (sp->type == VAL_I64)
1930 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1931 else if (sp->type == VAL_DOUBLE)
1932 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1933 (sp [0].data.f != sp [1].data.f);
1935 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1940 CASE (CEE_BGE_UN) /* Fall through */
1941 CASE (CEE_BGE_UN_S) {
1944 if (*ip == CEE_BGE_UN_S) {
1945 broffset = (signed char)ip [1];
1948 broffset = (gint32) read32 (ip + 1);
1952 if (sp->type == VAL_I32)
1953 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1954 else if (sp->type == VAL_I64)
1955 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1956 else if (sp->type == VAL_DOUBLE)
1957 result = !isless (sp [0].data.f,sp [1].data.f);
1959 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1964 CASE (CEE_BGT_UN) /* Fall through */
1965 CASE (CEE_BGT_UN_S) {
1968 if (*ip == CEE_BGT_UN_S) {
1969 broffset = (signed char)ip [1];
1972 broffset = (gint32) read32 (ip + 1);
1976 if (sp->type == VAL_I32)
1977 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1978 else if (sp->type == VAL_I64)
1979 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1980 else if (sp->type == VAL_DOUBLE)
1981 result = isgreater (sp [0].data.f, sp [1].data.f);
1983 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1988 CASE (CEE_BLE_UN) /* Fall through */
1989 CASE (CEE_BLE_UN_S) {
1992 if (*ip == CEE_BLE_UN_S) {
1993 broffset = (signed char)ip [1];
1996 broffset = (gint32) read32 (ip + 1);
2000 if (sp->type == VAL_I32)
2001 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
2002 else if (sp->type == VAL_I64)
2003 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2004 else if (sp->type == VAL_DOUBLE)
2005 result = islessequal (sp [0].data.f, sp [1].data.f);
2007 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
2012 CASE (CEE_BLT_UN) /* Fall through */
2013 CASE (CEE_BLT_UN_S) {
2016 if (*ip == CEE_BLT_UN_S) {
2017 broffset = (signed char)ip [1];
2020 broffset = (gint32) read32 (ip + 1);
2024 if (sp->type == VAL_I32)
2025 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
2026 else if (sp->type == VAL_I64)
2027 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2028 else if (sp->type == VAL_DOUBLE)
2029 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2030 (sp [0].data.f < sp [1].data.f);
2032 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
2039 const unsigned char *st;
2043 st = ip + sizeof (gint32) * n;
2045 if ((guint32)sp->data.i < n) {
2047 ip += sizeof (gint32) * (guint32)sp->data.i;
2048 offset = read32 (ip);
2057 sp[-1].type = VAL_I32;
2058 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2062 sp[-1].type = VAL_I32;
2063 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2067 sp[-1].type = VAL_I32;
2068 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2072 sp[-1].type = VAL_I32;
2073 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2075 CASE (CEE_LDIND_I4) /* Fall through */
2078 sp[-1].type = VAL_I32;
2079 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2083 sp[-1].type = VAL_I64;
2084 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2088 sp[-1].type = VAL_NATI;
2089 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2093 sp[-1].type = VAL_DOUBLE;
2094 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2098 sp[-1].type = VAL_DOUBLE;
2099 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2101 CASE (CEE_LDIND_REF)
2103 sp[-1].type = VAL_OBJ;
2104 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2105 sp[-1].data.vt.klass = NULL;
2107 CASE (CEE_STIND_REF) {
2115 CASE (CEE_STIND_I1) {
2120 *p = (gint8)sp[1].data.i;
2123 CASE (CEE_STIND_I2) {
2128 *p = (gint16)sp[1].data.i;
2131 CASE (CEE_STIND_I4) {
2139 CASE (CEE_STIND_I) {
2144 *p = (mono_i)sp[1].data.p;
2147 CASE (CEE_STIND_I8) {
2155 CASE (CEE_STIND_R4) {
2160 *p = (gfloat)sp[1].data.f;
2163 CASE (CEE_STIND_R8) {
2174 /* should probably consider the pointers as unsigned */
2175 if (sp->type == VAL_I32)
2176 sp [-1].data.i += GET_NATI (sp [0]);
2177 else if (sp->type == VAL_I64)
2178 sp [-1].data.l += sp [0].data.l;
2179 else if (sp->type == VAL_DOUBLE)
2180 sp [-1].data.f += sp [0].data.f;
2182 char *p = sp [-1].data.p;
2183 p += GET_NATI (sp [0]);
2190 /* should probably consider the pointers as unsigned */
2191 if (sp->type == VAL_I32)
2192 sp [-1].data.i -= GET_NATI (sp [0]);
2193 else if (sp->type == VAL_I64)
2194 sp [-1].data.l -= sp [0].data.l;
2195 else if (sp->type == VAL_DOUBLE)
2196 sp [-1].data.f -= sp [0].data.f;
2198 char *p = sp [-1].data.p;
2199 p -= GET_NATI (sp [0]);
2206 if (sp->type == VAL_I32)
2207 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
2208 else if (sp->type == VAL_I64)
2209 sp [-1].data.l *= sp [0].data.l;
2210 else if (sp->type == VAL_DOUBLE)
2211 sp [-1].data.f *= sp [0].data.f;
2216 if (sp->type == VAL_I32) {
2217 if (GET_NATI (sp [0]) == 0)
2218 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2219 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2220 } else if (sp->type == VAL_I64) {
2221 if (sp [0].data.l == 0)
2222 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2223 sp [-1].data.l /= sp [0].data.l;
2224 } else if (sp->type == VAL_DOUBLE) {
2225 /* set NaN is divisor is 0.0 */
2226 sp [-1].data.f /= sp [0].data.f;
2232 if (sp->type == VAL_I32) {
2234 if (GET_NATI (sp [0]) == 0)
2235 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2236 val = sp [-1].data.i;
2237 val /= (guint32)GET_NATI (sp [0]);
2238 sp [-1].data.i = val;
2239 } else if (sp->type == VAL_I64) {
2241 if (sp [0].data.l == 0)
2242 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2243 val = sp [-1].data.l;
2244 val /= (guint64)sp [0].data.l;
2245 sp [-1].data.l = val;
2246 } else if (sp->type == VAL_NATI) {
2248 if (GET_NATI (sp [0]) == 0)
2249 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2250 val = (mono_u)sp [-1].data.p;
2251 val /= (mono_u)sp [0].data.p;
2252 sp [-1].data.p = (gpointer)val;
2258 if (sp->type == VAL_I32) {
2259 if (GET_NATI (sp [0]) == 0)
2260 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2261 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2262 } else if (sp->type == VAL_I64) {
2263 if (sp [0].data.l == 0)
2264 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2265 sp [-1].data.l %= sp [0].data.l;
2266 } else if (sp->type == VAL_DOUBLE) {
2267 /* FIXME: what do we actually do here? */
2268 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2270 if (GET_NATI (sp [0]) == 0)
2271 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2272 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2278 if (sp->type == VAL_I32) {
2279 if (GET_NATI (sp [0]) == 0)
2280 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2281 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2282 } else if (sp->type == VAL_I64) {
2283 if (sp [0].data.l == 0)
2284 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2285 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2286 } else if (sp->type == VAL_DOUBLE) {
2287 /* unspecified behaviour according to the spec */
2289 if (GET_NATI (sp [0]) == 0)
2290 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2291 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2297 if (sp->type == VAL_I32)
2298 sp [-1].data.i &= GET_NATI (sp [0]);
2299 else if (sp->type == VAL_I64)
2300 sp [-1].data.l &= sp [0].data.l;
2302 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2307 if (sp->type == VAL_I32)
2308 sp [-1].data.i |= GET_NATI (sp [0]);
2309 else if (sp->type == VAL_I64)
2310 sp [-1].data.l |= sp [0].data.l;
2312 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2317 if (sp->type == VAL_I32)
2318 sp [-1].data.i ^= GET_NATI (sp [0]);
2319 else if (sp->type == VAL_I64)
2320 sp [-1].data.l ^= sp [0].data.l;
2322 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2327 if (sp [-1].type == VAL_I32)
2328 sp [-1].data.i <<= GET_NATI (sp [0]);
2329 else if (sp [-1].type == VAL_I64)
2330 sp [-1].data.l <<= GET_NATI (sp [0]);
2332 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2337 if (sp [-1].type == VAL_I32)
2338 sp [-1].data.i >>= GET_NATI (sp [0]);
2339 else if (sp [-1].type == VAL_I64)
2340 sp [-1].data.l >>= GET_NATI (sp [0]);
2342 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2347 if (sp [-1].type == VAL_I32)
2348 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2349 else if (sp [-1].type == VAL_I64)
2350 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2352 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2357 if (sp->type == VAL_I32)
2358 sp->data.i = - sp->data.i;
2359 else if (sp->type == VAL_I64)
2360 sp->data.l = - sp->data.l;
2361 else if (sp->type == VAL_DOUBLE)
2362 sp->data.f = - sp->data.f;
2363 else if (sp->type == VAL_NATI)
2364 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2370 if (sp->type == VAL_I32)
2371 sp->data.i = ~ sp->data.i;
2372 else if (sp->type == VAL_I64)
2373 sp->data.l = ~ sp->data.l;
2374 else if (sp->type == VAL_NATI)
2375 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2378 CASE (CEE_CONV_U1) /* fall through */
2379 CASE (CEE_CONV_I1) {
2381 switch (sp [-1].type) {
2383 sp [-1].data.i = (gint8)sp [-1].data.f;
2386 sp [-1].data.i = (gint8)sp [-1].data.l;
2391 sp [-1].data.i = (gint8)sp [-1].data.i;
2394 sp [-1].data.i = (gint8)sp [-1].data.nati;
2397 sp [-1].type = VAL_I32;
2400 CASE (CEE_CONV_U2) /* fall through */
2401 CASE (CEE_CONV_I2) {
2403 switch (sp [-1].type) {
2405 sp [-1].data.i = (gint16)sp [-1].data.f;
2408 sp [-1].data.i = (gint16)sp [-1].data.l;
2413 sp [-1].data.i = (gint16)sp [-1].data.i;
2416 sp [-1].data.i = (gint16)sp [-1].data.nati;
2419 sp [-1].type = VAL_I32;
2422 CASE (CEE_CONV_U4) /* Fall through */
2423 #if SIZEOF_VOID_P == 4
2424 CASE (CEE_CONV_I) /* Fall through */
2425 CASE (CEE_CONV_U) /* Fall through */
2427 CASE (CEE_CONV_I4) {
2429 switch (sp [-1].type) {
2431 sp [-1].data.i = (gint32)sp [-1].data.f;
2434 sp [-1].data.i = (gint32)sp [-1].data.l;
2441 sp [-1].data.i = (gint32)sp [-1].data.p;
2444 sp [-1].type = VAL_I32;
2447 #if SIZEOF_VOID_P == 8
2448 CASE (CEE_CONV_I) /* Fall through */
2452 switch (sp [-1].type) {
2454 sp [-1].data.l = (gint64)sp [-1].data.f;
2461 sp [-1].data.l = (gint64)sp [-1].data.i;
2464 sp [-1].data.l = (gint64)sp [-1].data.nati;
2467 sp [-1].type = VAL_I64;
2469 CASE (CEE_CONV_R4) {
2471 switch (sp [-1].type) {
2473 sp [-1].data.f = (float)sp [-1].data.f;
2476 sp [-1].data.f = (float)sp [-1].data.l;
2481 sp [-1].data.f = (float)sp [-1].data.i;
2484 sp [-1].data.f = (float)sp [-1].data.nati;
2487 sp [-1].type = VAL_DOUBLE;
2490 CASE (CEE_CONV_R8) {
2492 switch (sp [-1].type) {
2494 sp [-1].data.f = (double)sp [-1].data.f;
2497 sp [-1].data.f = (double)sp [-1].data.l;
2502 sp [-1].data.f = (double)sp [-1].data.i;
2505 sp [-1].data.f = (double)sp [-1].data.nati;
2508 sp [-1].type = VAL_DOUBLE;
2511 #if SIZEOF_VOID_P == 8
2512 CASE (CEE_CONV_U) /* Fall through */
2517 switch (sp [-1].type){
2519 sp [-1].data.l = (guint64)sp [-1].data.f;
2526 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
2529 sp [-1].data.l = (guint64) sp [-1].data.nati;
2532 sp [-1].type = VAL_I64;
2537 vtklass = mono_class_get (image, read32 (ip));
2540 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2549 token = read32 (ip);
2552 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
2553 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
2555 c = mono_class_get (image, token);
2557 addr = sp [-1].data.vt.vt;
2558 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
2559 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
2567 str_index = mono_metadata_token_index (read32 (ip));
2570 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2573 sp->data.vt.klass = NULL;
2580 MonoClass *newobj_class;
2581 MonoMethodSignature *csig;
2582 stackval valuetype_this;
2583 stackval *endsp = sp;
2590 token = read32 (ip);
2593 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2594 THROW_EX (mono_get_exception_missing_method (), ip -5);
2596 csig = child_frame.method->signature;
2597 newobj_class = child_frame.method->klass;
2598 /*if (profiling_classes) {
2599 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2601 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2605 if (newobj_class->parent == mono_defaults.array_class) {
2606 sp -= csig->param_count;
2607 o = ves_array_create (domain, newobj_class, csig, sp);
2608 goto array_constructed;
2612 * First arg is the object.
2614 if (newobj_class->valuetype) {
2616 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
2617 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2618 zero = valuetype_this.data.vt.vt;
2619 child_frame.obj = valuetype_this.data.vt.vt;
2621 memset (&valuetype_this, 0, sizeof (stackval));
2622 zero = &valuetype_this;
2623 child_frame.obj = &valuetype_this;
2625 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
2627 if (newobj_class != mono_defaults.string_class) {
2628 o = mono_object_new (domain, newobj_class);
2629 child_frame.obj = o;
2631 child_frame.retval = &retval;
2635 if (csig->param_count) {
2636 sp -= csig->param_count;
2637 child_frame.stack_args = sp;
2639 child_frame.stack_args = NULL;
2642 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2644 child_frame.ex = NULL;
2645 child_frame.ex_handler = NULL;
2647 ves_exec_method (&child_frame);
2649 while (endsp > sp) {
2654 if (child_frame.ex) {
2656 * An exception occurred, need to run finally, fault and catch handlers..
2658 frame->ex = child_frame.ex;
2659 goto handle_finally;
2662 * a constructor returns void, but we need to return the object we created
2665 if (newobj_class->valuetype && !newobj_class->enumtype) {
2666 *sp = valuetype_this;
2667 } else if (newobj_class == mono_defaults.string_class) {
2672 sp->data.vt.klass = newobj_class;
2677 CASE (CEE_CASTCLASS) /* Fall through */
2681 MonoClass *c , *oclass;
2683 int do_isinst = *ip == CEE_ISINST;
2684 gboolean found = FALSE;
2687 token = read32 (ip);
2688 c = mono_class_get (image, token);
2690 g_assert (sp [-1].type == VAL_OBJ);
2692 if ((o = sp [-1].data.p)) {
2697 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2698 if ((c->interface_id <= oclass->max_interface_id) &&
2699 vt->interface_offsets [c->interface_id])
2702 if (oclass == mono_defaults.transparent_proxy_class) {
2703 /* fixme: add check for IRemotingTypeInfo */
2704 MonoRealProxy *rp = ((MonoTransparentProxy *)o)->rp;
2706 type = rp->class_to_proxy->type;
2707 oclass = mono_class_from_mono_type (type);
2709 /* handle array casts */
2711 if ((oclass->rank == c->rank) &&
2712 (oclass->cast_class->baseval - c->cast_class->baseval) <=
2713 c->cast_class->diffval) {
2714 sp [-1].data.vt.klass = c;
2717 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2718 sp [-1].data.vt.klass = c;
2725 sp [-1].data.p = NULL;
2726 sp [-1].data.vt.klass = NULL;
2728 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2734 CASE (CEE_CONV_R_UN)
2736 switch (sp [-1].type) {
2740 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2745 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2748 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2751 sp [-1].type = VAL_DOUBLE;
2754 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2761 token = read32 (ip);
2763 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
2764 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
2766 c = mono_class_get (image, token);
2770 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2772 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2773 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2775 sp [-1].type = VAL_MP;
2776 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2783 frame->ex_handler = NULL;
2785 sp->data.p = mono_get_exception_null_reference ();
2786 THROW_EX (sp->data.p, ip);
2788 CASE (CEE_LDFLDA) /* Fall through */
2791 MonoClassField *field;
2793 int load_addr = *ip == CEE_LDFLDA;
2796 if (!sp [-1].data.p)
2797 THROW_EX (mono_get_exception_null_reference (), ip);
2800 token = read32 (ip);
2803 if (sp [-1].type == VAL_OBJ) {
2804 obj = sp [-1].data.p;
2806 if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
2807 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
2808 field = mono_class_get_field (klass, token);
2809 addr = mono_load_remote_field (obj, klass, field, NULL);
2811 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2812 field = mono_field_from_memberref (image, token, NULL);
2814 field = mono_class_get_field (obj->vtable->klass, token);
2815 addr = (char*)obj + field->offset;
2818 obj = sp [-1].data.vt.vt;
2819 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2820 addr = (char*)obj + field->offset - sizeof (MonoObject);
2824 sp [-1].type = VAL_TP;
2825 sp [-1].data.p = addr;
2826 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2828 vt_alloc (field->type, &sp [-1], FALSE);
2829 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2836 MonoClassField *field;
2837 guint32 token, offset;
2842 THROW_EX (mono_get_exception_null_reference (), ip);
2845 token = read32 (ip);
2848 if (sp [0].type == VAL_OBJ) {
2849 obj = sp [0].data.p;
2851 if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
2852 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
2853 field = mono_class_get_field (klass, token);
2855 mono_store_remote_field (obj, klass, field, &sp [1].data);
2856 offset = field->offset;
2858 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2859 field = mono_field_from_memberref (image, token, NULL);
2861 field = mono_class_get_field (obj->vtable->klass, token);
2862 offset = field->offset;
2863 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
2867 obj = sp [0].data.vt.vt;
2868 field = mono_class_get_field (sp [0].data.vt.klass, token);
2869 offset = field->offset - sizeof (MonoObject);
2870 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
2876 CASE (CEE_LDSFLD) /* Fall through */
2877 CASE (CEE_LDSFLDA) {
2880 MonoClassField *field;
2882 int load_addr = *ip == CEE_LDSFLDA;
2886 token = read32 (ip);
2889 /* need to handle fieldrefs */
2890 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2891 field = mono_field_from_memberref (image, token, &klass);
2893 klass = mono_class_get (image,
2894 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2895 field = mono_class_get_field (klass, token);
2899 vt = mono_class_vtable (domain, klass);
2900 addr = (char*)(vt->data) + field->offset;
2905 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2907 vt_alloc (field->type, sp, FALSE);
2908 stackval_from_data (field->type, sp, addr, FALSE);
2916 MonoClassField *field;
2921 token = read32 (ip);
2925 /* need to handle fieldrefs */
2926 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2927 field = mono_field_from_memberref (image, token, &klass);
2929 klass = mono_class_get (image,
2930 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2931 field = mono_class_get_field (klass, token);
2935 vt = mono_class_vtable (domain, klass);
2936 addr = (char*)(vt->data) + field->offset;
2938 stackval_to_data (field->type, sp, addr, FALSE);
2945 vtklass = mono_class_get (image, read32 (ip));
2948 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2951 #if SIZEOF_VOID_P == 8
2952 CASE (CEE_CONV_OVF_I_UN)
2954 CASE (CEE_CONV_OVF_I8_UN) {
2955 switch (sp [-1].type) {
2957 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2958 THROW_EX (mono_get_exception_overflow (), ip);
2959 sp [-1].data.l = (guint64)sp [-1].data.f;
2966 /* Can't overflow */
2967 sp [-1].data.l = (guint64)sp [-1].data.i;
2970 sp [-1].data.l = (guint64)sp [-1].data.nati;
2973 sp [-1].type = VAL_I64;
2977 #if SIZEOF_VOID_P == 8
2978 CASE (CEE_CONV_OVF_U_UN)
2980 CASE (CEE_CONV_OVF_U8_UN) {
2981 switch (sp [-1].type) {
2983 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
2984 THROW_EX (mono_get_exception_overflow (), ip);
2985 sp [-1].data.l = (guint64)sp [-1].data.f;
2993 /* Can't overflow */
2994 sp [-1].data.l = (guint64)sp [-1].data.i;
2997 /* Can't overflow */
2998 sp [-1].data.l = (guint64)sp [-1].data.nati;
3001 sp [-1].type = VAL_I64;
3005 #if SIZEOF_VOID_P == 4
3006 CASE (CEE_CONV_OVF_I_UN)
3007 CASE (CEE_CONV_OVF_U_UN)
3009 CASE (CEE_CONV_OVF_I1_UN)
3010 CASE (CEE_CONV_OVF_I2_UN)
3011 CASE (CEE_CONV_OVF_I4_UN)
3012 CASE (CEE_CONV_OVF_U1_UN)
3013 CASE (CEE_CONV_OVF_U2_UN)
3014 CASE (CEE_CONV_OVF_U4_UN) {
3016 switch (sp [-1].type) {
3018 value = (guint64)sp [-1].data.f;
3021 value = (guint64)sp [-1].data.l;
3026 value = (guint64)sp [-1].data.i;
3029 value = (guint64)sp [-1].data.nati;
3033 case CEE_CONV_OVF_I1_UN:
3035 THROW_EX (mono_get_exception_overflow (), ip);
3036 sp [-1].data.i = value;
3037 sp [-1].type = VAL_I32;
3039 case CEE_CONV_OVF_I2_UN:
3041 THROW_EX (mono_get_exception_overflow (), ip);
3042 sp [-1].data.i = value;
3043 sp [-1].type = VAL_I32;
3045 #if SIZEOF_VOID_P == 4
3046 case CEE_CONV_OVF_I_UN: /* Fall through */
3048 case CEE_CONV_OVF_I4_UN:
3049 if (value > 2147483647)
3050 THROW_EX (mono_get_exception_overflow (), ip);
3051 sp [-1].data.i = value;
3052 sp [-1].type = VAL_I32;
3054 case CEE_CONV_OVF_U1_UN:
3056 THROW_EX (mono_get_exception_overflow (), ip);
3057 sp [-1].data.i = value;
3058 sp [-1].type = VAL_I32;
3060 case CEE_CONV_OVF_U2_UN:
3062 THROW_EX (mono_get_exception_overflow (), ip);
3063 sp [-1].data.i = value;
3064 sp [-1].type = VAL_I32;
3066 #if SIZEOF_VOID_P == 4
3067 case CEE_CONV_OVF_U_UN: /* Fall through */
3069 case CEE_CONV_OVF_U4_UN:
3070 if (value > 4294967295U)
3071 THROW_EX (mono_get_exception_overflow (), ip);
3072 sp [-1].data.i = value;
3073 sp [-1].type = VAL_I32;
3076 g_assert_not_reached ();
3086 token = read32 (ip);
3088 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3089 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3091 class = mono_class_get (image, token);
3092 g_assert (class != NULL);
3094 sp [-1].type = VAL_OBJ;
3095 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3096 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3098 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3099 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3101 /* need to vt_free (sp); */
3113 token = read32 (ip);
3115 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3116 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3118 class = mono_class_get (image, token);
3120 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3123 sp [-1].type = VAL_OBJ;
3125 /*if (profiling_classes) {
3126 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3128 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3138 g_assert (sp [-1].type == VAL_OBJ);
3142 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3144 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3146 sp [-1].type = VAL_I32;
3147 sp [-1].data.i = mono_array_length (o);
3151 CASE (CEE_LDELEMA) {
3153 guint32 esize, token;
3156 token = read32 (ip);
3160 g_assert (sp [0].type == VAL_OBJ);
3163 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3165 if (sp [1].data.nati >= mono_array_length (o))
3166 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3168 /* check the array element corresponds to token */
3169 esize = mono_array_element_size (o->obj.vtable->klass);
3172 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
3173 sp->data.vt.klass = o->obj.vtable->klass->element_class;
3178 CASE (CEE_LDELEM_I1) /* fall through */
3179 CASE (CEE_LDELEM_U1) /* fall through */
3180 CASE (CEE_LDELEM_I2) /* fall through */
3181 CASE (CEE_LDELEM_U2) /* fall through */
3182 CASE (CEE_LDELEM_I4) /* fall through */
3183 CASE (CEE_LDELEM_U4) /* fall through */
3184 CASE (CEE_LDELEM_I8) /* fall through */
3185 CASE (CEE_LDELEM_I) /* fall through */
3186 CASE (CEE_LDELEM_R4) /* fall through */
3187 CASE (CEE_LDELEM_R8) /* fall through */
3188 CASE (CEE_LDELEM_REF) {
3194 g_assert (sp [0].type == VAL_OBJ);
3197 THROW_EX (mono_get_exception_null_reference (), ip);
3199 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3201 aindex = sp [1].data.nati;
3202 if (aindex >= mono_array_length (o))
3203 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3206 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3210 sp [0].data.i = mono_array_get (o, gint8, aindex);
3211 sp [0].type = VAL_I32;
3214 sp [0].data.i = mono_array_get (o, guint8, aindex);
3215 sp [0].type = VAL_I32;
3218 sp [0].data.i = mono_array_get (o, gint16, aindex);
3219 sp [0].type = VAL_I32;
3222 sp [0].data.i = mono_array_get (o, guint16, aindex);
3223 sp [0].type = VAL_I32;
3226 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3227 sp [0].type = VAL_NATI;
3230 sp [0].data.i = mono_array_get (o, gint32, aindex);
3231 sp [0].type = VAL_I32;
3234 sp [0].data.i = mono_array_get (o, guint32, aindex);
3235 sp [0].type = VAL_I32;
3238 sp [0].data.l = mono_array_get (o, guint64, aindex);
3239 sp [0].type = VAL_I64;
3242 sp [0].data.f = mono_array_get (o, float, aindex);
3243 sp [0].type = VAL_DOUBLE;
3246 sp [0].data.f = mono_array_get (o, double, aindex);
3247 sp [0].type = VAL_DOUBLE;
3249 case CEE_LDELEM_REF:
3250 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3251 sp [0].data.vt.klass = NULL;
3252 sp [0].type = VAL_OBJ;
3262 CASE (CEE_STELEM_I) /* fall through */
3263 CASE (CEE_STELEM_I1) /* fall through */
3264 CASE (CEE_STELEM_I2) /* fall through */
3265 CASE (CEE_STELEM_I4) /* fall through */
3266 CASE (CEE_STELEM_I8) /* fall through */
3267 CASE (CEE_STELEM_R4) /* fall through */
3268 CASE (CEE_STELEM_R8) /* fall through */
3269 CASE (CEE_STELEM_REF) {
3276 g_assert (sp [0].type == VAL_OBJ);
3279 THROW_EX (mono_get_exception_null_reference (), ip);
3281 ac = o->obj.vtable->klass;
3282 g_assert (MONO_CLASS_IS_ARRAY (ac));
3284 aindex = sp [1].data.nati;
3285 if (aindex >= mono_array_length (o))
3286 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3289 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3293 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3296 mono_array_set (o, gint8, aindex, sp [2].data.i);
3299 mono_array_set (o, gint16, aindex, sp [2].data.i);
3302 mono_array_set (o, gint32, aindex, sp [2].data.i);
3305 mono_array_set (o, gint64, aindex, sp [2].data.l);
3308 mono_array_set (o, float, aindex, sp [2].data.f);
3311 mono_array_set (o, double, aindex, sp [2].data.f);
3313 case CEE_STELEM_REF:
3314 g_assert (sp [2].type == VAL_OBJ);
3315 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3339 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3340 CASE (CEE_CONV_OVF_I1)
3341 if (sp [-1].type == VAL_I32) {
3342 if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
3343 THROW_EX (mono_get_exception_overflow (), ip);
3344 sp [-1].data.i = (gint8)sp [-1].data.i;
3345 } else if (sp [-1].type == VAL_I64) {
3346 if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
3347 THROW_EX (mono_get_exception_overflow (), ip);
3348 sp [-1].data.i = (gint8)sp [-1].data.l;
3354 CASE (CEE_CONV_OVF_U1)
3355 if (sp [-1].type == VAL_I32) {
3356 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3357 THROW_EX (mono_get_exception_overflow (), ip);
3358 sp [-1].data.i = (gint8)sp [-1].data.i;
3359 } else if (sp [-1].type == VAL_I64) {
3360 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3361 THROW_EX (mono_get_exception_overflow (), ip);
3362 sp [-1].data.i = (gint8)sp [-1].data.l;
3368 CASE (CEE_CONV_OVF_I2)
3369 CASE (CEE_CONV_OVF_U2)
3371 /* FIXME: handle other cases */
3372 if (sp [-1].type == VAL_I32) {
3373 /* defined as NOP */
3378 CASE (CEE_CONV_OVF_I4)
3379 /* FIXME: handle other cases */
3380 if (sp [-1].type == VAL_I32) {
3381 /* defined as NOP */
3382 } else if(sp [-1].type == VAL_I64) {
3383 sp [-1].data.i = (gint32)sp [-1].data.l;
3384 sp [-1].type = VAL_I32;
3390 CASE (CEE_CONV_OVF_U4)
3391 /* FIXME: handle other cases */
3392 if (sp [-1].type == VAL_I32) {
3393 /* defined as NOP */
3394 } else if(sp [-1].type == VAL_I64) {
3395 sp [-1].data.i = (guint32)sp [-1].data.l;
3396 sp [-1].type = VAL_I32;
3402 CASE (CEE_CONV_OVF_I8)
3403 /* FIXME: handle other cases */
3404 if (sp [-1].type == VAL_I32) {
3405 sp [-1].data.l = (guint64)sp [-1].data.i;
3406 sp [-1].type = VAL_I64;
3407 } else if(sp [-1].type == VAL_I64) {
3408 /* defined as NOP */
3414 CASE (CEE_CONV_OVF_U8)
3415 /* FIXME: handle other cases */
3416 if (sp [-1].type == VAL_I32) {
3417 sp [-1].data.l = (guint64) sp [-1].data.i;
3418 sp [-1].type = VAL_I64;
3419 } else if(sp [-1].type == VAL_I64) {
3420 /* defined as NOP */
3432 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3433 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3435 if (!finite(sp [-1].data.f))
3436 THROW_EX (mono_get_exception_arithmetic (), ip);
3439 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3440 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3441 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3450 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3451 CASE (CEE_LDTOKEN) {
3453 MonoClass *handle_class;
3455 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3457 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3458 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3462 CASE (CEE_CONV_OVF_I)
3465 /* FIXME: check overflow. */
3468 sp->data.p = (gpointer)(mono_i) sp->data.i;
3471 sp->data.p = (gpointer)(mono_i) sp->data.l;
3476 sp->data.p = (gpointer)(mono_i) sp->data.f;
3481 sp->type = VAL_NATI;
3484 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
3487 /* FIXME: check overflow */
3488 if (sp->type == VAL_I32) {
3489 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3490 THROW_EX (mono_get_exception_overflow (), ip);
3491 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)GET_NATI (sp [0]);
3492 } else if (sp->type == VAL_I64) {
3493 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3494 THROW_EX (mono_get_exception_overflow (), ip);
3495 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3496 } else if (sp->type == VAL_DOUBLE)
3497 sp [-1].data.f += sp [0].data.f;
3499 char *p = sp [-1].data.p;
3500 p += GET_NATI (sp [0]);
3505 CASE (CEE_ADD_OVF_UN)
3507 /* FIXME: check overflow, make unsigned */
3508 if (sp->type == VAL_I32) {
3509 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3510 THROW_EX (mono_get_exception_overflow (), ip);
3511 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3512 } else if (sp->type == VAL_I64) {
3513 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3514 THROW_EX (mono_get_exception_overflow (), ip);
3515 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3516 } else if (sp->type == VAL_DOUBLE)
3517 sp [-1].data.f += sp [0].data.f;
3519 char *p = sp [-1].data.p;
3520 p += GET_NATI (sp [0]);
3528 /* FIXME: check overflow */
3529 if (sp->type == VAL_I32) {
3530 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3531 THROW_EX (mono_get_exception_overflow (), ip);
3532 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3534 else if (sp->type == VAL_I64) {
3535 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3536 THROW_EX (mono_get_exception_overflow (), ip);
3537 sp [-1].data.l *= sp [0].data.l;
3539 else if (sp->type == VAL_DOUBLE)
3540 sp [-1].data.f *= sp [0].data.f;
3542 CASE (CEE_MUL_OVF_UN)
3545 /* FIXME: check overflow, make unsigned */
3546 if (sp->type == VAL_I32) {
3547 if (CHECK_MUL_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3548 THROW_EX (mono_get_exception_overflow (), ip);
3549 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3551 else if (sp->type == VAL_I64) {
3552 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3553 THROW_EX (mono_get_exception_overflow (), ip);
3554 sp [-1].data.l *= sp [0].data.l;
3556 else if (sp->type == VAL_DOUBLE)
3557 sp [-1].data.f *= sp [0].data.f;
3560 CASE (CEE_SUB_OVF_UN)
3563 /* FIXME: handle undeflow/unsigned */
3564 /* should probably consider the pointers as unsigned */
3565 if (sp->type == VAL_I32)
3566 sp [-1].data.i -= GET_NATI (sp [0]);
3567 else if (sp->type == VAL_I64)
3568 sp [-1].data.l -= sp [0].data.l;
3569 else if (sp->type == VAL_DOUBLE)
3570 sp [-1].data.f -= sp [0].data.f;
3572 char *p = sp [-1].data.p;
3573 p -= GET_NATI (sp [0]);
3577 CASE (CEE_ENDFINALLY)
3579 ip = finally_ips->data;
3580 finally_ips = g_slist_remove (finally_ips, ip);
3586 * There was no exception, we continue normally at the target address.
3590 CASE (CEE_LEAVE) /* Fall through */
3592 sp = frame->stack; /* empty the stack */
3594 if (*ip == CEE_LEAVE_S) {
3596 ip += (signed char) *ip;
3600 ip += (gint32) read32 (ip);
3605 * We may be either inside a try block or inside an handler.
3606 * In the first case there was no exception and we go on
3607 * executing the finally handlers and after that resume control
3609 * In the second case we need to clear the exception and
3610 * continue directly at the target ip.
3614 goto handle_finally;
3617 frame->ex_handler = NULL;
3621 frame->ex_handler = NULL;
3623 goto handle_finally;
3629 case CEE_MONO_FUNC1: {
3630 MonoMarshalConv conv;
3640 sp->data.vt.klass = NULL;
3643 case MONO_MARSHAL_CONV_STR_LPWSTR:
3644 sp->data.p = mono_string_to_utf16 (sp->data.p);
3646 case MONO_MARSHAL_CONV_LPSTR_STR:
3647 sp->data.p = mono_string_new_wrapper (sp->data.p);
3649 case MONO_MARSHAL_CONV_STR_LPTSTR:
3650 case MONO_MARSHAL_CONV_STR_LPSTR:
3651 sp->data.p = mono_string_to_utf8 (sp->data.p);
3653 case MONO_MARSHAL_CONV_STR_BSTR:
3654 sp->data.p = mono_string_to_bstr (sp->data.p);
3656 case MONO_MARSHAL_CONV_STR_TBSTR:
3657 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3658 sp->data.p = mono_string_to_ansibstr (sp->data.p);
3660 case MONO_MARSHAL_CONV_SB_LPSTR:
3661 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
3663 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3664 sp->data.p = mono_array_to_savearray (sp->data.p);
3666 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3667 sp->data.p = mono_array_to_lparray (sp->data.p);
3669 case MONO_MARSHAL_CONV_DEL_FTN:
3670 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
3672 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3673 sp->data.p = mono_marshal_string_array (sp->data.p);
3676 g_assert_not_reached ();
3681 case CEE_MONO_PROC2: {
3682 MonoMarshalConv conv;
3690 case MONO_MARSHAL_CONV_LPSTR_SB:
3691 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
3693 case MONO_MARSHAL_FREE_ARRAY:
3694 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
3697 g_assert_not_reached ();
3701 case CEE_MONO_PROC3: {
3702 MonoMarshalConv conv;
3710 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3711 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3713 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3714 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3717 g_assert_not_reached ();
3721 case CEE_MONO_VTADDR: {
3724 sp->type = VAL_VALUETA;
3728 case CEE_MONO_LDPTR: {
3732 token = read32 (ip);
3736 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
3737 sp->data.vt.klass = NULL;
3741 case CEE_MONO_FREE: {
3745 g_free (sp->data.p);
3748 case CEE_MONO_OBJADDR: {
3755 case CEE_MONO_NEWOBJ: {
3760 token = read32 (ip);
3763 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3764 sp->data.p = mono_object_new (domain, class);
3768 case CEE_MONO_RETOBJ: {
3773 token = read32 (ip);
3778 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3780 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt, signature->pinvoke);
3782 if (sp > frame->stack)
3783 g_warning ("more values on stack: %d", sp-frame->stack);
3788 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
3819 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3821 * Note: Exceptions thrown when executing a prefixed opcode need
3822 * to take into account the number of prefix bytes (usually the
3823 * throw point is just (ip - n_prefix_bytes).
3828 case CEE_ARGLIST: ves_abort(); break;
3834 if (sp->type == VAL_I32)
3835 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3836 else if (sp->type == VAL_I64)
3837 result = sp [0].data.l == sp [1].data.l;
3838 else if (sp->type == VAL_DOUBLE) {
3839 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3842 result = sp [0].data.f == sp [1].data.f;
3844 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3846 sp->data.i = result;
3856 if (sp->type == VAL_I32)
3857 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3858 else if (sp->type == VAL_I64)
3859 result = sp [0].data.l > sp [1].data.l;
3860 else if (sp->type == VAL_DOUBLE) {
3861 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3864 result = sp [0].data.f > sp [1].data.f;
3866 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3868 sp->data.i = result;
3878 if (sp->type == VAL_I32)
3879 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3880 else if (sp->type == VAL_I64)
3881 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3882 else if (sp->type == VAL_DOUBLE)
3883 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3885 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3887 sp->data.i = result;
3897 if (sp->type == VAL_I32)
3898 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3899 else if (sp->type == VAL_I64)
3900 result = sp [0].data.l < sp [1].data.l;
3901 else if (sp->type == VAL_DOUBLE) {
3902 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3905 result = sp [0].data.f < sp [1].data.f;
3907 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3909 sp->data.i = result;
3919 if (sp->type == VAL_I32)
3920 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3921 else if (sp->type == VAL_I64)
3922 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3923 else if (sp->type == VAL_DOUBLE)
3924 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3926 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3928 sp->data.i = result;
3934 case CEE_LDVIRTFTN: {
3935 int virtual = *ip == CEE_LDVIRTFTN;
3939 token = read32 (ip);
3942 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3943 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
3945 m = mono_get_method (image, token, NULL);
3948 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3952 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3954 m = get_virtual_method (domain, m, sp);
3956 sp->type = VAL_NATI;
3957 sp->data.p = mono_create_method_pointer (m);
3958 sp->data.vt.klass = NULL;
3962 case CEE_UNUSED56: ves_abort(); break;
3966 arg_pos = read16 (ip);
3968 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
3969 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
3981 t = ARG_TYPE (signature, anum);
3982 c = mono_class_from_mono_type (t);
3983 sp->data.vt.klass = c;
3984 sp->data.vt.vt = ARG_POS (anum);
3987 sp->type = VAL_VALUETA;
3997 arg_pos = read16 (ip);
4000 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4007 loc_pos = read16 (ip);
4009 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4010 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4020 loc_pos = read16 (ip);
4022 t = LOCAL_TYPE (header, loc_pos);
4023 c = mono_class_from_mono_type (t);
4024 sp->data.vt.vt = LOCAL_POS (loc_pos);
4025 sp->data.vt.klass = c;
4028 sp->type = VAL_VALUETA;
4038 loc_pos = read16 (ip);
4041 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4047 if (sp != frame->stack)
4048 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4050 sp->data.p = alloca (sp->data.i);
4054 case CEE_UNUSED57: ves_abort(); break;
4055 case CEE_ENDFILTER: ves_abort(); break;
4056 case CEE_UNALIGNED_:
4058 unaligned_address = 1;
4062 volatile_address = 1;
4071 token = read32 (ip);
4074 * we ignore the value of token (I think we can as unspecified
4075 * behavior described in Partition II, 3.5).
4078 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
4079 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
4082 case CEE_UNUSED68: ves_abort(); break;
4085 if (!sp [0].data.p || !sp [1].data.p)
4086 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4088 /* FIXME: value and size may be int64... */
4089 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4094 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4096 /* FIXME: value and size may be int64... */
4097 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4099 case CEE_UNUSED69: ves_abort(); break;
4102 * need to clarify what this should actually do:
4103 * start the search from the last found handler in
4104 * this method or continue in the caller or what.
4105 * Also, do we need to run finally/fault handlers after a retrow?
4106 * Well, this implementation will follow the usual search
4107 * for an handler, considering the current ip as throw spot.
4108 * We need to NULL frame->ex_handler for the later code to
4109 * actually run the new found handler.
4111 frame->ex_handler = NULL;
4112 THROW_EX (frame->ex, ip - 1);
4114 case CEE_UNUSED: ves_abort(); break;
4119 token = read32 (ip);
4121 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4122 MonoType *type = mono_type_create_from_typespec (image, token);
4123 sp->data.i = mono_type_size (type, &align);
4124 mono_metadata_free_type (type);
4126 MonoClass *szclass = mono_class_get (image, token);
4127 mono_class_init (szclass);
4128 if (!szclass->valuetype)
4129 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4130 sp->data.i = mono_class_value_size (szclass, &align);
4136 case CEE_REFANYTYPE: ves_abort(); break;
4143 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4150 g_assert_not_reached ();
4152 * Exception handling code.
4153 * The exception object is stored in frame->ex.
4160 MonoInvocation *inv;
4161 MonoMethodHeader *hd;
4162 MonoExceptionClause *clause;
4168 g_print ("* Handling exception '%s' at IL_%04x\n", mono_object_class (frame->ex)->name, frame->ip - header->code);
4170 if (die_on_exception)
4173 for (inv = frame; inv; inv = inv->parent) {
4174 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4176 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4178 hd = ((MonoMethodNormal*)inv->method)->header;
4179 ip_offset = inv->ip - hd->code;
4180 for (i = 0; i < hd->num_clauses; ++i) {
4181 clause = &hd->clauses [i];
4182 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4183 if (!clause->flags) {
4184 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4186 * OK, we found an handler, now we need to execute the finally
4187 * and fault blocks before branching to the handler code.
4189 inv->ex_handler = clause;
4192 g_print ("* Found handler at '%s'\n", inv->method->name);
4195 * It seems that if the catch handler is found in the same method,
4196 * it gets executed before the finally handler.
4201 goto handle_finally;
4204 /* FIXME: handle filter clauses */
4211 * If we get here, no handler was found: print a stack trace.
4213 for (inv = frame; inv; inv = inv->parent) {
4214 if (inv->invoke_trap)
4215 goto handle_finally;
4218 ex_obj = (MonoObject*)frame->ex;
4219 mono_unhandled_exception (ex_obj);
4226 MonoExceptionClause *clause;
4230 g_print ("* Handle finally\n");
4232 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4233 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4237 ip_offset = frame->ip - header->code;
4239 for (i = 0; i < header->num_clauses; ++i) {
4240 clause = &header->clauses [i];
4241 if (clause == frame->ex_handler)
4243 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code))) {
4244 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4245 ip = header->code + clause->handler_offset;
4246 finally_ips = g_slist_append (finally_ips, ip);
4249 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4255 ip = finally_ips->data;
4256 finally_ips = g_slist_remove (finally_ips, ip);
4261 * If an exception is set, we need to execute the fault handler, too,
4262 * otherwise, we continue normally.
4273 MonoExceptionClause *clause;
4277 g_print ("* Handle fault\n");
4279 ip_offset = frame->ip - header->code;
4280 for (i = 0; i < header->num_clauses; ++i) {
4281 clause = &header->clauses [i];
4282 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4283 ip = header->code + clause->handler_offset;
4286 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4292 * If the handler for the exception was found in this method, we jump
4293 * to it right away, otherwise we return and let the caller run
4294 * the finally, fault and catch blocks.
4295 * This same code should be present in the endfault opcode, but it
4296 * is corrently not assigned in the ECMA specs: LAMESPEC.
4298 if (frame->ex_handler) {
4301 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4303 ip = header->code + frame->ex_handler->handler_offset;
4306 sp->data.p = frame->ex;
4317 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4319 MonoImage *image = assembly->image;
4320 MonoCLIImageInfo *iinfo;
4322 MonoObject *exc = NULL;
4325 iinfo = image->image_info;
4326 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4328 g_error ("No entry point method found in %s", image->name);
4330 rval = mono_runtime_run_main (method, argc, argv, &exc);
4339 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4340 "Usage is: mint [options] executable args...\n\n", VERSION);
4342 "Runtime Debugging:\n"
4347 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4350 " --traceclassinit\n"
4353 " --debug method_name\n"
4359 " --config filename load the specified config file instead of the default\n"
4360 " --workers n maximum number of worker threads\n"
4367 test_load_class (MonoImage* image)
4369 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4373 for (i = 1; i <= t->rows; ++i) {
4374 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4375 mono_class_init (klass);
4380 static MonoException * segv_exception = NULL;
4383 segv_handler (int signum)
4385 signal (signum, segv_handler);
4386 mono_raise_exception (segv_exception);
4390 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4391 MonoReflectionMethod **method,
4392 gint32 *iloffset, gint32 *native_offset,
4393 MonoString **file, gint32 *line, gint32 *column)
4406 *file = mono_string_new (mono_domain_get (), "unknown");
4412 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4418 main (int argc, char *argv [])
4421 MonoAssembly *assembly;
4422 int retval = 0, i, ocount = 0;
4423 char *file, *error, *config_file = NULL;
4428 for (i = 1; i < argc && argv [i][0] == '-'; i++){
4429 if (strcmp (argv [i], "--trace") == 0)
4431 if (strcmp (argv [i], "--noptr") == 0)
4432 global_no_pointers = 1;
4433 if (strcmp (argv [i], "--traceops") == 0)
4435 if (strcmp (argv [i], "--dieonex") == 0)
4436 die_on_exception = 1;
4437 if (strcmp (argv [i], "--print-vtable") == 0)
4438 mono_print_vtable = TRUE;
4439 if (strcmp (argv [i], "--profile") == 0)
4440 mono_profiler_install_simple ();
4441 if (strcmp (argv [i], "--opcode-count") == 0)
4443 if (strcmp (argv [i], "--config") == 0)
4444 config_file = argv [++i];
4445 if (strcmp (argv [i], "--workers") == 0) {
4446 mono_worker_threads = atoi (argv [++i]);
4447 if (mono_worker_threads < 1)
4448 mono_worker_threads = 1;
4450 if (strcmp (argv [i], "--help") == 0)
4453 if (strcmp (argv [i], "--debug") == 0) {
4454 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
4456 g_error ("Invalid method name '%s'", argv [i]);
4457 db_methods = g_list_append (db_methods, desc);
4467 g_set_prgname (file);
4468 mono_set_rootdir ();
4469 mono_config_parse (config_file);
4471 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
4472 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
4475 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
4476 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
4478 frame_thread_id = TlsAlloc ();
4479 TlsSetValue (frame_thread_id, NULL);
4481 mono_install_compile_method (mono_create_method_pointer);
4482 mono_install_runtime_invoke (interp_mono_runtime_invoke);
4483 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
4485 mono_install_handler (interp_ex_handler);
4486 mono_install_stack_walk (interp_walk_stack);
4488 InitializeCriticalSection (&metadata_lock);
4489 domain = mono_init (file);
4490 mono_runtime_init (domain, NULL, NULL);
4492 assembly = mono_domain_assembly_open (domain, file);
4495 fprintf (stderr, "Can not open image %s\n", file);
4501 test_load_class (assembly->image);
4503 error = mono_verify_corlib ();
4505 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
4508 segv_exception = mono_get_exception_null_reference ();
4509 segv_exception->message = mono_string_new (domain, "Segmentation fault");
4510 signal (SIGSEGV, segv_handler);
4512 retval = ves_exec (domain, assembly, argc - i, argv + i);
4514 mono_profiler_shutdown ();
4516 mono_runtime_cleanup (domain);
4517 mono_domain_unload (domain, TRUE);
4521 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4522 fprintf (stderr, "fcall count: %ld\n", fcall_count);