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/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/os/util.h>
61 /*#include <mono/cli/types.h>*/
65 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
68 #define finite _finite
71 /* If true, then we output the opcodes as we interpret them */
72 static int global_tracing = 0;
73 static int global_no_pointers = 0;
75 static int debug_indent_level = 0;
78 * Pull the list of opcodes
80 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
84 #include "mono/cil/opcode.def"
89 #define GET_NATI(sp) ((sp).data.nati)
90 #define CSIZE(x) (sizeof (x) / 4)
92 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
94 (frame)->parent = (parent_frame); \
95 (frame)->obj = (obj_this); \
96 (frame)->stack_args = (method_args); \
97 (frame)->retval = (method_retval); \
98 (frame)->method = (mono_method); \
99 (frame)->ex_handler = NULL; \
100 (frame)->ex = NULL; \
101 (frame)->child = NULL; \
102 (frame)->invoke_trap = 0; \
105 void ves_exec_method (MonoInvocation *frame);
107 typedef void (*ICallMethod) (MonoInvocation *frame);
109 static guint32 die_on_exception = 0;
110 static guint32 frame_thread_id = 0;
112 #define DEBUG_INTERP 1
115 static unsigned long opcode_count = 0;
116 static unsigned long fcall_count = 0;
117 static int break_on_method = 0;
118 static GList *db_methods = NULL;
125 for (h = 0; h < debug_indent_level; h++)
130 db_match_method (gpointer data, gpointer user_data)
132 MonoMethod *m = (MonoMethod*)user_data;
133 MonoMethodDesc *desc = data;
135 if (mono_method_desc_full_match (desc, m))
139 #define DEBUG_ENTER() \
141 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
142 if (break_on_method) tracing=2; \
143 break_on_method = 0; \
145 char *mn, *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
146 debug_indent_level++; \
148 mn = mono_method_full_name (frame->method, FALSE); \
149 g_print ("(%d) Entering %s (", GetCurrentThreadId(), mn); \
151 if (signature->hasthis) { \
152 if (global_no_pointers) { \
153 g_print ("this%s ", frame->obj ? "" : "=null"); \
155 g_print ("%p ", frame->obj); } \
157 g_print ("%s)\n", args); \
160 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
161 mono_profiler_method_enter (frame->method);
163 #define DEBUG_LEAVE() \
166 if (signature->ret->type != MONO_TYPE_VOID) \
167 args = dump_stack (frame->retval, frame->retval + 1); \
169 args = g_strdup (""); \
171 mn = mono_method_full_name (frame->method, FALSE); \
172 g_print ("(%d) Leaving %s", GetCurrentThreadId(), mn); \
174 g_print (" => %s\n", args); \
176 debug_indent_level--; \
178 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
179 mono_profiler_method_leave (frame->method);
183 #define DEBUG_ENTER()
184 #define DEBUG_LEAVE()
189 interp_ex_handler (MonoException *ex) {
190 MonoInvocation *frame = TlsGetValue (frame_thread_id);
192 longjmp (*(jmp_buf*)frame->locals, 1);
196 ves_real_abort (int line, MonoMethod *mh,
197 const unsigned char *ip, stackval *stack, stackval *sp)
199 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
200 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
201 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
202 ip-mm->header->code);
203 g_print ("0x%04x %02x\n",
204 ip-mm->header->code, *ip);
206 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
208 #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);
211 interp_create_remoting_trampoline (MonoMethod *method)
213 return mono_marshal_get_remoting_invoke (method);
217 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
222 gboolean is_proxy = FALSE;
225 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
229 if ((klass = obj->vtable->klass) == mono_defaults.transparent_proxy_class) {
230 klass = ((MonoTransparentProxy *)obj)->klass;
233 vtable = (MonoMethod **)klass->vtable;
235 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
236 res = ((MonoMethod **)obj->vtable->interface_offsets [m->klass->interface_id]) [m->slot];
238 res = vtable [m->slot];
243 return mono_marshal_get_remoting_invoke (res);
249 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
252 switch (type->type) {
253 case MONO_TYPE_OBJECT:
254 case MONO_TYPE_CLASS:
255 case MONO_TYPE_STRING:
256 case MONO_TYPE_ARRAY:
257 case MONO_TYPE_SZARRAY:
258 result->type = VAL_OBJ;
261 result->type = VAL_VALUETA;
264 result->data.p = *(gpointer*)data;
265 result->data.vt.klass = mono_class_from_mono_type (type);
268 switch (type->type) {
272 result->type = VAL_I32;
273 result->data.i = *(gint8*)data;
276 case MONO_TYPE_BOOLEAN:
277 result->type = VAL_I32;
278 result->data.i = *(guint8*)data;
281 result->type = VAL_I32;
282 result->data.i = *(gint16*)data;
286 result->type = VAL_I32;
287 result->data.i = *(guint16*)data;
290 result->type = VAL_I32;
291 result->data.i = *(gint32*)data;
296 result->type = VAL_TP;
297 result->data.p = *(gpointer*)data;
300 result->type = VAL_I32;
301 result->data.i = *(guint32*)data;
304 result->type = VAL_DOUBLE;
305 result->data.f = *(float*)data;
309 result->type = VAL_I64;
310 result->data.l = *(gint64*)data;
313 result->type = VAL_DOUBLE;
314 result->data.f = *(double*)data;
316 case MONO_TYPE_STRING:
317 case MONO_TYPE_SZARRAY:
318 case MONO_TYPE_CLASS:
319 case MONO_TYPE_OBJECT:
320 case MONO_TYPE_ARRAY:
321 result->type = VAL_OBJ;
322 result->data.p = *(gpointer*)data;
323 result->data.vt.klass = mono_class_from_mono_type (type);
325 case MONO_TYPE_VALUETYPE:
326 if (type->data.klass->enumtype) {
327 return stackval_from_data (type->data.klass->enum_basetype, result, data, pinvoke);
330 result->type = VAL_VALUET;
331 result->data.vt.klass = type->data.klass;
334 size = mono_class_native_size (type->data.klass, NULL);
336 size = mono_class_value_size (type->data.klass, NULL);
337 memcpy (result->data.vt.vt, data, size);
341 g_warning ("got type 0x%02x", type->type);
342 g_assert_not_reached ();
347 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
350 gpointer *p = (gpointer*)data;
354 //printf ("TODAT0 %p\n", data);
355 switch (type->type) {
358 guint8 *p = (guint8*)data;
362 case MONO_TYPE_BOOLEAN: {
363 guint8 *p = (guint8*)data;
364 *p = (val->data.i != 0);
369 case MONO_TYPE_CHAR: {
370 guint16 *p = (guint16*)data;
374 #if SIZEOF_VOID_P == 4
380 gint32 *p = (gint32*)data;
384 #if SIZEOF_VOID_P == 8
390 gint64 *p = (gint64*)data;
395 float *p = (float*)data;
400 double *p = (double*)data;
404 case MONO_TYPE_STRING:
405 case MONO_TYPE_SZARRAY:
406 case MONO_TYPE_CLASS:
407 case MONO_TYPE_OBJECT:
408 case MONO_TYPE_ARRAY:
409 case MONO_TYPE_PTR: {
410 gpointer *p = (gpointer*)data;
414 case MONO_TYPE_VALUETYPE:
415 if (type->data.klass->enumtype) {
416 return stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
421 size = mono_class_native_size (type->data.klass, NULL);
423 size = mono_class_value_size (type->data.klass, NULL);
425 memcpy (data, val->data.vt.vt, size);
429 g_warning ("got type %x", type->type);
430 g_assert_not_reached ();
435 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
438 guint32 *lower_bounds;
441 lengths = alloca (sizeof (guint32) * klass->rank * 2);
442 for (i = 0; i < sig->param_count; ++i) {
443 lengths [i] = values->data.i;
446 if (klass->rank == sig->param_count) {
447 /* Only lengths provided. */
450 /* lower bounds are first. */
451 lower_bounds = lengths;
452 lengths += klass->rank;
454 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
458 ves_array_set (MonoInvocation *frame)
460 stackval *sp = frame->stack_args;
464 gint32 i, t, pos, esize;
470 ac = o->vtable->klass;
472 g_assert (ac->rank >= 1);
475 if (ao->bounds != NULL) {
476 pos -= ao->bounds [0].lower_bound;
477 for (i = 1; i < ac->rank; i++) {
478 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
479 ao->bounds [i].length) {
480 frame->ex = mono_get_exception_index_out_of_range ();
483 pos = pos*ao->bounds [i].length + sp [i].data.i -
484 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->params [ac->rank];
492 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
496 ves_array_get (MonoInvocation *frame)
498 stackval *sp = frame->stack_args;
502 gint32 i, t, pos, esize;
508 ac = o->vtable->klass;
510 g_assert (ac->rank >= 1);
513 if (ao->bounds != NULL) {
514 pos -= ao->bounds [0].lower_bound;
515 for (i = 1; i < ac->rank; i++) {
517 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
518 ao->bounds [i].length) {
519 frame->ex = mono_get_exception_index_out_of_range ();
523 pos = pos*ao->bounds [i].length + sp [i].data.i -
524 ao->bounds [i].lower_bound;
528 esize = mono_array_element_size (ac);
529 ea = mono_array_addr_with_size (ao, esize, pos);
531 mt = frame->method->signature->ret;
532 stackval_from_data (mt, frame->retval, ea, FALSE);
536 ves_array_element_address (MonoInvocation *frame)
538 stackval *sp = frame->stack_args;
542 gint32 i, pos, esize;
547 ac = o->vtable->klass;
549 g_assert (ac->rank >= 1);
552 if (ao->bounds != NULL) {
553 pos -= ao->bounds [0].lower_bound;
554 for (i = 1; i < ac->rank; i++)
555 pos = pos*ao->bounds [i].length + sp [i].data.i -
556 ao->bounds [i].lower_bound;
559 esize = mono_array_element_size (ac);
560 ea = mono_array_addr_with_size (ao, esize, pos);
562 frame->retval->type = VAL_TP;
563 frame->retval->data.p = ea;
567 interp_walk_stack (MonoStackWalk func, gpointer user_data)
569 MonoInvocation *frame = TlsGetValue (frame_thread_id);
571 MonoMethodHeader *hd;
574 gboolean managed = FALSE;
575 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
576 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
579 hd = ((MonoMethodNormal*)frame->method)->header;
580 il_offset = frame->ip - hd->code;
581 if (!frame->method->wrapper_type)
584 if (func (frame->method, -1, il_offset, managed, user_data))
586 frame = frame->parent;
591 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor)
597 TlsSetValue (frame_thread_id, frame->args);
602 if (!frame->method->info) {
603 func = frame->method->info = mono_create_trampoline (sig, string_ctor);
605 func = (MonoPIFunc)frame->method->info;
608 func = mono_create_trampoline (sig, string_ctor);
612 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
613 * locals will point to the jmp_buf, while args will point to the previous
614 * MonoInvocation frame: this is needed to make exception searching work across
615 * managed/unmanaged boundaries.
617 frame->locals = (char*)&env;
618 frame->args = (char*)TlsGetValue (frame_thread_id);
619 TlsSetValue (frame_thread_id, frame);
621 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
624 stackval_from_data (&mono_defaults.string_class->byval_arg,
625 frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
626 } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
627 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
629 TlsSetValue (frame_thread_id, frame->args);
634 * runtime specifies that the implementation of the method is automatically
635 * provided by the runtime and is primarily used for the methods of delegates.
638 ves_runtime_method (MonoInvocation *frame)
640 const char *name = frame->method->name;
641 MonoObject *obj = (MonoObject*)frame->obj;
642 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
647 mono_class_init (frame->method->klass);
649 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
650 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
651 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
654 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
661 code = (guchar*)delegate->delegate.method_ptr;
662 if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
664 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
665 ves_exec_method (&call);
670 g_assert_not_reached ();
673 delegate = delegate->prev;
677 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
678 nm = mono_marshal_get_delegate_begin_invoke (frame->method);
679 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
680 ves_exec_method (&call);
684 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
685 nm = mono_marshal_get_delegate_end_invoke (frame->method);
686 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
687 ves_exec_method (&call);
693 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
694 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
695 ves_array_set (frame);
698 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
699 ves_array_get (frame);
702 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
703 ves_array_element_address (frame);
708 g_error ("Don't know how to exec runtime method %s.%s::%s",
709 frame->method->klass->name_space, frame->method->klass->name,
710 frame->method->name);
714 dump_stack (stackval *stack, stackval *sp)
717 GString *str = g_string_new ("");
720 return g_string_free (str, FALSE);
724 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
725 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
726 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
728 if (!global_no_pointers)
729 g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
731 g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
734 MonoObject *obj = s->data.p;
735 if (global_no_pointers && obj && obj->vtable) {
736 MonoClass *klass = mono_object_class (obj);
737 if (klass == mono_defaults.string_class) {
738 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
739 g_string_sprintfa (str, "[str:%s] ", utf8);
742 } else if (klass == mono_defaults.sbyte_class) {
743 g_string_sprintfa (str, "[b:%d] ",
744 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
746 } else if (klass == mono_defaults.int16_class) {
747 g_string_sprintfa (str, "[b:%d] ",
748 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
750 } else if (klass == mono_defaults.int32_class) {
751 g_string_sprintfa (str, "[b:%d] ",
752 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
754 } else if (klass == mono_defaults.byte_class) {
755 g_string_sprintfa (str, "[b:%u] ",
756 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
758 } else if (klass == mono_defaults.char_class
759 || klass == mono_defaults.uint16_class) {
760 g_string_sprintfa (str, "[b:%u] ",
761 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
763 } else if (klass == mono_defaults.uint32_class) {
764 g_string_sprintfa (str, "[b:%u] ",
765 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
767 } else if (klass == mono_defaults.int64_class) {
768 g_string_sprintfa (str, "[b:%lld] ",
769 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
771 } else if (klass == mono_defaults.uint64_class) {
772 g_string_sprintfa (str, "[b:%llu] ",
773 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
775 } else if (klass == mono_defaults.double_class) {
776 g_string_sprintfa (str, "[b:%0.5f] ",
777 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
779 } else if (klass == mono_defaults.single_class) {
780 g_string_sprintfa (str, "[b:%0.5f] ",
781 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
783 } else if (klass == mono_defaults.boolean_class) {
784 g_string_sprintfa (str, "[b:%s] ",
785 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
793 if (!global_no_pointers)
794 g_string_sprintfa (str, "[%p] ", s->data.p);
796 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
801 return g_string_free (str, FALSE);
805 dump_frame (MonoInvocation *inv)
807 GString *str = g_string_new ("");
810 for (i = 0; inv; inv = inv->parent, ++i) {
811 MonoClass *k = inv->method->klass;
814 gchar *source = NULL;
815 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
816 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
820 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
823 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
826 opname = mono_opcode_names [codep];
827 codep = inv->ip - hd->code;
829 source = mono_debug_source_location_from_il_offset (inv->method, codep, NULL);
831 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
833 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s) at %s\n", i, codep, opname,
834 k->name_space, k->name, inv->method->name, args, source);
836 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
837 k->name_space, k->name, inv->method->name, args);
841 return g_string_free (str, FALSE);
845 INLINE_STRING_LENGTH = 1,
848 INLINE_TYPE_ELEMENT_TYPE
852 calc_offsets (MonoImage *image, MonoMethod *method)
854 int i, align, size, offset = 0;
855 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
856 MonoMethodSignature *signature = method->signature;
857 int hasthis = signature->hasthis;
858 register const unsigned char *ip, *end;
859 const MonoOpcode *opcode;
863 MonoDomain *domain = mono_domain_get ();
866 mono_profiler_method_jit (method); /* sort of... */
867 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
868 for (i = 0; i < header->num_locals; ++i) {
869 size = mono_type_size (header->locals [i], &align);
871 offset &= ~(align - 1);
872 offsets [2 + i] = offset;
875 offsets [0] = offset;
878 offset += sizeof (gpointer) - 1;
879 offset &= ~(sizeof (gpointer) - 1);
880 offsets [2 + header->num_locals] = offset;
881 offset += sizeof (gpointer);
883 for (i = 0; i < signature->param_count; ++i) {
884 if (signature->pinvoke)
885 size = mono_type_native_stack_size (signature->params [i], &align);
887 size = mono_type_stack_size (signature->params [i], &align);
889 offset &= ~(align - 1);
890 offsets [2 + hasthis + header->num_locals + i] = offset;
893 offsets [1] = offset;
895 /* FIXME: This might cause a deadlock with domain->lock */
896 EnterCriticalSection (metadata_section);
897 /* intern the strings in the method. */
899 end = ip + header->code_size;
906 opcode = &mono_opcodes [i];
907 switch (opcode->argument) {
911 case MonoInlineString:
912 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
916 if (method->wrapper_type == MONO_WRAPPER_NONE) {
917 class = mono_class_get (image, read32 (ip + 1));
918 mono_class_init (class);
919 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
920 mono_class_vtable (domain, class);
924 case MonoInlineField:
925 token = read32 (ip + 1);
926 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
927 mono_field_from_memberref (image, token, &class);
929 class = mono_class_get (image,
930 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
932 mono_class_init (class);
933 mono_class_vtable (domain, class);
936 case MonoInlineMethod:
937 if (method->wrapper_type == MONO_WRAPPER_NONE) {
938 m = mono_get_method (image, read32 (ip + 1), NULL);
939 mono_class_init (m->klass);
940 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
941 mono_class_vtable (domain, m->klass);
947 case MonoShortInlineR:
949 case MonoInlineBrTarget:
955 case MonoShortInlineVar:
956 case MonoShortInlineI:
957 case MonoShortInlineBrTarget:
960 case MonoInlineSwitch: {
973 g_assert_not_reached ();
977 method->info = offsets;
980 * We store the inline info in addr, since it's unused for IL methods.
982 if (method->klass == mono_defaults.string_class) {
983 if (strcmp (method->name, "get_Length") == 0)
984 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
985 } else if (method->klass == mono_defaults.array_class) {
986 if (strcmp (method->name, "get_Length") == 0)
987 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
988 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
989 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
990 } else if (method->klass == mono_defaults.monotype_class) {
991 if (strcmp (method->name, "GetElementType") == 0)
992 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
994 LeaveCriticalSection (metadata_section);
995 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
998 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
999 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1001 #define ARG_POS(n) (args_pointers [(n)])
1002 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1003 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1005 #define THROW_EX(exception,ex_ip) \
1007 char *stack_trace; \
1008 frame->ip = (ex_ip); \
1009 stack_trace = dump_frame (frame); \
1010 frame->ex = (MonoException*)(exception); \
1011 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
1012 g_free (stack_trace); \
1013 goto handle_exception; \
1016 typedef struct _vtallocation vtallocation;
1018 struct _vtallocation {
1021 char data [MONO_ZERO_LEN_ARRAY];
1024 #define vt_alloc(vtype,sp,native) \
1025 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1026 if (!(vtype)->byref) { \
1029 vtallocation *tmp, *prev; \
1030 if (native) size = mono_class_native_size ((vtype)->data.klass, &align); \
1031 else size = mono_class_value_size ((vtype)->data.klass, &align); \
1034 while (tmp && (tmp->size < size)) { \
1039 tmp = alloca (sizeof (vtallocation) + size); \
1041 g_assert (size < 10000); \
1045 prev->next = tmp->next; \
1047 vtalloc = tmp->next; \
1048 (sp)->data.vt.vt = tmp->data; \
1050 (sp)->data.vt.klass = (vtype)->data.klass; \
1054 #define vt_free(sp) \
1056 if ((sp)->type == VAL_VALUET) { \
1057 vtallocation *tmp = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
1058 tmp->next = vtalloc; \
1065 verify_method (MonoMethod *m)
1067 GSList *errors, *tmp;
1068 MonoVerifyInfo *info;
1070 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1072 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1073 for (tmp = errors; tmp; tmp = tmp->next) {
1075 g_print ("%s\n", info->message);
1079 mono_free_verify_list (errors);
1083 #define MYGUINT64_MAX 18446744073709551615ULL
1084 #define MYGINT64_MAX 9223372036854775807LL
1085 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1087 #define MYGUINT32_MAX 4294967295U
1088 #define MYGINT32_MAX 2147483647
1089 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1091 #define CHECK_ADD_OVERFLOW(a,b) \
1092 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1093 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1095 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1096 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1098 #define CHECK_ADD_OVERFLOW64(a,b) \
1099 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1100 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1102 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1103 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1105 /* Resolves to TRUE if the operands would overflow */
1106 #define CHECK_MUL_OVERFLOW(a,b) \
1107 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1108 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1109 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1110 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1111 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1112 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1113 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1115 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1116 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1117 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1119 #define CHECK_MUL_OVERFLOW(a,b) \
1120 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1121 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1122 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1123 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1124 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1125 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1126 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1128 #define CHECK_MUL_OVERFLOW64(a,b) \
1129 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1130 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1131 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1132 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1133 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1134 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1135 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1137 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1138 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1139 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1142 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1144 MonoInvocation frame, *parent;
1145 MonoObject *retval = NULL;
1146 MonoMethodSignature *sig = method->signature;
1147 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1148 int i, type, isobject = 0;
1151 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1153 /* FIXME: Set frame for execption handling. */
1155 switch (sig->ret->type) {
1156 case MONO_TYPE_VOID:
1158 case MONO_TYPE_STRING:
1159 case MONO_TYPE_OBJECT:
1160 case MONO_TYPE_CLASS:
1161 case MONO_TYPE_ARRAY:
1162 case MONO_TYPE_SZARRAY:
1165 case MONO_TYPE_VALUETYPE:
1166 retval = mono_object_new (mono_domain_get (), klass);
1167 ret = ((char*)retval) + sizeof (MonoObject);
1168 if (!sig->ret->data.klass->enumtype)
1169 result.data.vt.vt = ret;
1172 retval = mono_object_new (mono_domain_get (), klass);
1173 ret = ((char*)retval) + sizeof (MonoObject);
1177 for (i = 0; i < sig->param_count; ++i) {
1178 if (sig->params [i]->byref) {
1179 args [i].type = VAL_POINTER;
1180 args [i].data.p = params [i];
1183 type = sig->params [i]->type;
1188 case MONO_TYPE_BOOLEAN:
1189 args [i].type = VAL_I32;
1190 args [i].data.i = *(MonoBoolean*)params [i];
1191 args [i].data.vt.klass = NULL;
1195 case MONO_TYPE_CHAR:
1196 args [i].type = VAL_I32;
1197 args [i].data.i = *(gint16*)params [i];
1198 args [i].data.vt.klass = NULL;
1200 #if SIZEOF_VOID_P == 4
1201 case MONO_TYPE_U: /* use VAL_POINTER? */
1206 args [i].type = VAL_I32;
1207 args [i].data.i = *(gint32*)params [i];
1208 args [i].data.vt.klass = NULL;
1210 #if SIZEOF_VOID_P == 8
1216 args [i].type = VAL_I64;
1217 args [i].data.l = *(gint64*)params [i];
1218 args [i].data.vt.klass = NULL;
1220 case MONO_TYPE_VALUETYPE:
1221 if (sig->params [i]->data.klass->enumtype) {
1222 type = sig->params [i]->data.klass->enum_basetype->type;
1225 args [i].type = VAL_POINTER;
1226 args [i].data.p = params [i];
1227 args [i].data.vt.klass = NULL;
1230 case MONO_TYPE_STRING:
1231 case MONO_TYPE_CLASS:
1232 case MONO_TYPE_ARRAY:
1233 case MONO_TYPE_SZARRAY:
1234 case MONO_TYPE_OBJECT:
1235 args [i].type = VAL_OBJ;
1236 args [i].data.p = params [i];
1237 args [i].data.vt.klass = NULL;
1240 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1244 if (method->klass->valuetype)
1245 /* Unbox the instance, since valuetype methods expect an interior pointer. */
1246 obj = mono_object_unbox (obj);
1248 /* chain with managed parent if any */
1249 parent = TlsGetValue (frame_thread_id);
1250 INIT_FRAME(&frame,parent,obj,args,&result,method);
1252 frame.invoke_trap = 1;
1253 ves_exec_method (&frame);
1254 if (exc && frame.ex) {
1255 *exc = (MonoObject*) frame.ex;
1258 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1260 if (isobject || method->string_ctor)
1261 return result.data.p;
1262 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1267 * Need to optimize ALU ops when natural int == int32
1269 * IDEA: if we maintain a stack of ip, sp to be checked
1270 * in the return opcode, we could inline simple methods that don't
1271 * use the stack or local variables....
1273 * The {,.S} versions of many opcodes can/should be merged to reduce code
1278 ves_exec_method (MonoInvocation *frame)
1280 MonoDomain *domain = mono_domain_get ();
1281 MonoInvocation child_frame;
1282 MonoMethodHeader *header;
1283 MonoMethodSignature *signature;
1285 GSList *finally_ips = NULL;
1286 const unsigned char *endfinally_ip;
1287 register const unsigned char *ip;
1288 register stackval *sp = NULL;
1289 void **args_pointers;
1291 gint il_ins_count = -1;
1292 gint tracing = global_tracing;
1293 unsigned char tail_recursion = 0;
1294 unsigned char unaligned_address = 0;
1295 unsigned char volatile_address = 0;
1296 vtallocation *vtalloc = NULL;
1297 MonoVTable *method_class_vt;
1300 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1301 frame->method = mono_marshal_get_native_wrapper (frame->method);
1303 method_class_vt = mono_class_vtable (domain, frame->method->klass);
1304 if (!method_class_vt->initialized)
1305 mono_runtime_class_init (method_class_vt);
1306 signature = frame->method->signature;
1310 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1311 if (!frame->method->addr) {
1312 /* ugly, but needed by the iflags setting in loader.c */
1313 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1314 ves_runtime_method (frame);
1316 goto handle_exception;
1320 if (frame->method->addr) {
1321 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1322 goto handle_exception;
1325 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1326 frame->method->string_ctor);
1328 goto handle_exception;
1333 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1334 ves_runtime_method (frame);
1336 goto handle_exception;
1341 /*verify_method (frame->method);*/
1343 header = ((MonoMethodNormal *)frame->method)->header;
1344 image = frame->method->klass->image;
1346 if (!frame->method->info)
1347 calc_offsets (image, frame->method);
1348 offsets = frame->method->info;
1351 * with alloca we get the expected huge performance gain
1352 * stackval *stack = g_new0(stackval, header->max_stack);
1354 g_assert (header->max_stack < 10000);
1355 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1357 if (header->num_locals) {
1358 g_assert (offsets [0] < 10000);
1359 frame->locals = alloca (offsets [0]);
1361 * yes, we do it unconditionally, because it needs to be done for
1362 * some cases anyway and checking for that would be even slower.
1364 memset (frame->locals, 0, offsets [0]);
1367 * Copy args from stack_args to args.
1369 if (signature->param_count || signature->hasthis) {
1371 int has_this = signature->hasthis;
1373 g_assert (offsets [1] < 10000);
1374 frame->args = alloca (offsets [1]);
1375 g_assert ((signature->param_count + has_this) < 1000);
1376 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1379 this_arg = args_pointers [0] = frame->args;
1380 *this_arg = frame->obj;
1382 for (i = 0; i < signature->param_count; ++i) {
1383 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1384 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1388 child_frame.parent = frame;
1389 frame->child = &child_frame;
1396 * using while (ip < end) may result in a 15% performance drop,
1397 * but it may be useful for debug
1401 /*g_assert (sp >= stack);*/
1405 char *ins, *discode;
1406 if (sp > frame->stack) {
1407 ins = dump_stack (frame->stack, sp);
1409 ins = g_strdup ("");
1412 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1413 discode [strlen (discode) - 1] = 0; /* no \n */
1414 g_print ("(%d) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1418 if (il_ins_count > 0)
1419 if (!(--il_ins_count))
1429 G_BREAKPOINT (); /* this is not portable... */
1434 CASE (CEE_LDARG_3) {
1435 int n = (*ip)-CEE_LDARG_0;
1437 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1438 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1445 CASE (CEE_LDLOC_3) {
1446 int n = (*ip)-CEE_LDLOC_0;
1448 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1450 sp->data.i = *(gint32*) LOCAL_POS (n);
1454 vt_alloc (LOCAL_TYPE (header, n), sp, FALSE);
1455 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1463 CASE (CEE_STLOC_3) {
1464 int n = (*ip)-CEE_STLOC_0;
1467 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1468 gint32 *p = (gint32*)LOCAL_POS (n);
1472 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1479 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1480 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1484 CASE (CEE_LDARGA_S) {
1489 t = ARG_TYPE (signature, *ip);
1490 c = mono_class_from_mono_type (t);
1491 sp->data.vt.klass = c;
1492 sp->data.vt.vt = ARG_POS (*ip);
1495 sp->type = VAL_VALUETA;
1506 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1512 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1513 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1517 CASE (CEE_LDLOCA_S) {
1522 t = LOCAL_TYPE (header, *ip);
1523 c = mono_class_from_mono_type (t);
1524 sp->data.vt.klass = c;
1525 sp->data.p = LOCAL_POS (*ip);
1528 sp->type = VAL_VALUETA;
1539 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1547 sp->data.vt.klass = NULL;
1550 CASE (CEE_LDC_I4_M1)
1566 sp->data.i = (*ip) - CEE_LDC_I4_0;
1573 sp->data.i = *(const gint8 *)ip;
1580 sp->data.i = read32 (ip);
1587 sp->data.l = read64 (ip);
1594 sp->type = VAL_DOUBLE;
1603 sp->type = VAL_DOUBLE;
1604 readr8(ip, &sp->data.f);
1608 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1610 if (sp [-1].type == VAL_VALUET) {
1611 MonoClass *c = sp [-1].data.vt.klass;
1612 vt_alloc (&c->byval_arg, sp, FALSE);
1613 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt, FALSE);
1631 token = read32 (ip);
1634 child_frame.method = mono_get_method (image, token, NULL);
1635 if (!child_frame.method)
1636 THROW_EX (mono_get_exception_missing_method (), ip -5);
1642 CASE (CEE_CALLVIRT) /* Fall through */
1643 CASE (CEE_CALLI) /* Fall through */
1645 MonoMethodSignature *csignature;
1647 stackval *endsp = sp;
1649 int virtual = *ip == CEE_CALLVIRT;
1650 int calli = *ip == CEE_CALLI;
1651 unsigned char *code = NULL;
1654 * We ignore tail recursion for now.
1661 token = read32 (ip);
1667 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1668 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1669 child_frame.method = NULL;
1671 csignature = mono_metadata_parse_signature (image, token);
1672 if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
1673 child_frame.method = ji->method;
1675 g_assert_not_reached ();
1680 child_frame.method = mono_get_method (image, token, NULL);
1681 if (!child_frame.method)
1682 THROW_EX (mono_get_exception_missing_method (), ip -5);
1683 csignature = child_frame.method->signature;
1685 stackval *this_arg = &sp [-csignature->param_count-1];
1686 if (!this_arg->data.p)
1687 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1688 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1689 if (!child_frame.method)
1690 THROW_EX (mono_get_exception_missing_method (), ip -5);
1694 if (frame->method->wrapper_type == MONO_WRAPPER_NONE)
1695 if (child_frame.method && child_frame.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1696 child_frame.method = mono_marshal_get_synchronized_wrapper (child_frame.method);
1698 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1699 /* decrement by the actual number of args */
1700 if (csignature->param_count) {
1701 sp -= csignature->param_count;
1702 child_frame.stack_args = sp;
1704 child_frame.stack_args = NULL;
1706 if (csignature->hasthis) {
1707 g_assert (sp >= frame->stack);
1710 * It may also be a TP from LD(S)FLDA
1711 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1713 if (sp->type == VAL_OBJ && child_frame.method &&
1714 child_frame.method->klass->valuetype) /* unbox it */
1715 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1717 child_frame.obj = sp->data.p;
1719 child_frame.obj = NULL;
1721 if (csignature->ret->type != MONO_TYPE_VOID) {
1722 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
1723 child_frame.retval = &retval;
1725 child_frame.retval = NULL;
1728 child_frame.ex = NULL;
1729 child_frame.ex_handler = NULL;
1731 if (!child_frame.method) {
1733 ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE);
1734 if (child_frame.ex) {
1735 frame->ex = child_frame.ex;
1736 goto handle_exception;
1738 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
1739 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
1740 g_assert (child_frame.method);
1741 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
1742 ves_exec_method (&child_frame);
1744 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1745 case INLINE_STRING_LENGTH:
1746 retval.type = VAL_I32;
1747 retval.data.i = ((MonoString*)sp->data.p)->length;
1748 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
1750 case INLINE_ARRAY_LENGTH:
1751 retval.type = VAL_I32;
1752 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1754 case INLINE_ARRAY_RANK:
1755 retval.type = VAL_I32;
1756 retval.data.i = mono_object_class (sp->data.p)->rank;
1758 case INLINE_TYPE_ELEMENT_TYPE:
1759 retval.type = VAL_OBJ;
1761 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1762 retval.data.vt.klass = NULL;
1763 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1764 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1765 else if (c->element_class)
1766 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1768 retval.data.p = NULL;
1772 ves_exec_method (&child_frame);
1776 while (endsp > sp) {
1781 if (child_frame.ex) {
1783 * An exception occurred, need to run finally, fault and catch handlers..
1785 frame->ex = child_frame.ex;
1786 goto handle_finally;
1789 /* need to handle typedbyref ... */
1790 if (csignature->ret->type != MONO_TYPE_VOID) {
1797 if (signature->ret->type != MONO_TYPE_VOID) {
1799 if (sp->type == VAL_VALUET) {
1800 /* the caller has already allocated the memory */
1801 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt, signature->pinvoke);
1804 *frame->retval = *sp;
1807 if (sp > frame->stack)
1808 g_warning ("more values on stack: %d", sp-frame->stack);
1812 CASE (CEE_BR_S) /* Fall through */
1814 if (*ip == CEE_BR) {
1816 ip += (gint32) read32(ip);
1820 ip += (signed char) *ip;
1824 CASE (CEE_BRFALSE) /* Fall through */
1825 CASE (CEE_BRFALSE_S) {
1828 if (*ip == CEE_BRFALSE_S) {
1829 broffset = (signed char)ip [1];
1832 broffset = (gint32) read32 (ip + 1);
1837 case VAL_I32: result = sp->data.i == 0; break;
1838 case VAL_I64: result = sp->data.l == 0; break;
1839 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1840 default: result = sp->data.p == NULL; break;
1846 CASE (CEE_BRTRUE) /* Fall through */
1847 CASE (CEE_BRTRUE_S) {
1850 if (*ip == CEE_BRTRUE_S) {
1851 broffset = (signed char)ip [1];
1854 broffset = (gint32) read32 (ip + 1);
1859 case VAL_I32: result = sp->data.i != 0; break;
1860 case VAL_I64: result = sp->data.l != 0; break;
1861 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1862 default: result = sp->data.p != NULL; break;
1868 CASE (CEE_BEQ) /* Fall through */
1872 if (*ip == CEE_BEQ_S) {
1873 broffset = (signed char)ip [1];
1876 broffset = (gint32) read32 (ip + 1);
1880 if (sp->type == VAL_I32)
1881 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1882 else if (sp->type == VAL_I64)
1883 result = sp [0].data.l == sp [1].data.l;
1884 else if (sp->type == VAL_DOUBLE)
1885 result = sp [0].data.f == sp [1].data.f;
1887 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1892 CASE (CEE_BGE) /* Fall through */
1896 if (*ip == CEE_BGE_S) {
1897 broffset = (signed char)ip [1];
1900 broffset = (gint32) read32 (ip + 1);
1904 if (sp->type == VAL_I32)
1905 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1906 else if (sp->type == VAL_I64)
1907 result = sp [0].data.l >= sp [1].data.l;
1908 else if (sp->type == VAL_DOUBLE)
1909 result = sp [0].data.f >= sp [1].data.f;
1911 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1916 CASE (CEE_BGT) /* Fall through */
1920 if (*ip == CEE_BGT_S) {
1921 broffset = (signed char)ip [1];
1924 broffset = (gint32) read32 (ip + 1);
1928 if (sp->type == VAL_I32)
1929 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1930 else if (sp->type == VAL_I64)
1931 result = sp [0].data.l > sp [1].data.l;
1932 else if (sp->type == VAL_DOUBLE)
1933 result = sp [0].data.f > sp [1].data.f;
1935 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1940 CASE (CEE_BLT) /* Fall through */
1944 if (*ip == CEE_BLT_S) {
1945 broffset = (signed char)ip [1];
1948 broffset = (gint32) read32 (ip + 1);
1952 if (sp->type == VAL_I32)
1953 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1954 else if (sp->type == VAL_I64)
1955 result = sp[0].data.l < sp[1].data.l;
1956 else if (sp->type == VAL_DOUBLE)
1957 result = sp[0].data.f < sp[1].data.f;
1959 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1964 CASE (CEE_BLE) /* fall through */
1968 if (*ip == CEE_BLE_S) {
1969 broffset = (signed char)ip [1];
1972 broffset = (gint32) read32 (ip + 1);
1977 if (sp->type == VAL_I32)
1978 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1979 else if (sp->type == VAL_I64)
1980 result = sp [0].data.l <= sp [1].data.l;
1981 else if (sp->type == VAL_DOUBLE)
1982 result = sp [0].data.f <= sp [1].data.f;
1985 * FIXME: here and in other places GET_NATI on the left side
1986 * _will_ be wrong when we change the macro to work on 64 bits
1989 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1995 CASE (CEE_BNE_UN) /* Fall through */
1996 CASE (CEE_BNE_UN_S) {
1999 if (*ip == CEE_BNE_UN_S) {
2000 broffset = (signed char)ip [1];
2003 broffset = (gint32) read32 (ip + 1);
2007 if (sp->type == VAL_I32)
2008 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
2009 else if (sp->type == VAL_I64)
2010 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
2011 else if (sp->type == VAL_DOUBLE)
2012 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2013 (sp [0].data.f != sp [1].data.f);
2015 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
2020 CASE (CEE_BGE_UN) /* Fall through */
2021 CASE (CEE_BGE_UN_S) {
2024 if (*ip == CEE_BGE_UN_S) {
2025 broffset = (signed char)ip [1];
2028 broffset = (gint32) read32 (ip + 1);
2032 if (sp->type == VAL_I32)
2033 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
2034 else if (sp->type == VAL_I64)
2035 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
2036 else if (sp->type == VAL_DOUBLE)
2037 result = !isless (sp [0].data.f,sp [1].data.f);
2039 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
2044 CASE (CEE_BGT_UN) /* Fall through */
2045 CASE (CEE_BGT_UN_S) {
2048 if (*ip == CEE_BGT_UN_S) {
2049 broffset = (signed char)ip [1];
2052 broffset = (gint32) read32 (ip + 1);
2056 if (sp->type == VAL_I32)
2057 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
2058 else if (sp->type == VAL_I64)
2059 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2060 else if (sp->type == VAL_DOUBLE)
2061 result = isgreater (sp [0].data.f, sp [1].data.f);
2063 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
2068 CASE (CEE_BLE_UN) /* Fall through */
2069 CASE (CEE_BLE_UN_S) {
2072 if (*ip == CEE_BLE_UN_S) {
2073 broffset = (signed char)ip [1];
2076 broffset = (gint32) read32 (ip + 1);
2080 if (sp->type == VAL_I32)
2081 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
2082 else if (sp->type == VAL_I64)
2083 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2084 else if (sp->type == VAL_DOUBLE)
2085 result = islessequal (sp [0].data.f, sp [1].data.f);
2087 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
2092 CASE (CEE_BLT_UN) /* Fall through */
2093 CASE (CEE_BLT_UN_S) {
2096 if (*ip == CEE_BLT_UN_S) {
2097 broffset = (signed char)ip [1];
2100 broffset = (gint32) read32 (ip + 1);
2104 if (sp->type == VAL_I32)
2105 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
2106 else if (sp->type == VAL_I64)
2107 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2108 else if (sp->type == VAL_DOUBLE)
2109 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2110 (sp [0].data.f < sp [1].data.f);
2112 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
2119 const unsigned char *st;
2123 st = ip + sizeof (gint32) * n;
2125 if ((guint32)sp->data.i < n) {
2127 ip += sizeof (gint32) * (guint32)sp->data.i;
2128 offset = read32 (ip);
2137 sp[-1].type = VAL_I32;
2138 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2142 sp[-1].type = VAL_I32;
2143 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2147 sp[-1].type = VAL_I32;
2148 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2152 sp[-1].type = VAL_I32;
2153 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2155 CASE (CEE_LDIND_I4) /* Fall through */
2158 sp[-1].type = VAL_I32;
2159 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2163 sp[-1].type = VAL_I64;
2164 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2168 sp[-1].type = VAL_NATI;
2169 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2173 sp[-1].type = VAL_DOUBLE;
2174 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2178 sp[-1].type = VAL_DOUBLE;
2179 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2181 CASE (CEE_LDIND_REF)
2183 sp[-1].type = VAL_OBJ;
2184 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2185 sp[-1].data.vt.klass = NULL;
2187 CASE (CEE_STIND_REF) {
2195 CASE (CEE_STIND_I1) {
2200 *p = (gint8)sp[1].data.i;
2203 CASE (CEE_STIND_I2) {
2208 *p = (gint16)sp[1].data.i;
2211 CASE (CEE_STIND_I4) {
2219 CASE (CEE_STIND_I) {
2224 *p = (mono_i)sp[1].data.p;
2227 CASE (CEE_STIND_I8) {
2235 CASE (CEE_STIND_R4) {
2240 *p = (gfloat)sp[1].data.f;
2243 CASE (CEE_STIND_R8) {
2254 /* should probably consider the pointers as unsigned */
2255 if (sp->type == VAL_I32)
2256 sp [-1].data.i += GET_NATI (sp [0]);
2257 else if (sp->type == VAL_I64)
2258 sp [-1].data.l += sp [0].data.l;
2259 else if (sp->type == VAL_DOUBLE)
2260 sp [-1].data.f += sp [0].data.f;
2262 char *p = sp [-1].data.p;
2263 p += GET_NATI (sp [0]);
2270 /* should probably consider the pointers as unsigned */
2271 if (sp->type == VAL_I32)
2272 sp [-1].data.i -= GET_NATI (sp [0]);
2273 else if (sp->type == VAL_I64)
2274 sp [-1].data.l -= sp [0].data.l;
2275 else if (sp->type == VAL_DOUBLE)
2276 sp [-1].data.f -= sp [0].data.f;
2278 char *p = sp [-1].data.p;
2279 p -= GET_NATI (sp [0]);
2286 if (sp->type == VAL_I32)
2287 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
2288 else if (sp->type == VAL_I64)
2289 sp [-1].data.l *= sp [0].data.l;
2290 else if (sp->type == VAL_DOUBLE)
2291 sp [-1].data.f *= sp [0].data.f;
2296 if (sp->type == VAL_I32) {
2297 if (GET_NATI (sp [0]) == 0)
2298 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2299 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2300 } else if (sp->type == VAL_I64) {
2301 if (sp [0].data.l == 0)
2302 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2303 sp [-1].data.l /= sp [0].data.l;
2304 } else if (sp->type == VAL_DOUBLE) {
2305 /* set NaN is divisor is 0.0 */
2306 sp [-1].data.f /= sp [0].data.f;
2312 if (sp->type == VAL_I32) {
2314 if (GET_NATI (sp [0]) == 0)
2315 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2316 val = sp [-1].data.i;
2317 val /= (guint32)GET_NATI (sp [0]);
2318 sp [-1].data.i = val;
2319 } else if (sp->type == VAL_I64) {
2321 if (sp [0].data.l == 0)
2322 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2323 val = sp [-1].data.l;
2324 val /= (guint64)sp [0].data.l;
2325 sp [-1].data.l = val;
2326 } else if (sp->type == VAL_NATI) {
2328 if (GET_NATI (sp [0]) == 0)
2329 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2330 val = (mono_u)sp [-1].data.p;
2331 val /= (mono_u)sp [0].data.p;
2332 sp [-1].data.p = (gpointer)val;
2338 if (sp->type == VAL_I32) {
2339 if (GET_NATI (sp [0]) == 0)
2340 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2341 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2342 } else if (sp->type == VAL_I64) {
2343 if (sp [0].data.l == 0)
2344 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2345 sp [-1].data.l %= sp [0].data.l;
2346 } else if (sp->type == VAL_DOUBLE) {
2347 /* FIXME: what do we actually do here? */
2348 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2350 if (GET_NATI (sp [0]) == 0)
2351 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2352 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2358 if (sp->type == VAL_I32) {
2359 if (GET_NATI (sp [0]) == 0)
2360 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2361 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2362 } else if (sp->type == VAL_I64) {
2363 if (sp [0].data.l == 0)
2364 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2365 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2366 } else if (sp->type == VAL_DOUBLE) {
2367 /* unspecified behaviour according to the spec */
2369 if (GET_NATI (sp [0]) == 0)
2370 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2371 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2377 if (sp->type == VAL_I32)
2378 sp [-1].data.i &= GET_NATI (sp [0]);
2379 else if (sp->type == VAL_I64)
2380 sp [-1].data.l &= sp [0].data.l;
2382 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2387 if (sp->type == VAL_I32)
2388 sp [-1].data.i |= GET_NATI (sp [0]);
2389 else if (sp->type == VAL_I64)
2390 sp [-1].data.l |= sp [0].data.l;
2392 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2397 if (sp->type == VAL_I32)
2398 sp [-1].data.i ^= GET_NATI (sp [0]);
2399 else if (sp->type == VAL_I64)
2400 sp [-1].data.l ^= sp [0].data.l;
2402 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2407 if (sp [-1].type == VAL_I32)
2408 sp [-1].data.i <<= GET_NATI (sp [0]);
2409 else if (sp [-1].type == VAL_I64)
2410 sp [-1].data.l <<= GET_NATI (sp [0]);
2412 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2417 if (sp [-1].type == VAL_I32)
2418 sp [-1].data.i >>= GET_NATI (sp [0]);
2419 else if (sp [-1].type == VAL_I64)
2420 sp [-1].data.l >>= GET_NATI (sp [0]);
2422 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2427 if (sp [-1].type == VAL_I32)
2428 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2429 else if (sp [-1].type == VAL_I64)
2430 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2432 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2437 if (sp->type == VAL_I32)
2438 sp->data.i = - sp->data.i;
2439 else if (sp->type == VAL_I64)
2440 sp->data.l = - sp->data.l;
2441 else if (sp->type == VAL_DOUBLE)
2442 sp->data.f = - sp->data.f;
2443 else if (sp->type == VAL_NATI)
2444 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2450 if (sp->type == VAL_I32)
2451 sp->data.i = ~ sp->data.i;
2452 else if (sp->type == VAL_I64)
2453 sp->data.l = ~ sp->data.l;
2454 else if (sp->type == VAL_NATI)
2455 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2458 CASE (CEE_CONV_U1) /* fall through */
2459 CASE (CEE_CONV_I1) {
2461 switch (sp [-1].type) {
2463 sp [-1].data.i = (gint8)sp [-1].data.f;
2466 sp [-1].data.i = (gint8)sp [-1].data.l;
2471 sp [-1].data.i = (gint8)sp [-1].data.i;
2474 sp [-1].data.i = (gint8)sp [-1].data.nati;
2477 sp [-1].type = VAL_I32;
2480 CASE (CEE_CONV_U2) /* fall through */
2481 CASE (CEE_CONV_I2) {
2483 switch (sp [-1].type) {
2485 sp [-1].data.i = (gint16)sp [-1].data.f;
2488 sp [-1].data.i = (gint16)sp [-1].data.l;
2493 sp [-1].data.i = (gint16)sp [-1].data.i;
2496 sp [-1].data.i = (gint16)sp [-1].data.nati;
2499 sp [-1].type = VAL_I32;
2502 CASE (CEE_CONV_U4) /* Fall through */
2503 #if SIZEOF_VOID_P == 4
2504 CASE (CEE_CONV_I) /* Fall through */
2505 CASE (CEE_CONV_U) /* Fall through */
2507 CASE (CEE_CONV_I4) {
2509 switch (sp [-1].type) {
2511 sp [-1].data.i = (gint32)sp [-1].data.f;
2514 sp [-1].data.i = (gint32)sp [-1].data.l;
2521 sp [-1].data.i = (gint32)sp [-1].data.p;
2524 sp [-1].type = VAL_I32;
2527 #if SIZEOF_VOID_P == 8
2528 CASE (CEE_CONV_I) /* Fall through */
2532 switch (sp [-1].type) {
2534 sp [-1].data.l = (gint64)sp [-1].data.f;
2541 sp [-1].data.l = (gint64)sp [-1].data.i;
2544 sp [-1].data.l = (gint64)sp [-1].data.nati;
2547 sp [-1].type = VAL_I64;
2549 CASE (CEE_CONV_R4) {
2551 switch (sp [-1].type) {
2553 sp [-1].data.f = (float)sp [-1].data.f;
2556 sp [-1].data.f = (float)sp [-1].data.l;
2561 sp [-1].data.f = (float)sp [-1].data.i;
2564 sp [-1].data.f = (float)sp [-1].data.nati;
2567 sp [-1].type = VAL_DOUBLE;
2570 CASE (CEE_CONV_R8) {
2572 switch (sp [-1].type) {
2574 sp [-1].data.f = (double)sp [-1].data.f;
2577 sp [-1].data.f = (double)sp [-1].data.l;
2582 sp [-1].data.f = (double)sp [-1].data.i;
2585 sp [-1].data.f = (double)sp [-1].data.nati;
2588 sp [-1].type = VAL_DOUBLE;
2591 #if SIZEOF_VOID_P == 8
2592 CASE (CEE_CONV_U) /* Fall through */
2597 switch (sp [-1].type){
2599 sp [-1].data.l = (guint64)sp [-1].data.f;
2606 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
2609 sp [-1].data.l = (guint64) sp [-1].data.nati;
2612 sp [-1].type = VAL_I64;
2617 vtklass = mono_class_get (image, read32 (ip));
2620 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2629 token = read32 (ip);
2632 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
2633 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
2635 c = mono_class_get (image, token);
2637 addr = sp [-1].data.vt.vt;
2638 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
2639 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
2647 str_index = mono_metadata_token_index (read32 (ip));
2650 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2653 sp->data.vt.klass = NULL;
2660 MonoClass *newobj_class;
2661 MonoMethodSignature *csig;
2662 stackval valuetype_this;
2663 stackval *endsp = sp;
2670 token = read32 (ip);
2673 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2674 THROW_EX (mono_get_exception_missing_method (), ip -5);
2676 csig = child_frame.method->signature;
2677 newobj_class = child_frame.method->klass;
2678 /*if (profiling_classes) {
2679 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2681 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2685 if (newobj_class->parent == mono_defaults.array_class) {
2686 sp -= csig->param_count;
2687 o = ves_array_create (domain, newobj_class, csig, sp);
2688 goto array_constructed;
2692 * First arg is the object.
2694 if (newobj_class->valuetype) {
2696 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
2697 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2698 zero = valuetype_this.data.vt.vt;
2699 child_frame.obj = valuetype_this.data.vt.vt;
2701 memset (&valuetype_this, 0, sizeof (stackval));
2702 zero = &valuetype_this;
2703 child_frame.obj = &valuetype_this;
2705 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
2707 if (newobj_class != mono_defaults.string_class) {
2708 o = mono_object_new (domain, newobj_class);
2709 child_frame.obj = o;
2711 child_frame.retval = &retval;
2715 if (csig->param_count) {
2716 sp -= csig->param_count;
2717 child_frame.stack_args = sp;
2719 child_frame.stack_args = NULL;
2722 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2724 child_frame.ex = NULL;
2725 child_frame.ex_handler = NULL;
2727 ves_exec_method (&child_frame);
2729 while (endsp > sp) {
2734 if (child_frame.ex) {
2736 * An exception occurred, need to run finally, fault and catch handlers..
2738 frame->ex = child_frame.ex;
2739 goto handle_finally;
2742 * a constructor returns void, but we need to return the object we created
2745 if (newobj_class->valuetype && !newobj_class->enumtype) {
2746 *sp = valuetype_this;
2747 } else if (newobj_class == mono_defaults.string_class) {
2752 sp->data.vt.klass = newobj_class;
2757 CASE (CEE_CASTCLASS) /* Fall through */
2761 MonoClass *c , *oclass;
2763 int do_isinst = *ip == CEE_ISINST;
2766 token = read32 (ip);
2767 c = mono_class_get (image, token);
2769 g_assert (sp [-1].type == VAL_OBJ);
2771 if ((o = sp [-1].data.p)) {
2775 if (mono_object_isinst (o, c)) {
2776 sp [-1].data.vt.klass = c;
2780 sp [-1].data.p = NULL;
2781 sp [-1].data.vt.klass = NULL;
2783 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2789 CASE (CEE_CONV_R_UN)
2791 switch (sp [-1].type) {
2795 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2800 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2803 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2806 sp [-1].type = VAL_DOUBLE;
2809 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2816 token = read32 (ip);
2818 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
2819 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
2821 c = mono_class_get (image, token);
2825 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2827 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2828 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2830 sp [-1].type = VAL_MP;
2831 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2838 frame->ex_handler = NULL;
2840 sp->data.p = mono_get_exception_null_reference ();
2841 THROW_EX (sp->data.p, ip);
2843 CASE (CEE_LDFLDA) /* Fall through */
2846 MonoClassField *field;
2848 int load_addr = *ip == CEE_LDFLDA;
2851 if (!sp [-1].data.p)
2852 THROW_EX (mono_get_exception_null_reference (), ip);
2855 token = read32 (ip);
2858 if (sp [-1].type == VAL_OBJ) {
2859 obj = sp [-1].data.p;
2861 if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
2862 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
2863 field = mono_class_get_field (klass, token);
2864 addr = mono_load_remote_field (obj, klass, field, NULL);
2866 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2867 field = mono_field_from_memberref (image, token, NULL);
2869 field = mono_class_get_field (obj->vtable->klass, token);
2870 addr = (char*)obj + field->offset;
2873 obj = sp [-1].data.vt.vt;
2874 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2875 addr = (char*)obj + field->offset - sizeof (MonoObject);
2879 sp [-1].type = VAL_TP;
2880 sp [-1].data.p = addr;
2881 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2883 vt_alloc (field->type, &sp [-1], FALSE);
2884 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2891 MonoClassField *field;
2892 guint32 token, offset;
2897 THROW_EX (mono_get_exception_null_reference (), ip);
2900 token = read32 (ip);
2903 if (sp [0].type == VAL_OBJ) {
2904 obj = sp [0].data.p;
2906 if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
2907 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
2908 field = mono_class_get_field (klass, token);
2910 mono_store_remote_field (obj, klass, field, &sp [1].data);
2911 offset = field->offset;
2913 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2914 field = mono_field_from_memberref (image, token, NULL);
2916 field = mono_class_get_field (obj->vtable->klass, token);
2917 offset = field->offset;
2918 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
2922 obj = sp [0].data.vt.vt;
2923 field = mono_class_get_field (sp [0].data.vt.klass, token);
2924 offset = field->offset - sizeof (MonoObject);
2925 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
2931 CASE (CEE_LDSFLD) /* Fall through */
2932 CASE (CEE_LDSFLDA) {
2935 MonoClassField *field;
2937 int load_addr = *ip == CEE_LDSFLDA;
2941 token = read32 (ip);
2944 /* need to handle fieldrefs */
2945 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2946 field = mono_field_from_memberref (image, token, &klass);
2948 klass = mono_class_get (image,
2949 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2950 field = mono_class_get_field (klass, token);
2954 vt = mono_class_vtable (domain, klass);
2955 if (!vt->initialized)
2956 mono_runtime_class_init (vt);
2957 if (!domain->thread_static_fields || !(addr = g_hash_table_lookup (domain->thread_static_fields, field)))
2958 addr = (char*)(vt->data) + field->offset;
2960 addr = mono_threads_get_static_data (GPOINTER_TO_UINT (addr));
2965 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2967 vt_alloc (field->type, sp, FALSE);
2968 stackval_from_data (field->type, sp, addr, FALSE);
2976 MonoClassField *field;
2981 token = read32 (ip);
2985 /* need to handle fieldrefs */
2986 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2987 field = mono_field_from_memberref (image, token, &klass);
2989 klass = mono_class_get (image,
2990 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2991 field = mono_class_get_field (klass, token);
2995 vt = mono_class_vtable (domain, klass);
2996 if (!vt->initialized)
2997 mono_runtime_class_init (vt);
2998 if (!domain->thread_static_fields || !(addr = g_hash_table_lookup (domain->thread_static_fields, field)))
2999 addr = (char*)(vt->data) + field->offset;
3001 addr = mono_threads_get_static_data (GPOINTER_TO_UINT (addr));
3003 stackval_to_data (field->type, sp, addr, FALSE);
3010 vtklass = mono_class_get (image, read32 (ip));
3015 * LAMESPEC: According to the spec, the stack should contain a
3016 * pointer to a value type. In reality, it can contain anything.
3018 if (sp [1].type == VAL_VALUET)
3019 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
3021 memcpy (sp [0].data.p, &sp [1].data, mono_class_value_size (vtklass, NULL));
3024 #if SIZEOF_VOID_P == 8
3025 CASE (CEE_CONV_OVF_I_UN)
3027 CASE (CEE_CONV_OVF_I8_UN) {
3028 switch (sp [-1].type) {
3030 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
3031 THROW_EX (mono_get_exception_overflow (), ip);
3032 sp [-1].data.l = (guint64)sp [-1].data.f;
3039 /* Can't overflow */
3040 sp [-1].data.l = (guint64)sp [-1].data.i;
3043 sp [-1].data.l = (guint64)sp [-1].data.nati;
3046 sp [-1].type = VAL_I64;
3050 #if SIZEOF_VOID_P == 8
3051 CASE (CEE_CONV_OVF_U_UN)
3053 CASE (CEE_CONV_OVF_U8_UN) {
3054 switch (sp [-1].type) {
3056 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
3057 THROW_EX (mono_get_exception_overflow (), ip);
3058 sp [-1].data.l = (guint64)sp [-1].data.f;
3066 /* Can't overflow */
3067 sp [-1].data.l = (guint64)sp [-1].data.i;
3070 /* Can't overflow */
3071 sp [-1].data.l = (guint64)sp [-1].data.nati;
3074 sp [-1].type = VAL_I64;
3078 #if SIZEOF_VOID_P == 4
3079 CASE (CEE_CONV_OVF_I_UN)
3080 CASE (CEE_CONV_OVF_U_UN)
3082 CASE (CEE_CONV_OVF_I1_UN)
3083 CASE (CEE_CONV_OVF_I2_UN)
3084 CASE (CEE_CONV_OVF_I4_UN)
3085 CASE (CEE_CONV_OVF_U1_UN)
3086 CASE (CEE_CONV_OVF_U2_UN)
3087 CASE (CEE_CONV_OVF_U4_UN) {
3089 switch (sp [-1].type) {
3091 value = (guint64)sp [-1].data.f;
3094 value = (guint64)sp [-1].data.l;
3099 value = (guint64)sp [-1].data.i;
3102 value = (guint64)sp [-1].data.nati;
3106 case CEE_CONV_OVF_I1_UN:
3108 THROW_EX (mono_get_exception_overflow (), ip);
3109 sp [-1].data.i = value;
3110 sp [-1].type = VAL_I32;
3112 case CEE_CONV_OVF_I2_UN:
3114 THROW_EX (mono_get_exception_overflow (), ip);
3115 sp [-1].data.i = value;
3116 sp [-1].type = VAL_I32;
3118 #if SIZEOF_VOID_P == 4
3119 case CEE_CONV_OVF_I_UN: /* Fall through */
3121 case CEE_CONV_OVF_I4_UN:
3122 if (value > MYGUINT32_MAX)
3123 THROW_EX (mono_get_exception_overflow (), ip);
3124 sp [-1].data.i = value;
3125 sp [-1].type = VAL_I32;
3127 case CEE_CONV_OVF_U1_UN:
3129 THROW_EX (mono_get_exception_overflow (), ip);
3130 sp [-1].data.i = value;
3131 sp [-1].type = VAL_I32;
3133 case CEE_CONV_OVF_U2_UN:
3135 THROW_EX (mono_get_exception_overflow (), ip);
3136 sp [-1].data.i = value;
3137 sp [-1].type = VAL_I32;
3139 #if SIZEOF_VOID_P == 4
3140 case CEE_CONV_OVF_U_UN: /* Fall through */
3142 case CEE_CONV_OVF_U4_UN:
3143 if (value > 4294967295U)
3144 THROW_EX (mono_get_exception_overflow (), ip);
3145 sp [-1].data.i = value;
3146 sp [-1].type = VAL_I32;
3149 g_assert_not_reached ();
3159 token = read32 (ip);
3161 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3162 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3164 class = mono_class_get (image, token);
3165 g_assert (class != NULL);
3167 sp [-1].type = VAL_OBJ;
3168 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3169 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3171 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3172 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3174 /* need to vt_free (sp); */
3186 token = read32 (ip);
3188 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3189 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3191 class = mono_class_get (image, token);
3193 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3196 sp [-1].type = VAL_OBJ;
3198 /*if (profiling_classes) {
3199 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3201 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3211 g_assert (sp [-1].type == VAL_OBJ);
3215 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3217 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3219 sp [-1].type = VAL_I32;
3220 sp [-1].data.i = mono_array_length (o);
3224 CASE (CEE_LDELEMA) {
3226 guint32 esize, token;
3230 token = read32 (ip);
3234 g_assert (sp [0].type == VAL_OBJ);
3237 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3239 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3240 if (aindex >= mono_array_length (o))
3241 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3243 /* check the array element corresponds to token */
3244 esize = mono_array_element_size (o->obj.vtable->klass);
3247 sp->data.p = mono_array_addr_with_size (o, esize, aindex);
3248 sp->data.vt.klass = o->obj.vtable->klass->element_class;
3253 CASE (CEE_LDELEM_I1) /* fall through */
3254 CASE (CEE_LDELEM_U1) /* fall through */
3255 CASE (CEE_LDELEM_I2) /* fall through */
3256 CASE (CEE_LDELEM_U2) /* fall through */
3257 CASE (CEE_LDELEM_I4) /* fall through */
3258 CASE (CEE_LDELEM_U4) /* fall through */
3259 CASE (CEE_LDELEM_I8) /* fall through */
3260 CASE (CEE_LDELEM_I) /* fall through */
3261 CASE (CEE_LDELEM_R4) /* fall through */
3262 CASE (CEE_LDELEM_R8) /* fall through */
3263 CASE (CEE_LDELEM_REF) {
3269 g_assert (sp [0].type == VAL_OBJ);
3272 THROW_EX (mono_get_exception_null_reference (), ip);
3274 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3276 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3277 if (aindex >= mono_array_length (o))
3278 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3281 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3285 sp [0].data.i = mono_array_get (o, gint8, aindex);
3286 sp [0].type = VAL_I32;
3289 sp [0].data.i = mono_array_get (o, guint8, aindex);
3290 sp [0].type = VAL_I32;
3293 sp [0].data.i = mono_array_get (o, gint16, aindex);
3294 sp [0].type = VAL_I32;
3297 sp [0].data.i = mono_array_get (o, guint16, aindex);
3298 sp [0].type = VAL_I32;
3301 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3302 sp [0].type = VAL_NATI;
3305 sp [0].data.i = mono_array_get (o, gint32, aindex);
3306 sp [0].type = VAL_I32;
3309 sp [0].data.i = mono_array_get (o, guint32, aindex);
3310 sp [0].type = VAL_I32;
3313 sp [0].data.l = mono_array_get (o, guint64, aindex);
3314 sp [0].type = VAL_I64;
3317 sp [0].data.f = mono_array_get (o, float, aindex);
3318 sp [0].type = VAL_DOUBLE;
3321 sp [0].data.f = mono_array_get (o, double, aindex);
3322 sp [0].type = VAL_DOUBLE;
3324 case CEE_LDELEM_REF:
3325 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3326 sp [0].data.vt.klass = NULL;
3327 sp [0].type = VAL_OBJ;
3337 CASE (CEE_STELEM_I) /* fall through */
3338 CASE (CEE_STELEM_I1) /* fall through */
3339 CASE (CEE_STELEM_I2) /* fall through */
3340 CASE (CEE_STELEM_I4) /* fall through */
3341 CASE (CEE_STELEM_I8) /* fall through */
3342 CASE (CEE_STELEM_R4) /* fall through */
3343 CASE (CEE_STELEM_R8) /* fall through */
3344 CASE (CEE_STELEM_REF) {
3351 g_assert (sp [0].type == VAL_OBJ);
3354 THROW_EX (mono_get_exception_null_reference (), ip);
3356 ac = o->obj.vtable->klass;
3357 g_assert (MONO_CLASS_IS_ARRAY (ac));
3359 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3360 if (aindex >= mono_array_length (o))
3361 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3364 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3368 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3371 mono_array_set (o, gint8, aindex, sp [2].data.i);
3374 mono_array_set (o, gint16, aindex, sp [2].data.i);
3377 mono_array_set (o, gint32, aindex, sp [2].data.i);
3380 mono_array_set (o, gint64, aindex, sp [2].data.l);
3383 mono_array_set (o, float, aindex, sp [2].data.f);
3386 mono_array_set (o, double, aindex, sp [2].data.f);
3388 case CEE_STELEM_REF:
3389 g_assert (sp [2].type == VAL_OBJ);
3390 if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
3391 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3392 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3403 CASE (CEE_UNBOX_ANY)
3416 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3418 #if SIZEOF_VOID_P == 4
3419 CASE (CEE_CONV_OVF_I)
3420 CASE (CEE_CONV_OVF_U)
3422 CASE (CEE_CONV_OVF_I1)
3423 CASE (CEE_CONV_OVF_I2)
3424 CASE (CEE_CONV_OVF_I4)
3425 CASE (CEE_CONV_OVF_U1)
3426 CASE (CEE_CONV_OVF_U2)
3427 CASE (CEE_CONV_OVF_U4) {
3429 switch (sp [-1].type) {
3431 value = (gint64)sp [-1].data.f;
3434 value = (gint64)sp [-1].data.l;
3439 value = (gint64)sp [-1].data.i;
3442 value = (gint64)sp [-1].data.nati;
3446 case CEE_CONV_OVF_I1:
3447 if (value < -128 || value > 127)
3448 THROW_EX (mono_get_exception_overflow (), ip);
3449 sp [-1].data.i = value;
3450 sp [-1].type = VAL_I32;
3452 case CEE_CONV_OVF_I2:
3453 if (value < -32768 || value > 32767)
3454 THROW_EX (mono_get_exception_overflow (), ip);
3455 sp [-1].data.i = value;
3456 sp [-1].type = VAL_I32;
3458 #if SIZEOF_VOID_P == 4
3459 case CEE_CONV_OVF_I: /* Fall through */
3461 case CEE_CONV_OVF_I4:
3462 if (value < MYGINT32_MIN || value > MYGINT32_MAX)
3463 THROW_EX (mono_get_exception_overflow (), ip);
3464 sp [-1].data.i = value;
3465 sp [-1].type = VAL_I32;
3467 case CEE_CONV_OVF_U1:
3468 if (value < 0 || value > 255)
3469 THROW_EX (mono_get_exception_overflow (), ip);
3470 sp [-1].data.i = value;
3471 sp [-1].type = VAL_I32;
3473 case CEE_CONV_OVF_U2:
3474 if (value < 0 || value > 65535)
3475 THROW_EX (mono_get_exception_overflow (), ip);
3476 sp [-1].data.i = value;
3477 sp [-1].type = VAL_I32;
3479 #if SIZEOF_VOID_P == 4
3480 case CEE_CONV_OVF_U: /* Fall through */
3482 case CEE_CONV_OVF_U4:
3483 if (value < 0 || value > MYGUINT32_MAX)
3484 THROW_EX (mono_get_exception_overflow (), ip);
3485 sp [-1].data.i = value;
3486 sp [-1].type = VAL_I32;
3489 g_assert_not_reached ();
3495 #if SIZEOF_VOID_P == 8
3496 CASE (CEE_CONV_OVF_I)
3498 CASE (CEE_CONV_OVF_I8)
3499 /* FIXME: handle other cases */
3500 if (sp [-1].type == VAL_I32) {
3501 sp [-1].data.l = (guint64)sp [-1].data.i;
3502 sp [-1].type = VAL_I64;
3503 } else if(sp [-1].type == VAL_I64) {
3504 /* defined as NOP */
3511 #if SIZEOF_VOID_P == 8
3512 CASE (CEE_CONV_OVF_U)
3514 CASE (CEE_CONV_OVF_U8)
3515 /* FIXME: handle other cases */
3516 if (sp [-1].type == VAL_I32) {
3517 sp [-1].data.l = (guint64) sp [-1].data.i;
3518 sp [-1].type = VAL_I64;
3519 } else if(sp [-1].type == VAL_I64) {
3520 /* defined as NOP */
3532 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3533 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3535 if (!finite(sp [-1].data.f))
3536 THROW_EX (mono_get_exception_arithmetic (), ip);
3539 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3540 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3541 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3550 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3551 CASE (CEE_LDTOKEN) {
3553 MonoClass *handle_class;
3555 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3557 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3558 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3564 /* FIXME: check overflow */
3565 if (sp->type == VAL_I32) {
3566 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3567 THROW_EX (mono_get_exception_overflow (), ip);
3568 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)GET_NATI (sp [0]);
3569 } else if (sp->type == VAL_I64) {
3570 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3571 THROW_EX (mono_get_exception_overflow (), ip);
3572 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3573 } else if (sp->type == VAL_DOUBLE)
3574 sp [-1].data.f += sp [0].data.f;
3576 char *p = sp [-1].data.p;
3577 p += GET_NATI (sp [0]);
3582 CASE (CEE_ADD_OVF_UN)
3584 /* FIXME: check overflow, make unsigned */
3585 if (sp->type == VAL_I32) {
3586 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3587 THROW_EX (mono_get_exception_overflow (), ip);
3588 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3589 } else if (sp->type == VAL_I64) {
3590 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3591 THROW_EX (mono_get_exception_overflow (), ip);
3592 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3593 } else if (sp->type == VAL_DOUBLE)
3594 sp [-1].data.f += sp [0].data.f;
3596 char *p = sp [-1].data.p;
3597 p += GET_NATI (sp [0]);
3605 if (sp->type == VAL_I32) {
3606 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3607 THROW_EX (mono_get_exception_overflow (), ip);
3608 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3610 else if (sp->type == VAL_I64) {
3611 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3612 THROW_EX (mono_get_exception_overflow (), ip);
3613 sp [-1].data.l *= sp [0].data.l;
3615 else if (sp->type == VAL_DOUBLE)
3616 sp [-1].data.f *= sp [0].data.f;
3618 CASE (CEE_MUL_OVF_UN)
3621 /* FIXME: check overflow, make unsigned */
3622 if (sp->type == VAL_I32) {
3623 if (CHECK_MUL_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3624 THROW_EX (mono_get_exception_overflow (), ip);
3625 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3627 else if (sp->type == VAL_I64) {
3628 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3629 THROW_EX (mono_get_exception_overflow (), ip);
3630 sp [-1].data.l *= sp [0].data.l;
3632 else if (sp->type == VAL_DOUBLE)
3633 sp [-1].data.f *= sp [0].data.f;
3636 CASE (CEE_SUB_OVF_UN)
3639 /* FIXME: handle undeflow/unsigned */
3640 /* should probably consider the pointers as unsigned */
3641 if (sp->type == VAL_I32)
3642 sp [-1].data.i -= GET_NATI (sp [0]);
3643 else if (sp->type == VAL_I64)
3644 sp [-1].data.l -= sp [0].data.l;
3645 else if (sp->type == VAL_DOUBLE)
3646 sp [-1].data.f -= sp [0].data.f;
3648 char *p = sp [-1].data.p;
3649 p -= GET_NATI (sp [0]);
3653 CASE (CEE_ENDFINALLY)
3655 ip = finally_ips->data;
3656 finally_ips = g_slist_remove (finally_ips, ip);
3662 * There was no exception, we continue normally at the target address.
3666 CASE (CEE_LEAVE) /* Fall through */
3668 sp = frame->stack; /* empty the stack */
3670 if (*ip == CEE_LEAVE_S) {
3672 ip += (signed char) *ip;
3676 ip += (gint32) read32 (ip);
3681 * We may be either inside a try block or inside an handler.
3682 * In the first case there was no exception and we go on
3683 * executing the finally handlers and after that resume control
3685 * In the second case we need to clear the exception and
3686 * continue directly at the target ip.
3690 goto handle_finally;
3693 frame->ex_handler = NULL;
3697 frame->ex_handler = NULL;
3699 goto handle_finally;
3705 case CEE_MONO_FUNC1: {
3706 MonoMarshalConv conv;
3716 sp->data.vt.klass = NULL;
3719 case MONO_MARSHAL_CONV_STR_LPWSTR:
3720 sp->data.p = mono_string_to_utf16 (sp->data.p);
3722 case MONO_MARSHAL_CONV_LPSTR_STR:
3723 sp->data.p = mono_string_new_wrapper (sp->data.p);
3725 case MONO_MARSHAL_CONV_STR_LPTSTR:
3726 case MONO_MARSHAL_CONV_STR_LPSTR:
3727 sp->data.p = mono_string_to_utf8 (sp->data.p);
3729 case MONO_MARSHAL_CONV_STR_BSTR:
3730 sp->data.p = mono_string_to_bstr (sp->data.p);
3732 case MONO_MARSHAL_CONV_STR_TBSTR:
3733 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3734 sp->data.p = mono_string_to_ansibstr (sp->data.p);
3736 case MONO_MARSHAL_CONV_SB_LPSTR:
3737 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
3739 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3740 sp->data.p = mono_array_to_savearray (sp->data.p);
3742 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3743 sp->data.p = mono_array_to_lparray (sp->data.p);
3745 case MONO_MARSHAL_CONV_DEL_FTN:
3746 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
3748 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3749 sp->data.p = mono_marshal_string_array (sp->data.p);
3752 g_assert_not_reached ();
3757 case CEE_MONO_PROC2: {
3758 MonoMarshalConv conv;
3766 case MONO_MARSHAL_CONV_LPSTR_SB:
3767 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
3769 case MONO_MARSHAL_FREE_ARRAY:
3770 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
3773 g_assert_not_reached ();
3777 case CEE_MONO_PROC3: {
3778 MonoMarshalConv conv;
3786 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3787 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3789 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3790 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3793 g_assert_not_reached ();
3797 case CEE_MONO_VTADDR: {
3800 sp->type = VAL_VALUETA;
3804 case CEE_MONO_LDPTR: {
3808 token = read32 (ip);
3812 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
3813 sp->data.vt.klass = NULL;
3817 case CEE_MONO_FREE: {
3821 g_free (sp->data.p);
3824 case CEE_MONO_OBJADDR: {
3831 case CEE_MONO_NEWOBJ: {
3836 token = read32 (ip);
3839 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3840 sp->data.p = mono_object_new (domain, class);
3844 case CEE_MONO_RETOBJ: {
3849 token = read32 (ip);
3854 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3856 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt, signature->pinvoke);
3858 if (sp > frame->stack)
3859 g_warning ("more values on stack: %d", sp-frame->stack);
3864 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
3895 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3897 * Note: Exceptions thrown when executing a prefixed opcode need
3898 * to take into account the number of prefix bytes (usually the
3899 * throw point is just (ip - n_prefix_bytes).
3904 case CEE_ARGLIST: ves_abort(); break;
3910 if (sp->type == VAL_I32)
3911 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3912 else if (sp->type == VAL_I64)
3913 result = sp [0].data.l == sp [1].data.l;
3914 else if (sp->type == VAL_DOUBLE) {
3915 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3918 result = sp [0].data.f == sp [1].data.f;
3920 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3922 sp->data.i = result;
3932 if (sp->type == VAL_I32)
3933 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3934 else if (sp->type == VAL_I64)
3935 result = sp [0].data.l > sp [1].data.l;
3936 else if (sp->type == VAL_DOUBLE) {
3937 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3940 result = sp [0].data.f > sp [1].data.f;
3942 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3944 sp->data.i = result;
3954 if (sp->type == VAL_I32)
3955 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3956 else if (sp->type == VAL_I64)
3957 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3958 else if (sp->type == VAL_DOUBLE)
3959 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3961 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3963 sp->data.i = result;
3973 if (sp->type == VAL_I32)
3974 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3975 else if (sp->type == VAL_I64)
3976 result = sp [0].data.l < sp [1].data.l;
3977 else if (sp->type == VAL_DOUBLE) {
3978 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3981 result = sp [0].data.f < sp [1].data.f;
3983 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3985 sp->data.i = result;
3995 if (sp->type == VAL_I32)
3996 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3997 else if (sp->type == VAL_I64)
3998 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3999 else if (sp->type == VAL_DOUBLE)
4000 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
4002 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
4004 sp->data.i = result;
4010 case CEE_LDVIRTFTN: {
4011 int virtual = *ip == CEE_LDVIRTFTN;
4015 token = read32 (ip);
4018 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
4019 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
4021 m = mono_get_method (image, token, NULL);
4024 THROW_EX (mono_get_exception_missing_method (), ip - 5);
4028 THROW_EX (mono_get_exception_null_reference (), ip - 5);
4030 m = get_virtual_method (domain, m, sp);
4034 * This prevents infinite cycles since the wrapper contains
4037 if (frame->method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
4038 if (m && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4039 m = mono_marshal_get_synchronized_wrapper (m);
4041 sp->type = VAL_NATI;
4042 sp->data.p = mono_create_method_pointer (m);
4043 sp->data.vt.klass = NULL;
4047 case CEE_UNUSED56: ves_abort(); break;
4051 arg_pos = read16 (ip);
4053 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
4054 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4066 t = ARG_TYPE (signature, anum);
4067 c = mono_class_from_mono_type (t);
4068 sp->data.vt.klass = c;
4069 sp->data.vt.vt = ARG_POS (anum);
4072 sp->type = VAL_VALUETA;
4082 arg_pos = read16 (ip);
4085 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4092 loc_pos = read16 (ip);
4094 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4095 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4105 loc_pos = read16 (ip);
4107 t = LOCAL_TYPE (header, loc_pos);
4108 c = mono_class_from_mono_type (t);
4109 sp->data.vt.vt = LOCAL_POS (loc_pos);
4110 sp->data.vt.klass = c;
4113 sp->type = VAL_VALUETA;
4123 loc_pos = read16 (ip);
4126 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4132 if (sp != frame->stack)
4133 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4135 sp->data.p = alloca (sp->data.i);
4139 case CEE_UNUSED57: ves_abort(); break;
4140 case CEE_ENDFILTER: ves_abort(); break;
4141 case CEE_UNALIGNED_:
4143 unaligned_address = 1;
4147 volatile_address = 1;
4156 token = read32 (ip);
4159 * we ignore the value of token (I think we can as unspecified
4160 * behavior described in Partition II, 3.5).
4163 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
4164 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
4167 case CEE_CONSTRAINED_: {
4169 /* FIXME: implement */
4171 token = read32 (ip);
4177 if (!sp [0].data.p || !sp [1].data.p)
4178 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4180 /* FIXME: value and size may be int64... */
4181 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4186 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4188 /* FIXME: value and size may be int64... */
4189 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4192 /* FIXME: implement */
4197 * need to clarify what this should actually do:
4198 * start the search from the last found handler in
4199 * this method or continue in the caller or what.
4200 * Also, do we need to run finally/fault handlers after a retrow?
4201 * Well, this implementation will follow the usual search
4202 * for an handler, considering the current ip as throw spot.
4203 * We need to NULL frame->ex_handler for the later code to
4204 * actually run the new found handler.
4206 frame->ex_handler = NULL;
4207 THROW_EX (frame->ex, ip - 1);
4209 case CEE_UNUSED: ves_abort(); break;
4214 token = read32 (ip);
4216 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4217 MonoType *type = mono_type_create_from_typespec (image, token);
4218 sp->data.i = mono_type_size (type, &align);
4219 mono_metadata_free_type (type);
4221 MonoClass *szclass = mono_class_get (image, token);
4222 mono_class_init (szclass);
4223 if (!szclass->valuetype)
4224 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4225 sp->data.i = mono_class_value_size (szclass, &align);
4231 case CEE_REFANYTYPE: ves_abort(); break;
4233 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4240 g_assert_not_reached ();
4242 * Exception handling code.
4243 * The exception object is stored in frame->ex.
4250 MonoInvocation *inv;
4251 MonoMethodHeader *hd;
4252 MonoExceptionClause *clause;
4258 g_print ("* Handling exception '%s' at IL_%04x\n", mono_object_class (frame->ex)->name, frame->ip - header->code);
4260 if (die_on_exception)
4263 for (inv = frame; inv; inv = inv->parent) {
4264 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4266 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4268 hd = ((MonoMethodNormal*)inv->method)->header;
4269 ip_offset = inv->ip - hd->code;
4270 for (i = 0; i < hd->num_clauses; ++i) {
4271 clause = &hd->clauses [i];
4272 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4273 if (!clause->flags) {
4274 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4276 * OK, we found an handler, now we need to execute the finally
4277 * and fault blocks before branching to the handler code.
4279 inv->ex_handler = clause;
4282 g_print ("* Found handler at '%s'\n", inv->method->name);
4286 * It seems that if the catch handler is found in the same method,
4287 * it gets executed before the finally handler.
4292 goto handle_finally;
4295 /* FIXME: handle filter clauses */
4302 * If we get here, no handler was found: print a stack trace.
4304 for (inv = frame; inv; inv = inv->parent) {
4305 if (inv->invoke_trap)
4306 goto handle_finally;
4309 ex_obj = (MonoObject*)frame->ex;
4310 mono_unhandled_exception (ex_obj);
4317 MonoExceptionClause *clause;
4321 g_print ("* Handle finally\n");
4323 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4324 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4328 ip_offset = frame->ip - header->code;
4330 for (i = 0; i < header->num_clauses; ++i) {
4331 clause = &header->clauses [i];
4332 if (clause == frame->ex_handler)
4334 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code))) {
4335 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4336 ip = header->code + clause->handler_offset;
4337 finally_ips = g_slist_append (finally_ips, (gpointer) ip);
4340 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4346 ip = finally_ips->data;
4347 finally_ips = g_slist_remove (finally_ips, ip);
4352 * If an exception is set, we need to execute the fault handler, too,
4353 * otherwise, we continue normally.
4364 MonoExceptionClause *clause;
4368 g_print ("* Handle fault\n");
4370 ip_offset = frame->ip - header->code;
4371 for (i = 0; i < header->num_clauses; ++i) {
4372 clause = &header->clauses [i];
4373 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4374 ip = header->code + clause->handler_offset;
4377 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4383 * If the handler for the exception was found in this method, we jump
4384 * to it right away, otherwise we return and let the caller run
4385 * the finally, fault and catch blocks.
4386 * This same code should be present in the endfault opcode, but it
4387 * is corrently not assigned in the ECMA specs: LAMESPEC.
4389 if (frame->ex_handler) {
4392 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4394 ip = header->code + frame->ex_handler->handler_offset;
4397 sp->data.p = frame->ex;
4401 if (!frame->parent) {
4402 /* Pass the exception though the managed barrier if possible */
4403 MonoInvocation *parent = TlsGetValue (frame_thread_id);
4405 parent->ex = frame->ex;
4406 longjmp (*(jmp_buf*)parent->locals, 1);
4417 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4419 MonoImage *image = assembly->image;
4420 MonoCLIImageInfo *iinfo;
4422 MonoObject *exc = NULL;
4425 iinfo = image->image_info;
4426 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4428 g_error ("No entry point method found in %s", image->name);
4430 rval = mono_runtime_run_main (method, argc, argv, &exc);
4439 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4440 "Usage is: mint [options] executable args...\n\n", VERSION);
4442 "Runtime Debugging:\n"
4447 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4450 " --traceclassinit\n"
4453 " --debug method_name\n"
4459 " --config filename load the specified config file instead of the default\n"
4460 " --workers n maximum number of worker threads\n"
4467 test_load_class (MonoImage* image)
4469 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4473 for (i = 1; i <= t->rows; ++i) {
4474 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4475 mono_class_init (klass);
4480 static MonoException * segv_exception = NULL;
4483 segv_handler (int signum)
4485 signal (signum, segv_handler);
4486 mono_raise_exception (segv_exception);
4490 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4491 MonoReflectionMethod **method,
4492 gint32 *iloffset, gint32 *native_offset,
4493 MonoString **file, gint32 *line, gint32 *column)
4506 *file = mono_string_new (mono_domain_get (), "unknown");
4512 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4520 int enable_debugging;
4526 static void main_thread_handler (gpointer user_data)
4528 MainThreadArgs *main_args=(MainThreadArgs *)user_data;
4529 MonoAssembly *assembly;
4532 if (main_args->enable_debugging)
4533 mono_debug_init (main_args->domain, MONO_DEBUG_FORMAT_MONO);
4535 assembly = mono_domain_assembly_open (main_args->domain,
4539 fprintf (stderr, "Can not open image %s\n", main_args->file);
4543 if (main_args->enable_debugging)
4544 mono_debug_init_2 (assembly);
4547 test_load_class (assembly->image);
4549 error = mono_verify_corlib ();
4551 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
4554 segv_exception = mono_get_exception_null_reference ();
4555 segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
4556 signal (SIGSEGV, segv_handler);
4558 ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
4563 mono_runtime_install_handlers (void)
4565 /* FIXME: anything to do here? */
4569 quit_function (MonoDomain *domain, gpointer user_data)
4571 mono_profiler_shutdown ();
4573 mono_runtime_cleanup (domain);
4574 mono_domain_unload (domain, TRUE);
4578 static CRITICAL_SECTION ms;
4581 main (int argc, char *argv [])
4584 int retval = 0, i, ocount = 0;
4585 char *file, *config_file = NULL;
4586 int enable_debugging = FALSE;
4587 MainThreadArgs main_args;
4592 for (i = 1; i < argc && argv [i][0] == '-'; i++){
4593 if (strcmp (argv [i], "--trace") == 0)
4595 if (strcmp (argv [i], "--noptr") == 0)
4596 global_no_pointers = 1;
4597 if (strcmp (argv [i], "--traceops") == 0)
4599 if (strcmp (argv [i], "--dieonex") == 0) {
4600 die_on_exception = 1;
4601 enable_debugging = 1;
4603 if (strcmp (argv [i], "--print-vtable") == 0)
4604 mono_print_vtable = TRUE;
4605 if (strcmp (argv [i], "--profile") == 0)
4606 mono_profiler_load (NULL);
4607 if (strcmp (argv [i], "--opcode-count") == 0)
4609 if (strcmp (argv [i], "--config") == 0)
4610 config_file = argv [++i];
4611 if (strcmp (argv [i], "--workers") == 0) {
4612 mono_max_worker_threads = atoi (argv [++i]);
4613 if (mono_max_worker_threads < 1)
4614 mono_max_worker_threads = 1;
4616 if (strcmp (argv [i], "--help") == 0)
4619 if (strcmp (argv [i], "--debug") == 0) {
4620 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
4622 g_error ("Invalid method name '%s'", argv [i]);
4623 db_methods = g_list_append (db_methods, desc);
4633 g_set_prgname (file);
4634 mono_set_rootdir ();
4635 mono_config_parse (config_file);
4637 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
4638 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
4641 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
4642 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
4643 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
4645 frame_thread_id = TlsAlloc ();
4646 TlsSetValue (frame_thread_id, NULL);
4648 mono_install_compile_method (mono_create_method_pointer);
4649 mono_install_runtime_invoke (interp_mono_runtime_invoke);
4650 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
4652 mono_install_handler (interp_ex_handler);
4653 mono_install_stack_walk (interp_walk_stack);
4654 mono_runtime_install_cleanup (quit_function);
4656 metadata_section = &ms;
4657 InitializeCriticalSection (metadata_section);
4658 domain = mono_init (file);
4659 mono_runtime_init (domain, NULL, NULL);
4661 main_args.domain=domain;
4662 main_args.file=file;
4663 main_args.argc=argc-i;
4664 main_args.argv=argv+i;
4665 main_args.enable_debugging=enable_debugging;
4667 mono_runtime_exec_managed_code (domain, main_thread_handler,
4670 quit_function (domain, NULL);
4672 /* Get the return value from System.Environment.ExitCode */
4673 retval=mono_environment_exitcode_get ();
4677 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4678 fprintf (stderr, "fcall count: %ld\n", fcall_count);