2 * PLEASE NOTE: This is a research prototype.
5 * interp.c: Interpreter for CIL byte codes
8 * Paolo Molaro (lupus@ximian.com)
9 * Miguel de Icaza (miguel@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2001 Ximian, Inc.
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/blob.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/io-layer/io-layer.h>
55 #include <mono/metadata/socket-io.h>
56 /*#include <mono/cli/types.h>*/
62 #define finite _finite
65 /* If true, then we output the opcodes as we interpret them */
66 static int global_tracing = 0;
68 static int debug_indent_level = 0;
71 * Pull the list of opcodes
73 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
77 #include "mono/cil/opcode.def"
82 #define GET_NATI(sp) ((sp).data.nati)
83 #define CSIZE(x) (sizeof (x) / 4)
85 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
87 (frame)->parent = (parent_frame); \
88 (frame)->obj = (obj_this); \
89 (frame)->stack_args = (method_args); \
90 (frame)->retval = (method_retval); \
91 (frame)->method = (mono_method); \
92 (frame)->ex_handler = NULL; \
94 (frame)->child = NULL; \
97 void ves_exec_method (MonoInvocation *frame);
99 typedef void (*ICallMethod) (MonoInvocation *frame);
101 static guint32 die_on_exception = 0;
102 static guint32 frame_thread_id = 0;
104 #define DEBUG_INTERP 1
107 static unsigned long opcode_count = 0;
108 static unsigned long fcall_count = 0;
109 static int break_on_method = 0;
110 static GList *db_methods = NULL;
117 for (h = 0; h < debug_indent_level; h++)
122 db_match_method (gpointer data, gpointer user_data)
124 MonoMethod *m = (MonoMethod*)user_data;
125 MonoMethodDesc *desc = data;
127 if (mono_method_desc_full_match (desc, m))
131 #define DEBUG_ENTER() \
133 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
134 if (break_on_method) tracing=2; \
135 break_on_method = 0; \
137 MonoClass *klass = frame->method->klass; \
138 char *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
139 debug_indent_level++; \
141 g_print ("(%d) Entering %s.%s::%s (", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
142 if (signature->hasthis) g_print ("%p ", frame->obj); \
143 g_print ("%s)\n", args); \
146 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
147 mono_profiler_method_enter (frame->method);
149 #define DEBUG_LEAVE() \
151 MonoClass *klass = frame->method->klass; \
153 if (signature->ret->type != MONO_TYPE_VOID) \
154 args = dump_stack (frame->retval, frame->retval + 1); \
156 args = g_strdup (""); \
158 g_print ("(%d) Leaving %s.%s::%s", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
159 g_print (" => %s\n", args); \
161 debug_indent_level--; \
163 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
164 mono_profiler_method_leave (frame->method);
168 #define DEBUG_ENTER()
169 #define DEBUG_LEAVE()
174 interp_ex_handler (MonoException *ex) {
175 MonoInvocation *frame = TlsGetValue (frame_thread_id);
177 longjmp (*(jmp_buf*)frame->locals, 1);
181 ves_real_abort (int line, MonoMethod *mh,
182 const unsigned char *ip, stackval *stack, stackval *sp)
184 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
185 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
186 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
187 ip-mm->header->code);
188 g_print ("0x%04x %02x\n",
189 ip-mm->header->code, *ip);
191 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
193 #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);
196 interp_create_remoting_trampoline (MonoMethod *method)
202 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
208 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
212 klass = obj->vtable->klass;
213 vtable = (MonoMethod **)obj->vtable->vtable;
215 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
216 return *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
219 g_assert (vtable [m->slot]);
221 return vtable [m->slot];
225 stackval_from_data (MonoType *type, stackval *result, char *data)
228 switch (type->type) {
229 case MONO_TYPE_OBJECT:
230 case MONO_TYPE_CLASS:
231 case MONO_TYPE_STRING:
232 case MONO_TYPE_ARRAY:
233 case MONO_TYPE_SZARRAY:
234 result->type = VAL_OBJ;
237 result->type = VAL_VALUETA;
240 result->data.p = *(gpointer*)data;
241 result->data.vt.klass = mono_class_from_mono_type (type);
244 switch (type->type) {
248 result->type = VAL_I32;
249 result->data.i = *(gint8*)data;
252 case MONO_TYPE_BOOLEAN:
253 result->type = VAL_I32;
254 result->data.i = *(guint8*)data;
257 result->type = VAL_I32;
258 result->data.i = *(gint16*)data;
262 result->type = VAL_I32;
263 result->data.i = *(guint16*)data;
266 result->type = VAL_I32;
267 result->data.i = *(gint32*)data;
272 result->type = VAL_TP;
273 result->data.p = *(gpointer*)data;
276 result->type = VAL_I32;
277 result->data.i = *(guint32*)data;
280 result->type = VAL_DOUBLE;
281 result->data.f = *(float*)data;
285 result->type = VAL_I64;
286 result->data.l = *(gint64*)data;
289 result->type = VAL_DOUBLE;
290 result->data.f = *(double*)data;
292 case MONO_TYPE_STRING:
293 case MONO_TYPE_SZARRAY:
294 case MONO_TYPE_CLASS:
295 case MONO_TYPE_OBJECT:
296 case MONO_TYPE_ARRAY:
297 result->type = VAL_OBJ;
298 result->data.p = *(gpointer*)data;
299 result->data.vt.klass = mono_class_from_mono_type (type);
301 case MONO_TYPE_VALUETYPE:
302 if (type->data.klass->enumtype) {
303 return stackval_from_data (type->data.klass->enum_basetype, result, data);
305 result->type = VAL_VALUET;
306 result->data.vt.klass = type->data.klass;
307 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
311 g_warning ("got type 0x%02x", type->type);
312 g_assert_not_reached ();
317 stackval_to_data (MonoType *type, stackval *val, char *data)
320 gpointer *p = (gpointer*)data;
324 switch (type->type) {
327 guint8 *p = (guint8*)data;
331 case MONO_TYPE_BOOLEAN: {
332 guint8 *p = (guint8*)data;
333 *p = (val->data.i != 0);
338 case MONO_TYPE_CHAR: {
339 guint16 *p = (guint16*)data;
343 #if SIZEOF_VOID_P == 4
349 gint32 *p = (gint32*)data;
353 #if SIZEOF_VOID_P == 8
359 gint64 *p = (gint64*)data;
364 float *p = (float*)data;
369 double *p = (double*)data;
373 case MONO_TYPE_STRING:
374 case MONO_TYPE_SZARRAY:
375 case MONO_TYPE_CLASS:
376 case MONO_TYPE_OBJECT:
377 case MONO_TYPE_ARRAY:
378 case MONO_TYPE_PTR: {
379 gpointer *p = (gpointer*)data;
383 case MONO_TYPE_VALUETYPE:
384 if (type->data.klass->enumtype) {
385 return stackval_to_data (type->data.klass->enum_basetype, val, data);
387 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
391 g_warning ("got type %x", type->type);
392 g_assert_not_reached ();
397 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
400 guint32 *lower_bounds;
403 lengths = alloca (sizeof (guint32) * klass->rank * 2);
404 for (i = 0; i < sig->param_count; ++i) {
405 lengths [i] = values->data.i;
408 if (klass->rank == sig->param_count) {
409 /* Only lengths provided. */
412 /* lower bounds are first. */
413 lower_bounds = lengths;
414 lengths += klass->rank;
416 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
420 ves_array_set (MonoInvocation *frame)
422 stackval *sp = frame->stack_args;
426 gint32 i, t, pos, esize;
432 ac = o->vtable->klass;
434 g_assert (ac->rank >= 1);
437 if (ao->bounds != NULL) {
438 pos -= ao->bounds [0].lower_bound;
439 for (i = 1; i < ac->rank; i++) {
440 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
441 ao->bounds [i].length) {
442 g_warning ("wrong array index");
443 g_assert_not_reached ();
445 pos = pos*ao->bounds [i].length + sp [i].data.i -
446 ao->bounds [i].lower_bound;
450 esize = mono_array_element_size (ac);
451 ea = mono_array_addr_with_size (ao, esize, pos);
453 mt = frame->method->signature->params [ac->rank];
454 stackval_to_data (mt, &sp [ac->rank], ea);
458 ves_array_get (MonoInvocation *frame)
460 stackval *sp = frame->stack_args;
464 gint32 i, 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 pos = pos*ao->bounds [i].length + sp [i].data.i -
479 ao->bounds [i].lower_bound;
482 esize = mono_array_element_size (ac);
483 ea = mono_array_addr_with_size (ao, esize, pos);
485 mt = frame->method->signature->ret;
486 stackval_from_data (mt, frame->retval, ea);
490 ves_array_element_address (MonoInvocation *frame)
492 stackval *sp = frame->stack_args;
496 gint32 i, pos, esize;
501 ac = o->vtable->klass;
503 g_assert (ac->rank >= 1);
506 if (ao->bounds != NULL) {
507 pos -= ao->bounds [0].lower_bound;
508 for (i = 1; i < ac->rank; i++)
509 pos = pos*ao->bounds [i].length + sp [i].data.i -
510 ao->bounds [i].lower_bound;
513 esize = mono_array_element_size (ac);
514 ea = mono_array_addr_with_size (ao, esize, pos);
516 frame->retval->type = VAL_TP;
517 frame->retval->data.p = ea;
521 ves_pinvoke_method (MonoInvocation *frame)
527 TlsSetValue (frame_thread_id, frame->args);
530 if (!frame->method->info)
531 frame->method->info = mono_create_trampoline (frame->method, 0);
532 func = (MonoPIFunc)frame->method->info;
535 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
536 * locals will point to the jmp_buf, while args will point to the previous
537 * MonoInvocation frame: this is needed to make exception searching work across
538 * managed/unmanaged boundaries.
540 frame->locals = (char*)&env;
541 frame->args = (char*)TlsGetValue (frame_thread_id);
542 TlsSetValue (frame_thread_id, frame);
544 func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
545 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
546 TlsSetValue (frame_thread_id, frame->args);
551 * runtime specifies that the implementation of the method is automatically
552 * provided by the runtime and is primarily used for the methods of delegates.
555 ves_runtime_method (MonoInvocation *frame)
557 const char *name = frame->method->name;
558 MonoObject *obj = (MonoObject*)frame->obj;
559 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
562 mono_class_init (mono_defaults.multicastdelegate_class);
564 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
565 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
566 delegate->delegate.target = frame->stack_args[0].data.p;
567 delegate->delegate.method_ptr = frame->stack_args[1].data.p;
568 delegate->delegate.method_info = mono_method_get_object (mono_object_domain(delegate), mono_method_pointer_get (delegate->delegate.method_ptr));
571 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
572 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
578 code = (guchar*)delegate->delegate.method_ptr;
579 method = mono_method_pointer_get (code);
581 /* FIXME: check for NULL method */
582 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
583 ves_exec_method (&call);
586 method->addr = mono_create_trampoline (method, 1);
588 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
589 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, delegate->target, frame->stack_args);
591 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
592 delegate = delegate->prev;
596 g_error ("Don't know how to exec runtime method %s.%s::%s",
597 frame->method->klass->name_space, frame->method->klass->name,
598 frame->method->name);
602 dump_stack (stackval *stack, stackval *sp)
605 GString *str = g_string_new ("");
608 return g_string_free (str, FALSE);
612 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
613 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
614 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
615 case VAL_VALUET: g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt); break;
618 MonoObject *obj = s->data.p;
619 if (obj && obj->klass == mono_defaults.string_class) {
620 char *str = mono_string_to_utf8 ((MonoString*)obj);
621 printf ("\"%s\" ", str);
627 default: g_string_sprintfa (str, "[%p] ", s->data.p); break;
631 return g_string_free (str, FALSE);
635 dump_frame (MonoInvocation *inv)
637 GString *str = g_string_new ("");
640 for (i = 0; inv; inv = inv->parent, ++i) {
641 MonoClass *k = inv->method->klass;
644 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
645 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
649 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
651 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
654 opname = mono_opcode_names [codep];
655 codep = inv->ip - hd->code;
657 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
658 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
659 k->name_space, k->name, inv->method->name, args);
662 return g_string_free (str, FALSE);
665 static CRITICAL_SECTION metadata_lock;
668 INLINE_STRING_LENGTH = 1,
671 INLINE_TYPE_ELEMENT_TYPE
675 calc_offsets (MonoImage *image, MonoMethod *method)
677 int i, align, size, offset = 0;
678 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
679 MonoMethodSignature *signature = method->signature;
680 int hasthis = signature->hasthis;
681 register const unsigned char *ip, *end;
682 const MonoOpcode *opcode;
686 MonoDomain *domain = mono_domain_get ();
689 mono_profiler_method_jit (method); /* sort of... */
690 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
691 for (i = 0; i < header->num_locals; ++i) {
692 size = mono_type_size (header->locals [i], &align);
694 offset &= ~(align - 1);
695 offsets [2 + i] = offset;
698 offsets [0] = offset;
701 offset += sizeof (gpointer) - 1;
702 offset &= ~(sizeof (gpointer) - 1);
703 offsets [2 + header->num_locals] = offset;
704 offset += sizeof (gpointer);
706 for (i = 0; i < signature->param_count; ++i) {
707 size = mono_type_size (signature->params [i], &align);
709 offset &= ~(align - 1);
710 offsets [2 + hasthis + header->num_locals + i] = offset;
713 offsets [1] = offset;
715 EnterCriticalSection (&metadata_lock);
716 /* intern the strings in the method. */
718 end = ip + header->code_size;
725 opcode = &mono_opcodes [i];
726 switch (opcode->argument) {
730 case MonoInlineString:
731 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
735 class = mono_class_get (image, read32 (ip + 1));
736 mono_class_init (class);
737 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
738 mono_class_vtable (domain, class);
741 case MonoInlineField:
742 token = read32 (ip + 1);
743 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
744 mono_field_from_memberref (image, token, &class);
746 class = mono_class_get (image,
747 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
749 mono_class_init (class);
750 mono_class_vtable (domain, class);
753 case MonoInlineMethod:
754 m = mono_get_method (image, read32 (ip + 1), NULL);
755 mono_class_init (m->klass);
756 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
757 mono_class_vtable (domain, m->klass);
762 case MonoShortInlineR:
764 case MonoInlineBrTarget:
770 case MonoShortInlineVar:
771 case MonoShortInlineI:
772 case MonoShortInlineBrTarget:
775 case MonoInlineSwitch: {
788 g_assert_not_reached ();
792 method->info = offsets;
795 * We store the inline info in addr, since it's unused for IL methods.
797 if (method->klass == mono_defaults.string_class) {
798 if (strcmp (method->name, "get_Length") == 0)
799 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
800 } else if (method->klass == mono_defaults.array_class) {
801 if (strcmp (method->name, "get_Length") == 0)
802 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
803 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
804 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
805 } else if (method->klass == mono_defaults.monotype_class) {
806 if (strcmp (method->name, "GetElementType") == 0)
807 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
809 LeaveCriticalSection (&metadata_lock);
810 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
813 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
814 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
816 #define ARG_POS(n) (args_pointers [(n)])
817 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
818 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
820 #define THROW_EX(exception,ex_ip) \
823 frame->ip = (ex_ip); \
824 stack_trace = dump_frame (frame); \
825 frame->ex = (MonoException*)(exception); \
826 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
827 g_free (stack_trace); \
828 goto handle_exception; \
831 typedef struct _vtallocation vtallocation;
833 struct _vtallocation {
836 char data [MONO_ZERO_LEN_ARRAY];
840 * we don't use vtallocation->next, yet
842 #define vt_alloc(vtype,sp) \
843 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
844 if (!(vtype)->byref) { \
846 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
847 if (!vtalloc || vtalloc->size <= size) { \
848 vtalloc = alloca (sizeof (vtallocation) + size); \
849 vtalloc->size = size; \
850 g_assert (size < 10000); \
852 (sp)->data.vt.vt = vtalloc->data; \
855 (sp)->data.vt.klass = (vtype)->data.klass; \
859 #define vt_free(sp) \
861 if ((sp)->type == VAL_VALUET) { \
862 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
867 verify_method (MonoMethod *m)
869 GSList *errors, *tmp;
870 MonoVerifyInfo *info;
872 errors = mono_method_verify (m, MONO_VERIFY_ALL);
874 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
875 for (tmp = errors; tmp; tmp = tmp->next) {
877 g_print ("%s\n", info->message);
881 mono_free_verify_list (errors);
884 #define MYGUINT64_MAX 18446744073709551615UL
885 #define MYGINT64_MAX 9223372036854775807LL
886 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
888 #define MYGUINT32_MAX 4294967295U
889 #define MYGINT32_MAX 2147483647
890 #define MYGINT32_MIN (-MYGINT32_MAX -1)
892 #define CHECK_ADD_OVERFLOW(a,b) \
893 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
894 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
896 #define CHECK_ADD_OVERFLOW_UN(a,b) \
897 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
899 #define CHECK_ADD_OVERFLOW64(a,b) \
900 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
901 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
903 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
904 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
907 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params)
909 MonoInvocation frame;
910 MonoObject *retval = NULL;
911 MonoMethodSignature *sig = method->signature;
912 MonoClass *klass = mono_class_from_mono_type (sig->ret);
913 int i, type, isobject = 0;
916 stackval *args = alloca (sizeof (stackval) * sig->param_count);
918 /* FIXME: Set frame for execption handling. */
920 switch (sig->ret->type) {
923 case MONO_TYPE_STRING:
924 case MONO_TYPE_OBJECT:
925 case MONO_TYPE_CLASS:
926 case MONO_TYPE_ARRAY:
927 case MONO_TYPE_SZARRAY:
930 case MONO_TYPE_VALUETYPE:
931 retval = mono_object_new (mono_domain_get (), klass);
932 ret = ((char*)retval) + sizeof (MonoObject);
933 if (!sig->ret->data.klass->enumtype)
934 result.data.vt.vt = ret;
937 retval = mono_object_new (mono_domain_get (), klass);
938 ret = ((char*)retval) + sizeof (MonoObject);
942 for (i = 0; i < sig->param_count; ++i) {
943 if (sig->params [i]->byref) {
944 args [i].type = VAL_POINTER;
945 args [i].data.p = params [i];
948 type = sig->params [i]->type;
953 case MONO_TYPE_BOOLEAN:
954 args [i].type = VAL_I32;
955 args [i].data.i = *(MonoBoolean*)params [i];
956 args [i].data.vt.klass = NULL;
961 args [i].type = VAL_I32;
962 args [i].data.i = *(gint16*)params [i];
963 args [i].data.vt.klass = NULL;
965 #if SIZEOF_VOID_P == 4
966 case MONO_TYPE_U: /* use VAL_POINTER? */
971 args [i].type = VAL_I32;
972 args [i].data.i = *(gint32*)params [i];
973 args [i].data.vt.klass = NULL;
975 #if SIZEOF_VOID_P == 8
981 args [i].type = VAL_I64;
982 args [i].data.l = *(gint64*)params [i];
983 args [i].data.vt.klass = NULL;
985 case MONO_TYPE_VALUETYPE:
986 if (sig->params [i]->data.klass->enumtype) {
987 type = sig->params [i]->data.klass->enum_basetype->type;
990 g_warning ("generic valutype %s not handled in runtime invoke", sig->params [i]->data.klass->name);
993 case MONO_TYPE_STRING:
994 case MONO_TYPE_CLASS:
995 case MONO_TYPE_ARRAY:
996 case MONO_TYPE_SZARRAY:
997 case MONO_TYPE_OBJECT:
998 args [i].type = VAL_OBJ;
999 args [i].data.p = params [i];
1000 args [i].data.vt.klass = NULL;
1003 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1007 INIT_FRAME(&frame,NULL,obj,args,&result,method);
1008 ves_exec_method (&frame);
1009 if (sig->ret->type == MONO_TYPE_VOID)
1012 return result.data.p;
1013 stackval_to_data (sig->ret, &result, ret);
1018 * Need to optimize ALU ops when natural int == int32
1020 * IDEA: if we maintain a stack of ip, sp to be checked
1021 * in the return opcode, we could inline simple methods that don't
1022 * use the stack or local variables....
1024 * The {,.S} versions of many opcodes can/should be merged to reduce code
1029 ves_exec_method (MonoInvocation *frame)
1031 MonoDomain *domain = mono_domain_get ();
1032 MonoInvocation child_frame;
1033 MonoMethodHeader *header;
1034 MonoMethodSignature *signature;
1036 const unsigned char *endfinally_ip;
1037 register const unsigned char *ip;
1038 register stackval *sp;
1039 void **args_pointers;
1041 gint il_ins_count = -1;
1042 gint tracing = global_tracing;
1043 unsigned char tail_recursion = 0;
1044 unsigned char unaligned_address = 0;
1045 unsigned char volatile_address = 0;
1046 vtallocation *vtalloc = NULL;
1049 signature = frame->method->signature;
1053 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1054 if (!frame->method->addr) {
1055 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1059 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1060 ves_pinvoke_method (frame);
1062 ICallMethod icall = (ICallMethod)frame->method->addr;
1066 goto handle_exception;
1071 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1072 if (!frame->method->addr) {
1073 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1077 ves_pinvoke_method (frame);
1079 goto handle_exception;
1084 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1085 ves_runtime_method (frame);
1087 goto handle_exception;
1092 /*verify_method (frame->method);*/
1094 header = ((MonoMethodNormal *)frame->method)->header;
1095 image = frame->method->klass->image;
1097 if (!frame->method->info)
1098 calc_offsets (image, frame->method);
1099 offsets = frame->method->info;
1102 * with alloca we get the expected huge performance gain
1103 * stackval *stack = g_new0(stackval, header->max_stack);
1105 g_assert (header->max_stack < 10000);
1106 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1108 if (header->num_locals) {
1109 g_assert (offsets [0] < 10000);
1110 frame->locals = alloca (offsets [0]);
1112 * yes, we do it unconditionally, because it needs to be done for
1113 * some cases anyway and checking for that would be even slower.
1115 memset (frame->locals, 0, offsets [0]);
1118 * Copy args from stack_args to args.
1120 if (signature->param_count || signature->hasthis) {
1122 int has_this = signature->hasthis;
1124 g_assert (offsets [1] < 10000);
1125 frame->args = alloca (offsets [1]);
1126 g_assert ((signature->param_count + has_this) < 1000);
1127 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1130 this_arg = args_pointers [0] = frame->args;
1131 *this_arg = frame->obj;
1133 for (i = 0; i < signature->param_count; ++i) {
1134 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1135 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this]);
1139 child_frame.parent = frame;
1140 frame->child = &child_frame;
1147 * using while (ip < end) may result in a 15% performance drop,
1148 * but it may be useful for debug
1152 /*g_assert (sp >= stack);*/
1157 if (sp > frame->stack) {
1159 ins = dump_stack (frame->stack, sp);
1160 g_print ("(%d) stack: %s\n", GetCurrentThreadId(), ins);
1164 ins = mono_disasm_code_one (NULL, frame->method, ip);
1165 g_print ("(%d) %s", GetCurrentThreadId(), ins);
1168 if (il_ins_count > 0)
1169 if (!(--il_ins_count))
1179 G_BREAKPOINT (); /* this is not portable... */
1184 CASE (CEE_LDARG_3) {
1185 int n = (*ip)-CEE_LDARG_0;
1187 vt_alloc (ARG_TYPE (signature, n), sp);
1188 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
1195 CASE (CEE_LDLOC_3) {
1196 int n = (*ip)-CEE_LDLOC_0;
1198 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1200 sp->data.i = *(gint32*) LOCAL_POS (n);
1204 vt_alloc (LOCAL_TYPE (header, n), sp);
1205 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1213 CASE (CEE_STLOC_3) {
1214 int n = (*ip)-CEE_STLOC_0;
1217 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1218 gint32 *p = (gint32*)LOCAL_POS (n);
1222 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1229 vt_alloc (ARG_TYPE (signature, *ip), sp);
1230 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1234 CASE (CEE_LDARGA_S) {
1239 t = ARG_TYPE (signature, *ip);
1240 c = mono_class_from_mono_type (t);
1241 sp->data.vt.klass = c;
1242 sp->data.vt.vt = ARG_POS (*ip);
1245 sp->type = VAL_VALUETA;
1256 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1262 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1263 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1267 CASE (CEE_LDLOCA_S) {
1272 t = LOCAL_TYPE (header, *ip);
1273 c = mono_class_from_mono_type (t);
1274 sp->data.vt.klass = c;
1275 sp->data.p = LOCAL_POS (*ip);
1278 sp->type = VAL_VALUETA;
1289 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1297 sp->data.vt.klass = NULL;
1300 CASE (CEE_LDC_I4_M1)
1316 sp->data.i = (*ip) - CEE_LDC_I4_0;
1323 sp->data.i = *(const gint8 *)ip;
1330 sp->data.i = read32 (ip);
1337 sp->data.l = read64 (ip);
1344 sp->type = VAL_DOUBLE;
1353 sp->type = VAL_DOUBLE;
1354 readr8(ip, &sp->data.f);
1358 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1360 if (sp [-1].type == VAL_VALUET) {
1361 MonoClass *c = sp [-1].data.vt.klass;
1362 vt_alloc (&c->byval_arg, sp);
1363 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1375 CASE (CEE_JMP) ves_abort(); BREAK;
1376 CASE (CEE_CALLVIRT) /* Fall through */
1377 CASE (CEE_CALLI) /* Fall through */
1379 MonoMethodSignature *csignature;
1381 stackval *endsp = sp;
1383 int virtual = *ip == CEE_CALLVIRT;
1384 int calli = *ip == CEE_CALLI;
1387 * We ignore tail recursion for now.
1394 token = read32 (ip);
1397 unsigned char *code;
1400 child_frame.method = mono_method_pointer_get (code);
1401 /* check for NULL with native code */
1402 csignature = child_frame.method->signature;
1404 child_frame.method = mono_get_method (image, token, NULL);
1405 if (!child_frame.method)
1406 THROW_EX (mono_get_exception_missing_method (), ip -5);
1407 csignature = child_frame.method->signature;
1409 stackval *this_arg = &sp [-csignature->param_count-1];
1410 if (!this_arg->data.p)
1411 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1412 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1413 if (!child_frame.method)
1414 THROW_EX (mono_get_exception_missing_method (), ip -5);
1417 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1418 /* decrement by the actual number of args */
1419 if (csignature->param_count) {
1420 sp -= csignature->param_count;
1421 child_frame.stack_args = sp;
1423 child_frame.stack_args = NULL;
1425 if (csignature->hasthis) {
1426 g_assert (sp >= frame->stack);
1429 * It may also be a TP from LD(S)FLDA
1430 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1432 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1433 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1435 child_frame.obj = sp->data.p;
1437 child_frame.obj = NULL;
1439 if (csignature->ret->type != MONO_TYPE_VOID) {
1440 vt_alloc (csignature->ret, &retval);
1441 child_frame.retval = &retval;
1443 child_frame.retval = NULL;
1446 child_frame.ex = NULL;
1447 child_frame.ex_handler = NULL;
1449 if (csignature->hasthis && sp->type == VAL_OBJ &&
1450 ((MonoObject *)sp->data.p)->vtable->klass ==
1451 mono_defaults.transparent_proxy_class) {
1452 /* implement remoting */
1453 g_assert_not_reached ();
1455 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1456 case INLINE_STRING_LENGTH:
1457 retval.type = VAL_I32;
1458 retval.data.i = ((MonoString*)sp->data.p)->length;
1459 //g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);
1461 case INLINE_ARRAY_LENGTH:
1462 retval.type = VAL_I32;
1463 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1465 case INLINE_ARRAY_RANK:
1466 retval.type = VAL_I32;
1467 retval.data.i = mono_object_class (sp->data.p)->rank;
1469 case INLINE_TYPE_ELEMENT_TYPE:
1470 retval.type = VAL_OBJ;
1472 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1473 retval.data.vt.klass = NULL;
1474 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1475 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1476 else if (c->element_class)
1477 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1479 retval.data.p = NULL;
1483 ves_exec_method (&child_frame);
1487 while (endsp > sp) {
1492 if (child_frame.ex) {
1494 * An exception occurred, need to run finally, fault and catch handlers..
1496 frame->ex = child_frame.ex;
1497 goto handle_finally;
1500 /* need to handle typedbyref ... */
1501 if (csignature->ret->type != MONO_TYPE_VOID) {
1508 if (signature->ret->type != MONO_TYPE_VOID) {
1510 if (sp->type == VAL_VALUET) {
1511 /* the caller has already allocated the memory */
1512 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1515 *frame->retval = *sp;
1518 if (sp > frame->stack)
1519 g_warning ("more values on stack: %d", sp-frame->stack);
1523 CASE (CEE_BR_S) /* Fall through */
1525 if (*ip == CEE_BR) {
1527 ip += (gint32) read32(ip);
1531 ip += (signed char) *ip;
1535 CASE (CEE_BRFALSE) /* Fall through */
1536 CASE (CEE_BRFALSE_S) {
1538 int near_jump = *ip == CEE_BRFALSE_S;
1542 case VAL_I32: result = sp->data.i == 0; break;
1543 case VAL_I64: result = sp->data.l == 0; break;
1544 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1545 default: result = sp->data.p == NULL; break;
1549 ip += (signed char)*ip;
1551 ip += (gint32) read32 (ip);
1553 ip += near_jump ? 1: 4;
1556 CASE (CEE_BRTRUE) /* Fall through */
1557 CASE (CEE_BRTRUE_S) {
1559 int near_jump = *ip == CEE_BRTRUE_S;
1563 case VAL_I32: result = sp->data.i != 0; break;
1564 case VAL_I64: result = sp->data.l != 0; break;
1565 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1566 default: result = sp->data.p != NULL; break;
1570 ip += (signed char)*ip;
1572 ip += (gint32) read32 (ip);
1574 ip += near_jump ? 1: 4;
1577 CASE (CEE_BEQ) /* Fall through */
1580 int near_jump = *ip == CEE_BEQ_S;
1583 if (sp->type == VAL_I32)
1584 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1585 else if (sp->type == VAL_I64)
1586 result = sp [0].data.l == sp [1].data.l;
1587 else if (sp->type == VAL_DOUBLE)
1588 result = sp [0].data.f == sp [1].data.f;
1590 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1593 ip += (signed char)*ip;
1595 ip += (gint32) read32 (ip);
1597 ip += near_jump ? 1: 4;
1600 CASE (CEE_BGE) /* Fall through */
1603 int near_jump = *ip == CEE_BGE_S;
1606 if (sp->type == VAL_I32)
1607 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1608 else if (sp->type == VAL_I64)
1609 result = sp [0].data.l >= sp [1].data.l;
1610 else if (sp->type == VAL_DOUBLE)
1611 result = sp [0].data.f >= sp [1].data.f;
1613 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1616 ip += (signed char)*ip;
1618 ip += (gint32) read32 (ip);
1620 ip += near_jump ? 1: 4;
1623 CASE (CEE_BGT) /* Fall through */
1626 int near_jump = *ip == CEE_BGT_S;
1629 if (sp->type == VAL_I32)
1630 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1631 else if (sp->type == VAL_I64)
1632 result = sp [0].data.l > sp [1].data.l;
1633 else if (sp->type == VAL_DOUBLE)
1634 result = sp [0].data.f > sp [1].data.f;
1636 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1639 ip += (signed char)*ip;
1641 ip += (gint32) read32 (ip);
1643 ip += near_jump ? 1: 4;
1646 CASE (CEE_BLT) /* Fall through */
1649 int near_jump = *ip == CEE_BLT_S;
1652 if (sp->type == VAL_I32)
1653 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1654 else if (sp->type == VAL_I64)
1655 result = sp[0].data.l < sp[1].data.l;
1656 else if (sp->type == VAL_DOUBLE)
1657 result = sp[0].data.f < sp[1].data.f;
1659 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1662 ip += 1 + (signed char)*ip;
1664 ip += 4 + (gint32) read32 (ip);
1667 ip += near_jump ? 1: 4;
1671 CASE (CEE_BLE) /* fall through */
1674 int near_jump = *ip == CEE_BLE_S;
1678 if (sp->type == VAL_I32)
1679 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1680 else if (sp->type == VAL_I64)
1681 result = sp [0].data.l <= sp [1].data.l;
1682 else if (sp->type == VAL_DOUBLE)
1683 result = sp [0].data.f <= sp [1].data.f;
1686 * FIXME: here and in other places GET_NATI on the left side
1687 * _will_ be wrong when we change the macro to work on 64 bits
1690 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1694 ip += (signed char)*ip;
1696 ip += (gint32) read32 (ip);
1698 ip += near_jump ? 1: 4;
1701 CASE (CEE_BNE_UN) /* Fall through */
1702 CASE (CEE_BNE_UN_S) {
1704 int near_jump = *ip == CEE_BNE_UN_S;
1707 if (sp->type == VAL_I32)
1708 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1709 else if (sp->type == VAL_I64)
1710 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1711 else if (sp->type == VAL_DOUBLE)
1712 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1713 (sp [0].data.f != sp [1].data.f);
1715 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1718 ip += (signed char)*ip;
1720 ip += (gint32) read32 (ip);
1722 ip += near_jump ? 1: 4;
1725 CASE (CEE_BGE_UN) /* Fall through */
1726 CASE (CEE_BGE_UN_S) {
1728 int near_jump = *ip == CEE_BGE_UN_S;
1731 if (sp->type == VAL_I32)
1732 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1733 else if (sp->type == VAL_I64)
1734 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1735 else if (sp->type == VAL_DOUBLE)
1736 result = !isless (sp [0].data.f,sp [1].data.f);
1738 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1741 ip += (signed char)*ip;
1743 ip += (gint32) read32 (ip);
1745 ip += near_jump ? 1: 4;
1748 CASE (CEE_BGT_UN) /* Fall through */
1749 CASE (CEE_BGT_UN_S) {
1751 int near_jump = *ip == CEE_BGT_UN_S;
1754 if (sp->type == VAL_I32)
1755 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1756 else if (sp->type == VAL_I64)
1757 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1758 else if (sp->type == VAL_DOUBLE)
1759 result = isgreater (sp [0].data.f, sp [1].data.f);
1761 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1764 ip += (signed char)*ip;
1766 ip += (gint32) read32 (ip);
1768 ip += near_jump ? 1: 4;
1771 CASE (CEE_BLE_UN) /* Fall through */
1772 CASE (CEE_BLE_UN_S) {
1774 int near_jump = *ip == CEE_BLE_UN_S;
1777 if (sp->type == VAL_I32)
1778 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1779 else if (sp->type == VAL_I64)
1780 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1781 else if (sp->type == VAL_DOUBLE)
1782 result = islessequal (sp [0].data.f, sp [1].data.f);
1784 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1787 ip += (signed char)*ip;
1789 ip += (gint32) read32 (ip);
1791 ip += near_jump ? 1: 4;
1794 CASE (CEE_BLT_UN) /* Fall through */
1795 CASE (CEE_BLT_UN_S) {
1797 int near_jump = *ip == CEE_BLT_UN_S;
1800 if (sp->type == VAL_I32)
1801 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1802 else if (sp->type == VAL_I64)
1803 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1804 else if (sp->type == VAL_DOUBLE)
1805 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1806 (sp [0].data.f < sp [1].data.f);
1808 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1811 ip += (signed char)*ip;
1813 ip += (gint32) read32 (ip);
1815 ip += near_jump ? 1: 4;
1820 const unsigned char *st;
1824 st = ip + sizeof (gint32) * n;
1826 if ((guint32)sp->data.i < n) {
1828 ip += sizeof (gint32) * (guint32)sp->data.i;
1829 offset = read32 (ip);
1838 sp[-1].type = VAL_I32;
1839 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1843 sp[-1].type = VAL_I32;
1844 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1848 sp[-1].type = VAL_I32;
1849 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1853 sp[-1].type = VAL_I32;
1854 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1856 CASE (CEE_LDIND_I4) /* Fall through */
1859 sp[-1].type = VAL_I32;
1860 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1864 sp[-1].type = VAL_I64;
1865 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1869 sp[-1].type = VAL_NATI;
1870 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1874 sp[-1].type = VAL_DOUBLE;
1875 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
1879 sp[-1].type = VAL_DOUBLE;
1880 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
1882 CASE (CEE_LDIND_REF)
1884 sp[-1].type = VAL_OBJ;
1885 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1886 sp[-1].data.vt.klass = NULL;
1888 CASE (CEE_STIND_REF) {
1896 CASE (CEE_STIND_I1) {
1901 *p = (gint8)sp[1].data.i;
1904 CASE (CEE_STIND_I2) {
1909 *p = (gint16)sp[1].data.i;
1912 CASE (CEE_STIND_I4) {
1920 CASE (CEE_STIND_I) {
1925 *p = (mono_i)sp[1].data.p;
1928 CASE (CEE_STIND_I8) {
1936 CASE (CEE_STIND_R4) {
1941 *p = (gfloat)sp[1].data.f;
1944 CASE (CEE_STIND_R8) {
1955 /* should probably consider the pointers as unsigned */
1956 if (sp->type == VAL_I32)
1957 sp [-1].data.i += GET_NATI (sp [0]);
1958 else if (sp->type == VAL_I64)
1959 sp [-1].data.l += sp [0].data.l;
1960 else if (sp->type == VAL_DOUBLE)
1961 sp [-1].data.f += sp [0].data.f;
1963 char *p = sp [-1].data.p;
1964 p += GET_NATI (sp [0]);
1971 /* should probably consider the pointers as unsigned */
1972 if (sp->type == VAL_I32)
1973 sp [-1].data.i -= GET_NATI (sp [0]);
1974 else if (sp->type == VAL_I64)
1975 sp [-1].data.l -= sp [0].data.l;
1976 else if (sp->type == VAL_DOUBLE)
1977 sp [-1].data.f -= sp [0].data.f;
1979 char *p = sp [-1].data.p;
1980 p -= GET_NATI (sp [0]);
1987 if (sp->type == VAL_I32)
1988 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
1989 else if (sp->type == VAL_I64)
1990 sp [-1].data.l *= sp [0].data.l;
1991 else if (sp->type == VAL_DOUBLE)
1992 sp [-1].data.f *= sp [0].data.f;
1997 if (sp->type == VAL_I32) {
1998 if (GET_NATI (sp [0]) == 0)
1999 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2000 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2001 } else if (sp->type == VAL_I64) {
2002 if (sp [0].data.l == 0)
2003 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2004 sp [-1].data.l /= sp [0].data.l;
2005 } else if (sp->type == VAL_DOUBLE) {
2006 /* set NaN is divisor is 0.0 */
2007 sp [-1].data.f /= sp [0].data.f;
2013 if (sp->type == VAL_I32) {
2015 if (GET_NATI (sp [0]) == 0)
2016 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2017 val = sp [-1].data.i;
2018 val /= (guint32)GET_NATI (sp [0]);
2019 sp [-1].data.i = val;
2020 } else if (sp->type == VAL_I64) {
2022 if (sp [0].data.l == 0)
2023 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2024 val = sp [-1].data.l;
2025 val /= (guint64)sp [0].data.l;
2026 sp [-1].data.l = val;
2027 } else if (sp->type == VAL_NATI) {
2029 if (GET_NATI (sp [0]) == 0)
2030 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2031 val = (mono_u)sp [-1].data.p;
2032 val /= (mono_u)sp [0].data.p;
2033 sp [-1].data.p = (gpointer)val;
2039 if (sp->type == VAL_I32) {
2040 if (GET_NATI (sp [0]) == 0)
2041 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2042 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2043 } else if (sp->type == VAL_I64) {
2044 if (sp [0].data.l == 0)
2045 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2046 sp [-1].data.l %= sp [0].data.l;
2047 } else if (sp->type == VAL_DOUBLE) {
2048 /* FIXME: what do we actually do here? */
2049 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2051 if (GET_NATI (sp [0]) == 0)
2052 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2053 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2059 if (sp->type == VAL_I32) {
2060 if (GET_NATI (sp [0]) == 0)
2061 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2062 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2063 } else if (sp->type == VAL_I64) {
2064 if (sp [0].data.l == 0)
2065 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2066 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2067 } else if (sp->type == VAL_DOUBLE) {
2068 /* unspecified behaviour according to the spec */
2070 if (GET_NATI (sp [0]) == 0)
2071 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2072 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2078 if (sp->type == VAL_I32)
2079 sp [-1].data.i &= GET_NATI (sp [0]);
2080 else if (sp->type == VAL_I64)
2081 sp [-1].data.l &= sp [0].data.l;
2083 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2088 if (sp->type == VAL_I32)
2089 sp [-1].data.i |= GET_NATI (sp [0]);
2090 else if (sp->type == VAL_I64)
2091 sp [-1].data.l |= sp [0].data.l;
2093 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2098 if (sp->type == VAL_I32)
2099 sp [-1].data.i ^= GET_NATI (sp [0]);
2100 else if (sp->type == VAL_I64)
2101 sp [-1].data.l ^= sp [0].data.l;
2103 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2108 if (sp [-1].type == VAL_I32)
2109 sp [-1].data.i <<= GET_NATI (sp [0]);
2110 else if (sp [-1].type == VAL_I64)
2111 sp [-1].data.l <<= GET_NATI (sp [0]);
2113 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2118 if (sp [-1].type == VAL_I32)
2119 sp [-1].data.i >>= GET_NATI (sp [0]);
2120 else if (sp [-1].type == VAL_I64)
2121 sp [-1].data.l >>= GET_NATI (sp [0]);
2123 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2128 if (sp [-1].type == VAL_I32)
2129 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2130 else if (sp [-1].type == VAL_I64)
2131 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2133 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2138 if (sp->type == VAL_I32)
2139 sp->data.i = - sp->data.i;
2140 else if (sp->type == VAL_I64)
2141 sp->data.l = - sp->data.l;
2142 else if (sp->type == VAL_DOUBLE)
2143 sp->data.f = - sp->data.f;
2144 else if (sp->type == VAL_NATI)
2145 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2151 if (sp->type == VAL_I32)
2152 sp->data.i = ~ sp->data.i;
2153 else if (sp->type == VAL_I64)
2154 sp->data.l = ~ sp->data.l;
2155 else if (sp->type == VAL_NATI)
2156 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2159 CASE (CEE_CONV_U1) /* fall through */
2160 CASE (CEE_CONV_I1) {
2162 switch (sp [-1].type) {
2164 sp [-1].data.i = (gint8)sp [-1].data.f;
2167 sp [-1].data.i = (gint8)sp [-1].data.l;
2172 sp [-1].data.i = (gint8)sp [-1].data.i;
2175 sp [-1].data.i = (gint8)sp [-1].data.nati;
2178 sp [-1].type = VAL_I32;
2181 CASE (CEE_CONV_U2) /* fall through */
2182 CASE (CEE_CONV_I2) {
2184 switch (sp [-1].type) {
2186 sp [-1].data.i = (gint16)sp [-1].data.f;
2189 sp [-1].data.i = (gint16)sp [-1].data.l;
2194 sp [-1].data.i = (gint16)sp [-1].data.i;
2197 sp [-1].data.i = (gint16)sp [-1].data.nati;
2200 sp [-1].type = VAL_I32;
2203 CASE (CEE_CONV_U4) /* Fall through */
2204 #if SIZEOF_VOID_P == 4
2205 CASE (CEE_CONV_I) /* Fall through */
2206 CASE (CEE_CONV_U) /* Fall through */
2208 CASE (CEE_CONV_I4) {
2210 switch (sp [-1].type) {
2212 sp [-1].data.i = (gint32)sp [-1].data.f;
2215 sp [-1].data.i = (gint32)sp [-1].data.l;
2222 sp [-1].data.i = (gint32)sp [-1].data.p;
2225 sp [-1].type = VAL_I32;
2228 #if SIZEOF_VOID_P == 8
2229 CASE (CEE_CONV_I) /* Fall through */
2233 switch (sp [-1].type) {
2235 sp [-1].data.l = (gint64)sp [-1].data.f;
2242 sp [-1].data.l = (gint64)sp [-1].data.i;
2245 sp [-1].data.l = (gint64)sp [-1].data.nati;
2248 sp [-1].type = VAL_I64;
2250 CASE (CEE_CONV_R4) /* Fall through */
2251 CASE (CEE_CONV_R8) {
2253 switch (sp [-1].type) {
2255 sp [-1].data.f = (double)sp [-1].data.f;
2258 sp [-1].data.f = (double)sp [-1].data.l;
2263 sp [-1].data.f = (double)sp [-1].data.i;
2266 sp [-1].data.f = (double)sp [-1].data.nati;
2269 sp [-1].type = VAL_DOUBLE;
2272 #if SIZEOF_VOID_P == 8
2273 CASE (CEE_CONV_U) /* Fall through */
2278 switch (sp [-1].type){
2280 sp [-1].data.l = (guint64)sp [-1].data.f;
2287 sp [-1].data.l = (guint64) sp [-1].data.i;
2290 sp [-1].data.l = (guint64) sp [-1].data.nati;
2293 sp [-1].type = VAL_I64;
2298 vtklass = mono_class_get (image, read32 (ip));
2301 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2310 token = read32 (ip);
2312 c = mono_class_get (image, token);
2313 addr = sp [-1].data.vt.vt;
2314 vt_alloc (&c->byval_arg, &sp [-1]);
2315 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2323 str_index = mono_metadata_token_index (read32 (ip));
2326 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2329 sp->data.vt.klass = NULL;
2336 MonoClass *newobj_class;
2337 MonoMethodSignature *csig;
2338 stackval valuetype_this;
2339 stackval *endsp = sp;
2346 token = read32 (ip);
2349 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2350 THROW_EX (mono_get_exception_missing_method (), ip -5);
2352 csig = child_frame.method->signature;
2353 newobj_class = child_frame.method->klass;
2354 /*if (profiling_classes) {
2355 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2357 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2361 if (newobj_class->parent == mono_defaults.array_class) {
2362 sp -= csig->param_count;
2363 o = ves_array_create (domain, newobj_class, csig, sp);
2364 goto array_constructed;
2368 * First arg is the object.
2370 if (newobj_class->valuetype) {
2372 vt_alloc (&newobj_class->byval_arg, &valuetype_this);
2373 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2374 zero = valuetype_this.data.vt.vt;
2375 child_frame.obj = valuetype_this.data.vt.vt;
2377 memset (&valuetype_this, 0, sizeof (stackval));
2378 zero = &valuetype_this;
2379 child_frame.obj = &valuetype_this;
2381 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero);
2383 if (newobj_class != mono_defaults.string_class) {
2384 o = mono_object_new (domain, newobj_class);
2385 child_frame.obj = o;
2387 child_frame.retval = &retval;
2391 if (csig->param_count) {
2392 sp -= csig->param_count;
2393 child_frame.stack_args = sp;
2395 child_frame.stack_args = NULL;
2398 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2400 child_frame.ex = NULL;
2401 child_frame.ex_handler = NULL;
2403 ves_exec_method (&child_frame);
2405 while (endsp > sp) {
2410 if (child_frame.ex) {
2412 * An exception occurred, need to run finally, fault and catch handlers..
2414 frame->ex = child_frame.ex;
2415 goto handle_finally;
2418 * a constructor returns void, but we need to return the object we created
2421 if (newobj_class->valuetype && !newobj_class->enumtype) {
2422 *sp = valuetype_this;
2423 } else if (newobj_class == mono_defaults.string_class) {
2428 sp->data.vt.klass = newobj_class;
2433 CASE (CEE_CASTCLASS) /* Fall through */
2437 MonoClass *c , *oclass;
2439 int do_isinst = *ip == CEE_ISINST;
2440 gboolean found = FALSE;
2443 token = read32 (ip);
2444 c = mono_class_get (image, token);
2446 g_assert (sp [-1].type == VAL_OBJ);
2448 if ((o = sp [-1].data.p)) {
2453 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2454 if ((c->interface_id <= oclass->max_interface_id) &&
2455 vt->interface_offsets [c->interface_id])
2458 if (oclass == mono_defaults.transparent_proxy_class) {
2459 /* fixme: add check for IRemotingTypeInfo */
2460 MonoRealProxy *rp = ((MonoTransparentProxy *)o)->rp;
2462 type = rp->class_to_proxy->type;
2463 oclass = mono_class_from_mono_type (type);
2465 /* handle array casts */
2466 if (oclass->rank && oclass->rank == c->rank) {
2467 if ((oclass->element_class->baseval - c->element_class->baseval) <= c->element_class->diffval) {
2468 sp [-1].data.vt.klass = c;
2471 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2472 sp [-1].data.vt.klass = c;
2479 sp [-1].data.p = NULL;
2480 sp [-1].data.vt.klass = NULL;
2482 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2488 CASE (CEE_CONV_R_UN)
2489 switch (sp [-1].type) {
2493 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2498 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2501 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2504 sp [-1].type = VAL_DOUBLE;
2507 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2514 token = read32 (ip);
2516 c = mono_class_get (image, token);
2520 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2522 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2523 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2525 sp [-1].type = VAL_MP;
2526 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2533 frame->ex_handler = NULL;
2534 THROW_EX (sp->data.p, ip);
2536 CASE (CEE_LDFLDA) /* Fall through */
2539 MonoClassField *field;
2540 guint32 token, offset;
2541 int load_addr = *ip == CEE_LDFLDA;
2543 if (!sp [-1].data.p)
2544 THROW_EX (mono_get_exception_null_reference (), ip);
2547 token = read32 (ip);
2550 if (sp [-1].type == VAL_OBJ) {
2551 obj = sp [-1].data.p;
2552 /* if we access a field from our parent and the parent was
2553 * defined in another assembly, we get a memberref.
2555 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2556 field = mono_field_from_memberref (image, token, NULL);
2558 field = mono_class_get_field (obj->vtable->klass, token);
2559 offset = field->offset;
2560 } else { /* valuetype */
2561 /*g_assert (sp [-1].type == VAL_VALUETA); */
2562 obj = sp [-1].data.vt.vt;
2563 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2564 offset = field->offset - sizeof (MonoObject);
2567 sp [-1].type = VAL_TP;
2568 sp [-1].data.p = (char*)obj + offset;
2569 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2571 vt_alloc (field->type, &sp [-1]);
2572 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2579 MonoClassField *field;
2580 guint32 token, offset;
2585 THROW_EX (mono_get_exception_null_reference (), ip);
2588 token = read32 (ip);
2591 if (sp [0].type == VAL_OBJ) {
2592 obj = sp [0].data.p;
2593 /* if we access a field from our parent and the parent was
2594 * defined in another assembly, we get a memberref.
2596 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2597 field = mono_field_from_memberref (image, token, NULL);
2599 field = mono_class_get_field (obj->vtable->klass, token);
2600 offset = field->offset;
2601 } else { /* valuetype */
2602 /*g_assert (sp->type == VAL_VALUETA); */
2603 obj = sp [0].data.vt.vt;
2604 field = mono_class_get_field (sp [0].data.vt.klass, token);
2605 offset = field->offset - sizeof (MonoObject);
2608 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2612 CASE (CEE_LDSFLD) /* Fall through */
2613 CASE (CEE_LDSFLDA) {
2616 MonoClassField *field;
2618 int load_addr = *ip == CEE_LDSFLDA;
2622 token = read32 (ip);
2625 /* need to handle fieldrefs */
2626 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2627 field = mono_field_from_memberref (image, token, &klass);
2629 klass = mono_class_get (image,
2630 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2631 field = mono_class_get_field (klass, token);
2635 vt = mono_class_vtable (domain, klass);
2636 addr = (char*)(vt->data) + field->offset;
2641 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2643 vt_alloc (field->type, sp);
2644 stackval_from_data (field->type, sp, addr);
2652 MonoClassField *field;
2657 token = read32 (ip);
2661 /* need to handle fieldrefs */
2662 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2663 field = mono_field_from_memberref (image, token, &klass);
2665 klass = mono_class_get (image,
2666 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2667 field = mono_class_get_field (klass, token);
2671 vt = mono_class_vtable (domain, klass);
2672 addr = (char*)(vt->data) + field->offset;
2674 stackval_to_data (field->type, sp, addr);
2681 vtklass = mono_class_get (image, read32 (ip));
2684 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2687 #if SIZEOF_VOID_P == 8
2688 CASE (CEE_CONV_OVF_I_UN)
2690 CASE (CEE_CONV_OVF_I8_UN) {
2691 switch (sp [-1].type) {
2693 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2694 THROW_EX (mono_get_exception_overflow (), ip);
2695 sp [-1].data.l = (guint64)sp [-1].data.f;
2698 if (sp [-1].data.l < 0)
2699 THROW_EX (mono_get_exception_overflow (), ip);
2704 /* Can't overflow */
2705 sp [-1].data.l = (guint64)sp [-1].data.i;
2708 if ((gint64)sp [-1].data.nati < 0)
2709 THROW_EX (mono_get_exception_overflow (), ip);
2710 sp [-1].data.l = (guint64)sp [-1].data.nati;
2713 sp [-1].type = VAL_I64;
2717 #if SIZEOF_VOID_P == 8
2718 CASE (CEE_CONV_OVF_U_UN)
2720 CASE (CEE_CONV_OVF_U8_UN) {
2721 switch (sp [-1].type) {
2723 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
2724 THROW_EX (mono_get_exception_overflow (), ip);
2725 sp [-1].data.l = (guint64)sp [-1].data.f;
2733 /* Can't overflow */
2734 sp [-1].data.l = (guint64)sp [-1].data.i;
2737 /* Can't overflow */
2738 sp [-1].data.l = (guint64)sp [-1].data.nati;
2741 sp [-1].type = VAL_I64;
2745 #if SIZEOF_VOID_P == 4
2746 CASE (CEE_CONV_OVF_I_UN)
2747 CASE (CEE_CONV_OVF_U_UN)
2749 CASE (CEE_CONV_OVF_I1_UN)
2750 CASE (CEE_CONV_OVF_I2_UN)
2751 CASE (CEE_CONV_OVF_I4_UN)
2752 CASE (CEE_CONV_OVF_U1_UN)
2753 CASE (CEE_CONV_OVF_U2_UN)
2754 CASE (CEE_CONV_OVF_U4_UN) {
2756 switch (sp [-1].type) {
2758 value = (guint64)sp [-1].data.f;
2761 value = (guint64)sp [-1].data.l;
2766 value = (guint64)sp [-1].data.i;
2769 value = (guint64)sp [-1].data.nati;
2773 case CEE_CONV_OVF_I1_UN:
2775 THROW_EX (mono_get_exception_overflow (), ip);
2776 sp [-1].data.i = value;
2777 sp [-1].type = VAL_I32;
2779 case CEE_CONV_OVF_I2_UN:
2781 THROW_EX (mono_get_exception_overflow (), ip);
2782 sp [-1].data.i = value;
2783 sp [-1].type = VAL_I32;
2785 #if SIZEOF_VOID_P == 4
2786 case CEE_CONV_OVF_I_UN: /* Fall through */
2788 case CEE_CONV_OVF_I4_UN:
2789 if (value > 2147483647)
2790 THROW_EX (mono_get_exception_overflow (), ip);
2791 sp [-1].data.i = value;
2792 sp [-1].type = VAL_I32;
2794 case CEE_CONV_OVF_U1_UN:
2796 THROW_EX (mono_get_exception_overflow (), ip);
2797 sp [-1].data.i = value;
2798 sp [-1].type = VAL_I32;
2800 case CEE_CONV_OVF_U2_UN:
2802 THROW_EX (mono_get_exception_overflow (), ip);
2803 sp [-1].data.i = value;
2804 sp [-1].type = VAL_I32;
2806 #if SIZEOF_VOID_P == 4
2807 case CEE_CONV_OVF_U_UN: /* Fall through */
2809 case CEE_CONV_OVF_U4_UN:
2810 if (value > 4294967295U)
2811 THROW_EX (mono_get_exception_overflow (), ip);
2812 sp [-1].data.i = value;
2813 sp [-1].type = VAL_I32;
2816 g_assert_not_reached ();
2826 token = read32 (ip);
2828 class = mono_class_get (image, token);
2829 g_assert (class != NULL);
2831 sp [-1].type = VAL_OBJ;
2832 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
2833 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
2835 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
2836 /* need to vt_free (sp); */
2848 token = read32 (ip);
2849 class = mono_class_get (image, token);
2850 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
2853 sp [-1].type = VAL_OBJ;
2855 /*if (profiling_classes) {
2856 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
2858 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
2868 g_assert (sp [-1].type == VAL_OBJ);
2872 THROW_EX (mono_get_exception_null_reference (), ip - 1);
2874 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2876 sp [-1].type = VAL_I32;
2877 sp [-1].data.i = mono_array_length (o);
2881 CASE (CEE_LDELEMA) {
2883 guint32 esize, token;
2886 token = read32 (ip);
2890 g_assert (sp [0].type == VAL_OBJ);
2893 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2895 if (sp [1].data.nati >= mono_array_length (o))
2896 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
2898 /* check the array element corresponds to token */
2899 esize = mono_array_element_size (o->obj.vtable->klass);
2902 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
2903 sp->data.vt.klass = o->obj.vtable->klass->element_class;
2908 CASE (CEE_LDELEM_I1) /* fall through */
2909 CASE (CEE_LDELEM_U1) /* fall through */
2910 CASE (CEE_LDELEM_I2) /* fall through */
2911 CASE (CEE_LDELEM_U2) /* fall through */
2912 CASE (CEE_LDELEM_I4) /* fall through */
2913 CASE (CEE_LDELEM_U4) /* fall through */
2914 CASE (CEE_LDELEM_I8) /* fall through */
2915 CASE (CEE_LDELEM_I) /* fall through */
2916 CASE (CEE_LDELEM_R4) /* fall through */
2917 CASE (CEE_LDELEM_R8) /* fall through */
2918 CASE (CEE_LDELEM_REF) {
2924 g_assert (sp [0].type == VAL_OBJ);
2927 THROW_EX (mono_get_exception_null_reference (), ip);
2929 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2931 aindex = sp [1].data.nati;
2932 if (aindex >= mono_array_length (o))
2933 THROW_EX (mono_get_exception_index_out_of_range (), ip);
2936 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
2940 sp [0].data.i = mono_array_get (o, gint8, aindex);
2941 sp [0].type = VAL_I32;
2944 sp [0].data.i = mono_array_get (o, guint8, aindex);
2945 sp [0].type = VAL_I32;
2948 sp [0].data.i = mono_array_get (o, gint16, aindex);
2949 sp [0].type = VAL_I32;
2952 sp [0].data.i = mono_array_get (o, guint16, aindex);
2953 sp [0].type = VAL_I32;
2956 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
2957 sp [0].type = VAL_NATI;
2960 sp [0].data.i = mono_array_get (o, gint32, aindex);
2961 sp [0].type = VAL_I32;
2964 sp [0].data.i = mono_array_get (o, guint32, aindex);
2965 sp [0].type = VAL_I32;
2968 sp [0].data.l = mono_array_get (o, gint64, aindex);
2969 sp [0].type = VAL_I64;
2972 sp [0].data.f = mono_array_get (o, float, aindex);
2973 sp [0].type = VAL_DOUBLE;
2976 sp [0].data.f = mono_array_get (o, double, aindex);
2977 sp [0].type = VAL_DOUBLE;
2979 case CEE_LDELEM_REF:
2980 sp [0].data.p = mono_array_get (o, gpointer, aindex);
2981 sp [0].data.vt.klass = NULL;
2982 sp [0].type = VAL_OBJ;
2992 CASE (CEE_STELEM_I) /* fall through */
2993 CASE (CEE_STELEM_I1) /* fall through */
2994 CASE (CEE_STELEM_I2) /* fall through */
2995 CASE (CEE_STELEM_I4) /* fall through */
2996 CASE (CEE_STELEM_I8) /* fall through */
2997 CASE (CEE_STELEM_R4) /* fall through */
2998 CASE (CEE_STELEM_R8) /* fall through */
2999 CASE (CEE_STELEM_REF) {
3006 g_assert (sp [0].type == VAL_OBJ);
3009 THROW_EX (mono_get_exception_null_reference (), ip);
3011 ac = o->obj.vtable->klass;
3012 g_assert (MONO_CLASS_IS_ARRAY (ac));
3014 aindex = sp [1].data.nati;
3015 if (aindex >= mono_array_length (o))
3016 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3019 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3023 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3026 mono_array_set (o, gint8, aindex, sp [2].data.i);
3029 mono_array_set (o, gint16, aindex, sp [2].data.i);
3032 mono_array_set (o, gint32, aindex, sp [2].data.i);
3035 mono_array_set (o, gint64, aindex, sp [2].data.l);
3038 mono_array_set (o, float, aindex, sp [2].data.f);
3041 mono_array_set (o, double, aindex, sp [2].data.f);
3043 case CEE_STELEM_REF:
3044 g_assert (sp [2].type == VAL_OBJ);
3045 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3069 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3070 CASE (CEE_CONV_OVF_I1)
3071 if (sp [-1].type == VAL_I32) {
3072 if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
3073 THROW_EX (mono_get_exception_overflow (), ip);
3074 sp [-1].data.i = (gint8)sp [-1].data.i;
3075 } else if (sp [-1].type == VAL_I64) {
3076 if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
3077 THROW_EX (mono_get_exception_overflow (), ip);
3078 sp [-1].data.i = (gint8)sp [-1].data.l;
3084 CASE (CEE_CONV_OVF_U1)
3085 if (sp [-1].type == VAL_I32) {
3086 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3087 THROW_EX (mono_get_exception_overflow (), ip);
3088 sp [-1].data.i = (gint8)sp [-1].data.i;
3089 } else if (sp [-1].type == VAL_I64) {
3090 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3091 THROW_EX (mono_get_exception_overflow (), ip);
3092 sp [-1].data.i = (gint8)sp [-1].data.l;
3098 CASE (CEE_CONV_OVF_I2)
3099 CASE (CEE_CONV_OVF_U2)
3101 /* FIXME: handle other cases */
3102 if (sp [-1].type == VAL_I32) {
3103 /* defined as NOP */
3108 CASE (CEE_CONV_OVF_I4)
3109 /* FIXME: handle other cases */
3110 if (sp [-1].type == VAL_I32) {
3111 /* defined as NOP */
3112 } else if(sp [-1].type == VAL_I64) {
3113 sp [-1].data.i = (gint32)sp [-1].data.l;
3119 CASE (CEE_CONV_OVF_U4)
3120 /* FIXME: handle other cases */
3121 if (sp [-1].type == VAL_I32) {
3122 /* defined as NOP */
3123 } else if(sp [-1].type == VAL_I64) {
3124 sp [-1].data.i = (guint32)sp [-1].data.l;
3130 CASE (CEE_CONV_OVF_I8)
3131 /* FIXME: handle other cases */
3132 if (sp [-1].type == VAL_I32) {
3133 sp [-1].data.l = (guint64)sp [-1].data.l;
3134 } else if(sp [-1].type == VAL_I64) {
3135 /* defined as NOP */
3141 CASE (CEE_CONV_OVF_U8)
3142 /* FIXME: handle other cases */
3143 if (sp [-1].type == VAL_I32) {
3144 sp [-1].data.l = (guint64)sp [-1].data.l;
3145 } else if(sp [-1].type == VAL_I64) {
3146 /* defined as NOP */
3158 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3159 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3161 if (!finite(sp [-1].data.f))
3162 THROW_EX (mono_get_exception_arithmetic (), ip);
3165 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3166 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3167 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3176 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3177 CASE (CEE_LDTOKEN) {
3179 MonoClass *handle_class;
3181 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3183 vt_alloc (&handle_class->byval_arg, sp);
3184 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
3188 CASE (CEE_CONV_OVF_I)
3191 /* FIXME: check overflow. */
3194 sp->data.p = (gpointer)(mono_i) sp->data.i;
3197 sp->data.p = (gpointer)(mono_i) sp->data.l;
3202 sp->data.p = (gpointer)(mono_i) sp->data.f;
3207 sp->type = VAL_NATI;
3210 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
3213 /* FIXME: check overflow */
3214 if (sp->type == VAL_I32) {
3215 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3216 THROW_EX (mono_get_exception_overflow (), ip);
3217 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3218 } else if (sp->type == VAL_I64) {
3219 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3220 THROW_EX (mono_get_exception_overflow (), ip);
3221 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3222 } else if (sp->type == VAL_DOUBLE)
3223 sp [-1].data.f += sp [0].data.f;
3225 char *p = sp [-1].data.p;
3226 p += GET_NATI (sp [0]);
3231 CASE (CEE_ADD_OVF_UN)
3233 /* FIXME: check overflow, make unsigned */
3234 if (sp->type == VAL_I32) {
3235 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3236 THROW_EX (mono_get_exception_overflow (), ip);
3237 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3238 } else if (sp->type == VAL_I64) {
3239 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3240 THROW_EX (mono_get_exception_overflow (), ip);
3241 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3242 } else if (sp->type == VAL_DOUBLE)
3243 sp [-1].data.f += sp [0].data.f;
3245 char *p = sp [-1].data.p;
3246 p += GET_NATI (sp [0]);
3254 /* FIXME: check overflow */
3255 if (sp->type == VAL_I32)
3256 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3257 else if (sp->type == VAL_I64)
3258 sp [-1].data.l *= sp [0].data.l;
3259 else if (sp->type == VAL_DOUBLE)
3260 sp [-1].data.f *= sp [0].data.f;
3262 CASE (CEE_MUL_OVF_UN)
3265 /* FIXME: check overflow, make unsigned */
3266 if (sp->type == VAL_I32)
3267 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3268 else if (sp->type == VAL_I64)
3269 sp [-1].data.l *= sp [0].data.l;
3270 else if (sp->type == VAL_DOUBLE)
3271 sp [-1].data.f *= sp [0].data.f;
3274 CASE (CEE_SUB_OVF_UN)
3277 /* FIXME: handle undeflow/unsigned */
3278 /* should probably consider the pointers as unsigned */
3279 if (sp->type == VAL_I32)
3280 sp [-1].data.i -= GET_NATI (sp [0]);
3281 else if (sp->type == VAL_I64)
3282 sp [-1].data.l -= sp [0].data.l;
3283 else if (sp->type == VAL_DOUBLE)
3284 sp [-1].data.f -= sp [0].data.f;
3286 char *p = sp [-1].data.p;
3287 p -= GET_NATI (sp [0]);
3291 CASE (CEE_ENDFINALLY)
3295 * There was no exception, we continue normally at the target address.
3299 CASE (CEE_LEAVE) /* Fall through */
3301 sp = frame->stack; /* empty the stack */
3303 if (*ip == CEE_LEAVE_S) {
3305 ip += (signed char) *ip;
3309 ip += (gint32) read32 (ip);
3314 * We may be either inside a try block or inside an handler.
3315 * In the first case there was no exception and we go on
3316 * executing the finally handlers and after that resume control
3318 * In the second case we need to clear the exception and
3319 * continue directly at the target ip.
3323 goto handle_finally;
3326 frame->ex_handler = NULL;
3330 frame->ex_handler = NULL;
3332 goto handle_finally;
3363 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3365 * Note: Exceptions thrown when executing a prefixed opcode need
3366 * to take into account the number of prefix bytes (usually the
3367 * throw point is just (ip - n_prefix_bytes).
3372 case CEE_ARGLIST: ves_abort(); break;
3378 if (sp->type == VAL_I32)
3379 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3380 else if (sp->type == VAL_I64)
3381 result = sp [0].data.l == sp [1].data.l;
3382 else if (sp->type == VAL_DOUBLE) {
3383 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3386 result = sp [0].data.f == sp [1].data.f;
3388 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3390 sp->data.i = result;
3400 if (sp->type == VAL_I32)
3401 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3402 else if (sp->type == VAL_I64)
3403 result = sp [0].data.l > sp [1].data.l;
3404 else if (sp->type == VAL_DOUBLE) {
3405 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3408 result = sp [0].data.f > sp [1].data.f;
3410 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3412 sp->data.i = result;
3422 if (sp->type == VAL_I32)
3423 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3424 else if (sp->type == VAL_I64)
3425 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3426 else if (sp->type == VAL_DOUBLE)
3427 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3429 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3431 sp->data.i = result;
3441 if (sp->type == VAL_I32)
3442 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3443 else if (sp->type == VAL_I64)
3444 result = sp [0].data.l < sp [1].data.l;
3445 else if (sp->type == VAL_DOUBLE) {
3446 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3449 result = sp [0].data.f < sp [1].data.f;
3451 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3453 sp->data.i = result;
3463 if (sp->type == VAL_I32)
3464 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3465 else if (sp->type == VAL_I64)
3466 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3467 else if (sp->type == VAL_DOUBLE)
3468 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3470 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3472 sp->data.i = result;
3478 case CEE_LDVIRTFTN: {
3479 int virtual = *ip == CEE_LDVIRTFTN;
3483 token = read32 (ip);
3485 m = mono_get_method (image, token, NULL);
3487 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3491 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3492 m = get_virtual_method (domain, m, sp);
3494 sp->type = VAL_NATI;
3495 sp->data.p = mono_create_method_pointer (m);
3496 sp->data.vt.klass = NULL;
3500 case CEE_UNUSED56: ves_abort(); break;
3504 arg_pos = read16 (ip);
3506 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
3507 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3519 t = ARG_TYPE (signature, anum);
3520 c = mono_class_from_mono_type (t);
3521 sp->data.vt.klass = c;
3522 sp->data.vt.vt = ARG_POS (anum);
3525 sp->type = VAL_VALUETA;
3536 arg_pos = read16 (ip);
3539 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3546 loc_pos = read16 (ip);
3548 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3549 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3559 loc_pos = read16 (ip);
3561 t = LOCAL_TYPE (header, loc_pos);
3562 c = mono_class_from_mono_type (t);
3563 sp->data.vt.vt = LOCAL_POS (loc_pos);
3564 sp->data.vt.klass = c;
3567 sp->type = VAL_VALUETA;
3577 loc_pos = read16 (ip);
3580 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3585 if (sp != frame->stack)
3586 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
3588 sp->data.p = alloca (sp->data.i);
3591 case CEE_UNUSED57: ves_abort(); break;
3592 case CEE_ENDFILTER: ves_abort(); break;
3593 case CEE_UNALIGNED_:
3595 unaligned_address = 1;
3599 volatile_address = 1;
3608 token = read32 (ip);
3611 * we ignore the value of token (I think we can as unspecified
3612 * behavior described in Partition II, 3.5).
3615 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
3616 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3619 case CEE_UNUSED68: ves_abort(); break;
3622 if (!sp [0].data.p || !sp [1].data.p)
3623 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3625 /* FIXME: value and size may be int64... */
3626 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3631 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3633 /* FIXME: value and size may be int64... */
3634 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3636 case CEE_UNUSED69: ves_abort(); break;
3639 * need to clarify what this should actually do:
3640 * start the search from the last found handler in
3641 * this method or continue in the caller or what.
3642 * Also, do we need to run finally/fault handlers after a retrow?
3643 * Well, this implementation will follow the usual search
3644 * for an handler, considering the current ip as throw spot.
3645 * We need to NULL frame->ex_handler for the later code to
3646 * actually run the new found handler.
3648 frame->ex_handler = NULL;
3649 THROW_EX (frame->ex, ip - 1);
3651 case CEE_UNUSED: ves_abort(); break;
3657 token = read32 (ip);
3659 type = mono_type_create_from_typespec (image, token);
3661 sp->data.i = mono_type_size (type, &align);
3662 mono_metadata_free_type (type);
3666 case CEE_REFANYTYPE: ves_abort(); break;
3673 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3680 g_assert_not_reached ();
3682 * Exception handling code.
3683 * The exception object is stored in frame->ex.
3690 MonoInvocation *inv;
3691 MonoMethodHeader *hd;
3692 MonoExceptionClause *clause;
3696 if (die_on_exception)
3699 for (inv = frame; inv; inv = inv->parent) {
3700 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
3702 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
3704 hd = ((MonoMethodNormal*)inv->method)->header;
3705 ip_offset = inv->ip - hd->code;
3706 for (i = 0; i < hd->num_clauses; ++i) {
3707 clause = &hd->clauses [i];
3708 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3709 if (!clause->flags) {
3710 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3712 * OK, we found an handler, now we need to execute the finally
3713 * and fault blocks before branching to the handler code.
3715 inv->ex_handler = clause;
3717 * It seems that if the catch handler is found in the same method,
3718 * it gets executed before the finally handler.
3723 goto handle_finally;
3726 /* FIXME: handle filter clauses */
3733 * If we get here, no handler was found: print a stack trace.
3736 ex_obj = (MonoObject*)frame->ex;
3737 message = frame->ex->message? mono_string_to_utf8 (frame->ex->message): NULL;
3738 g_print ("Unhandled exception %s.%s %s.\n", ex_obj->vtable->klass->name_space, ex_obj->vtable->klass->name,
3739 message?message:"");
3741 message = dump_frame (frame);
3742 g_print ("%s", message);
3750 MonoExceptionClause *clause;
3752 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3756 ip_offset = frame->ip - header->code;
3758 for (i = 0; i < header->num_clauses; ++i) {
3759 clause = &header->clauses [i];
3760 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3761 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3762 ip = header->code + clause->handler_offset;
3770 * If an exception is set, we need to execute the fault handler, too,
3771 * otherwise, we continue normally.
3782 MonoExceptionClause *clause;
3784 ip_offset = frame->ip - header->code;
3785 for (i = 0; i < header->num_clauses; ++i) {
3786 clause = &header->clauses [i];
3787 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3788 ip = header->code + clause->handler_offset;
3793 * If the handler for the exception was found in this method, we jump
3794 * to it right away, otherwise we return and let the caller run
3795 * the finally, fault and catch blocks.
3796 * This same code should be present in the endfault opcode, but it
3797 * is corrently not assigned in the ECMA specs: LAMESPEC.
3799 if (frame->ex_handler) {
3800 ip = header->code + frame->ex_handler->handler_offset;
3803 sp->data.p = frame->ex;
3814 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3816 MonoArray *args = NULL;
3817 MonoImage *image = assembly->image;
3818 MonoCLIImageInfo *iinfo;
3822 iinfo = image->image_info;
3823 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3825 g_error ("No entry point method found in %s", image->name);
3827 if (method->signature->param_count) {
3828 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3829 for (i = 0; i < argc; ++i) {
3830 MonoString *arg = mono_string_new (domain, argv [i]);
3831 mono_array_set (args, gpointer, i, arg);
3835 return mono_runtime_exec_main (method, args);
3842 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3843 "Usage is: mint [options] executable args...\n", VERSION);
3845 "Valid Options are:\n"
3852 "--traceclassinit\n"
3855 "--debug method_name\n"
3857 "--opcode-count\n");
3863 test_load_class (MonoImage* image)
3865 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3869 for (i = 1; i <= t->rows; ++i) {
3870 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3871 mono_class_init (klass);
3876 static MonoException * segv_exception = NULL;
3879 segv_handler (int signum)
3881 signal (signum, segv_handler);
3882 mono_raise_exception (segv_exception);
3886 main (int argc, char *argv [])
3889 MonoAssembly *assembly;
3890 int retval = 0, i, ocount = 0;
3896 for (i = 1; i < argc && argv [i][0] == '-'; i++){
3897 if (strcmp (argv [i], "--trace") == 0)
3899 if (strcmp (argv [i], "--traceops") == 0)
3901 if (strcmp (argv [i], "--dieonex") == 0)
3902 die_on_exception = 1;
3903 if (strcmp (argv [i], "--print-vtable") == 0)
3904 mono_print_vtable = TRUE;
3905 if (strcmp (argv [i], "--profile") == 0)
3906 mono_profiler_install_simple ();
3907 if (strcmp (argv [i], "--opcode-count") == 0)
3909 if (strcmp (argv [i], "--help") == 0)
3912 if (strcmp (argv [i], "--debug") == 0) {
3913 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
3915 g_error ("Invalid method name '%s'", argv [i]);
3916 db_methods = g_list_append (db_methods, desc);
3926 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
3927 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
3930 mono_add_internal_call ("System.Array::Set", ves_array_set);
3931 mono_add_internal_call ("System.Array::Get", ves_array_get);
3932 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
3934 frame_thread_id = TlsAlloc ();
3935 TlsSetValue (frame_thread_id, NULL);
3937 mono_install_runtime_invoke (interp_mono_runtime_invoke);
3938 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
3940 mono_install_handler (interp_ex_handler);
3942 InitializeCriticalSection (&metadata_lock);
3943 domain = mono_init (file);
3944 mono_runtime_init (domain);
3945 mono_thread_init (domain);
3946 mono_network_init ();
3948 assembly = mono_domain_assembly_open (domain, file);
3951 fprintf (stderr, "Can not open image %s\n", file);
3957 test_load_class (assembly->image);
3959 error = mono_verify_corlib ();
3961 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
3964 segv_exception = mono_get_exception_null_reference ();
3965 segv_exception->message = mono_string_new (domain, "Segmentation fault");
3966 signal (SIGSEGV, segv_handler);
3968 * skip the program name from the args.
3971 retval = ves_exec (domain, assembly, argc - i, argv + i);
3973 mono_profiler_shutdown ();
3975 mono_network_cleanup ();
3976 mono_thread_cleanup ();
3978 mono_domain_unload (domain, TRUE);
3982 fprintf (stderr, "opcode count: %ld\n", opcode_count);
3983 fprintf (stderr, "fcall count: %ld\n", fcall_count);