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.
26 #include <mono/os/gc_wrapper.h>
32 # define alloca __builtin_alloca
36 /* trim excessive headers */
37 #include <mono/metadata/image.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/cil-coff.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/blob.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.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/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/os/util.h>
62 /*#include <mono/cli/types.h>*/
67 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
70 #define finite _finite
74 #define finite isfinite
78 /* If true, then we output the opcodes as we interpret them */
79 static int global_tracing = 0;
80 static int global_no_pointers = 0;
82 static int debug_indent_level = 0;
85 * Pull the list of opcodes
87 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
91 #include "mono/cil/opcode.def"
96 #if SIZEOF_VOID_P == 8
97 #define GET_NATI(sp) ((sp).type == VAL_I32 ? (sp).data.i : (sp).data.nati)
99 #define GET_NATI(sp) (sp).data.i
101 #define CSIZE(x) (sizeof (x) / 4)
103 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
105 (frame)->parent = (parent_frame); \
106 (frame)->obj = (obj_this); \
107 (frame)->stack_args = (method_args); \
108 (frame)->retval = (method_retval); \
109 (frame)->method = (mono_method); \
110 (frame)->ex_handler = NULL; \
111 (frame)->ex = NULL; \
112 (frame)->child = NULL; \
113 (frame)->ip = NULL; \
114 (frame)->invoke_trap = 0; \
118 MonoInvocation *base_frame;
119 MonoInvocation *current_frame;
120 MonoInvocation *env_frame;
121 jmp_buf *current_env;
122 int search_for_handler;
125 static MonoException * quit_exception = NULL;
127 void ves_exec_method (MonoInvocation *frame);
129 static char* dump_stack (stackval *stack, stackval *sp);
130 static char* dump_frame (MonoInvocation *inv);
131 static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
133 typedef void (*ICallMethod) (MonoInvocation *frame);
135 static guint32 die_on_exception = 0;
136 static guint32 thread_context_id = 0;
138 #define DEBUG_INTERP 1
141 static unsigned long opcode_count = 0;
142 static unsigned long fcall_count = 0;
143 static int break_on_method = 0;
144 static GList *db_methods = NULL;
151 for (h = 0; h < debug_indent_level; h++)
156 db_match_method (gpointer data, gpointer user_data)
158 MonoMethod *m = (MonoMethod*)user_data;
159 MonoMethodDesc *desc = data;
161 if (mono_method_desc_full_match (desc, m))
165 #define DEBUG_ENTER() \
167 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
168 if (break_on_method) tracing=2; \
169 break_on_method = 0; \
171 char *mn, *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
172 debug_indent_level++; \
174 mn = mono_method_full_name (frame->method, FALSE); \
175 g_print ("(%u) Entering %s (", GetCurrentThreadId(), mn); \
177 if (signature->hasthis) { \
178 if (global_no_pointers) { \
179 g_print ("this%s ", frame->obj ? "" : "=null"); \
181 g_print ("%p ", frame->obj); } \
183 g_print ("%s)\n", args); \
186 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
187 mono_profiler_method_enter (frame->method);
189 #define DEBUG_LEAVE() \
192 if (signature->ret->type != MONO_TYPE_VOID) \
193 args = dump_stack (frame->retval, frame->retval + 1); \
195 args = g_strdup (""); \
197 mn = mono_method_full_name (frame->method, FALSE); \
198 g_print ("(%u) Leaving %s", GetCurrentThreadId(), mn); \
200 g_print (" => %s\n", args); \
202 debug_indent_level--; \
204 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
205 mono_profiler_method_leave (frame->method);
209 #define DEBUG_ENTER()
210 #define DEBUG_LEAVE()
215 interp_ex_handler (MonoException *ex) {
216 ThreadContext *context = TlsGetValue (thread_context_id);
218 stack_trace = dump_frame (context->current_frame);
219 ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
220 g_free (stack_trace);
221 if (context == NULL || context->current_env == NULL) {
222 char *strace = mono_string_to_utf8 (ex->stack_trace);
223 fprintf(stderr, "Nothing can catch this exception: ");
224 fprintf(stderr, "%s", ex->object.vtable->klass->name);
225 if (ex->message != NULL) {
226 char *m = mono_string_to_utf8 (ex->message);
227 fprintf(stderr, ": %s", m);
230 fprintf(stderr, "\n");
231 fprintf(stderr, "%s\n", strace);
233 if (ex->inner_ex != NULL) {
234 ex = (MonoException *)ex->inner_ex;
235 fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name);
236 if (ex->message != NULL) {
237 char *m = mono_string_to_utf8 (ex->message);
238 fprintf(stderr, ": %s", m);
241 strace = mono_string_to_utf8 (ex->stack_trace);
242 fprintf(stderr, "\n");
243 fprintf(stderr, "%s\n", strace);
248 context->env_frame->ex = ex;
249 context->search_for_handler = 1;
250 longjmp (*context->current_env, 1);
254 ves_real_abort (int line, MonoMethod *mh,
255 const unsigned char *ip, stackval *stack, stackval *sp)
257 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
258 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
259 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
260 ip-mm->header->code);
261 g_print ("0x%04x %02x\n",
262 ip-mm->header->code, *ip);
264 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
266 #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);
269 interp_create_remoting_trampoline (MonoMethod *method)
271 return mono_marshal_get_remoting_invoke (method);
275 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
280 gboolean is_proxy = FALSE;
283 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
287 if ((klass = obj->vtable->klass) == mono_defaults.transparent_proxy_class) {
288 klass = ((MonoTransparentProxy *)obj)->klass;
291 vtable = (MonoMethod **)klass->vtable;
293 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
294 res = ((MonoMethod **)obj->vtable->interface_offsets [m->klass->interface_id]) [m->slot];
296 res = vtable [m->slot];
301 return mono_marshal_get_remoting_invoke (res);
307 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
310 switch (type->type) {
311 case MONO_TYPE_OBJECT:
312 case MONO_TYPE_CLASS:
313 case MONO_TYPE_STRING:
314 case MONO_TYPE_ARRAY:
315 case MONO_TYPE_SZARRAY:
316 result->type = VAL_OBJ;
319 result->type = VAL_MP;
322 result->data.p = *(gpointer*)data;
325 switch (type->type) {
329 result->type = VAL_I32;
330 result->data.i = *(gint8*)data;
333 case MONO_TYPE_BOOLEAN:
334 result->type = VAL_I32;
335 result->data.i = *(guint8*)data;
338 result->type = VAL_I32;
339 result->data.i = *(gint16*)data;
343 result->type = VAL_I32;
344 result->data.i = *(guint16*)data;
347 result->type = VAL_I32;
348 result->data.i = *(gint32*)data;
352 result->type = VAL_NATI;
353 result->data.nati = *(mono_i*)data;
356 result->type = VAL_TP;
357 result->data.p = *(gpointer*)data;
360 result->type = VAL_I32;
361 result->data.i = *(guint32*)data;
364 result->type = VAL_DOUBLE;
365 result->data.f = *(float*)data;
369 result->type = VAL_I64;
370 result->data.l = *(gint64*)data;
373 result->type = VAL_DOUBLE;
374 result->data.f = *(double*)data;
376 case MONO_TYPE_STRING:
377 case MONO_TYPE_SZARRAY:
378 case MONO_TYPE_CLASS:
379 case MONO_TYPE_OBJECT:
380 case MONO_TYPE_ARRAY:
381 result->type = VAL_OBJ;
382 result->data.p = *(gpointer*)data;
384 case MONO_TYPE_VALUETYPE:
385 if (type->data.klass->enumtype) {
386 stackval_from_data (type->data.klass->enum_basetype, result, data, pinvoke);
390 result->type = VAL_VALUET;
393 size = mono_class_native_size (type->data.klass, NULL);
395 size = mono_class_value_size (type->data.klass, NULL);
396 memcpy (result->data.vt, data, size);
400 g_warning ("got type 0x%02x", type->type);
401 g_assert_not_reached ();
406 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
409 gpointer *p = (gpointer*)data;
413 //printf ("TODAT0 %p\n", data);
414 switch (type->type) {
417 guint8 *p = (guint8*)data;
421 case MONO_TYPE_BOOLEAN: {
422 guint8 *p = (guint8*)data;
423 *p = (val->data.i != 0);
428 case MONO_TYPE_CHAR: {
429 guint16 *p = (guint16*)data;
434 mono_i *p = (mono_i*)data;
435 /* In theory the value used by stloc should match the local var type
436 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
437 a native int - both by csc and mcs). Not sure what to do about sign extension
438 as it is outside the spec... doing the obvious */
439 *p = val->type == VAL_I32 ? val->data.i : val->data.nati;
443 mono_u *p = (mono_u*)data;
445 *p = val->type == VAL_I32 ? (guint32)val->data.i : val->data.nati;
450 gint32 *p = (gint32*)data;
456 gint64 *p = (gint64*)data;
461 float *p = (float*)data;
466 double *p = (double*)data;
470 case MONO_TYPE_STRING:
471 case MONO_TYPE_SZARRAY:
472 case MONO_TYPE_CLASS:
473 case MONO_TYPE_OBJECT:
474 case MONO_TYPE_ARRAY:
475 case MONO_TYPE_PTR: {
476 gpointer *p = (gpointer*)data;
480 case MONO_TYPE_VALUETYPE:
481 if (type->data.klass->enumtype) {
482 stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
488 size = mono_class_native_size (type->data.klass, NULL);
490 size = mono_class_value_size (type->data.klass, NULL);
492 memcpy (data, val->data.vt, size);
496 g_warning ("got type %x", type->type);
497 g_assert_not_reached ();
501 #define FILL_IN_TRACE(exception, frame) \
504 stack_trace = dump_frame (frame); \
505 (exception)->stack_trace = mono_string_new (mono_domain_get(), stack_trace); \
506 g_free (stack_trace); \
509 #define THROW_EX(exception,ex_ip) \
511 frame->ip = (ex_ip); \
512 frame->ex = (MonoException*)(exception); \
513 FILL_IN_TRACE(frame->ex, frame); \
514 goto handle_exception; \
518 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
521 guint32 *lower_bounds;
524 lengths = alloca (sizeof (guint32) * klass->rank * 2);
525 for (i = 0; i < sig->param_count; ++i) {
526 lengths [i] = values->data.i;
529 if (klass->rank == sig->param_count) {
530 /* Only lengths provided. */
533 /* lower bounds are first. */
534 lower_bounds = lengths;
535 lengths += klass->rank;
537 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
541 ves_array_set (MonoInvocation *frame)
543 stackval *sp = frame->stack_args;
547 gint32 i, t, pos, esize;
553 ac = o->vtable->klass;
555 g_assert (ac->rank >= 1);
558 if (ao->bounds != NULL) {
559 pos -= ao->bounds [0].lower_bound;
560 for (i = 1; i < ac->rank; i++) {
561 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
562 ao->bounds [i].length) {
563 frame->ex = mono_get_exception_index_out_of_range ();
564 FILL_IN_TRACE(frame->ex, frame);
567 pos = pos*ao->bounds [i].length + sp [i].data.i -
568 ao->bounds [i].lower_bound;
570 } else if (pos >= ao->max_length) {
571 frame->ex = mono_get_exception_index_out_of_range ();
572 FILL_IN_TRACE(frame->ex, frame);
576 esize = mono_array_element_size (ac);
577 ea = mono_array_addr_with_size (ao, esize, pos);
579 mt = frame->method->signature->params [ac->rank];
580 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
584 ves_array_get (MonoInvocation *frame)
586 stackval *sp = frame->stack_args;
590 gint32 i, t, pos, esize;
596 ac = o->vtable->klass;
598 g_assert (ac->rank >= 1);
601 if (ao->bounds != NULL) {
602 pos -= ao->bounds [0].lower_bound;
603 for (i = 1; i < ac->rank; i++) {
604 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
605 ao->bounds [i].length) {
606 frame->ex = mono_get_exception_index_out_of_range ();
607 FILL_IN_TRACE(frame->ex, frame);
611 pos = pos*ao->bounds [i].length + sp [i].data.i -
612 ao->bounds [i].lower_bound;
614 } else if (pos >= ao->max_length) {
615 frame->ex = mono_get_exception_index_out_of_range ();
616 FILL_IN_TRACE(frame->ex, frame);
620 esize = mono_array_element_size (ac);
621 ea = mono_array_addr_with_size (ao, esize, pos);
623 mt = frame->method->signature->ret;
624 stackval_from_data (mt, frame->retval, ea, FALSE);
628 ves_array_element_address (MonoInvocation *frame)
630 stackval *sp = frame->stack_args;
634 gint32 i, t, pos, esize;
639 ac = o->vtable->klass;
641 g_assert (ac->rank >= 1);
644 if (ao->bounds != NULL) {
645 pos -= ao->bounds [0].lower_bound;
646 for (i = 1; i < ac->rank; i++) {
647 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
648 ao->bounds [i].length) {
649 frame->ex = mono_get_exception_index_out_of_range ();
650 FILL_IN_TRACE(frame->ex, frame);
653 pos = pos*ao->bounds [i].length + sp [i].data.i -
654 ao->bounds [i].lower_bound;
656 } else if (pos >= ao->max_length) {
657 frame->ex = mono_get_exception_index_out_of_range ();
658 FILL_IN_TRACE(frame->ex, frame);
662 esize = mono_array_element_size (ac);
663 ea = mono_array_addr_with_size (ao, esize, pos);
665 frame->retval->type = VAL_MP;
666 frame->retval->data.p = ea;
670 interp_walk_stack (MonoStackWalk func, gpointer user_data)
672 ThreadContext *context = TlsGetValue (thread_context_id);
673 MonoInvocation *frame = context->current_frame;
675 MonoMethodHeader *hd;
678 gboolean managed = FALSE;
679 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
680 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
683 hd = ((MonoMethodNormal*)frame->method)->header;
684 il_offset = frame->ip - hd->code;
685 if (!frame->method->wrapper_type)
688 if (func (frame->method, -1, il_offset, managed, user_data))
690 frame = frame->parent;
695 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor, ThreadContext *context)
699 MonoInvocation *old_frame = context->current_frame;
700 MonoInvocation *old_env_frame = context->env_frame;
701 jmp_buf *old_env = context->current_env;
704 context->current_frame = old_frame;
705 context->env_frame = old_env_frame;
706 context->current_env = old_env;
707 context->search_for_handler = 0;
711 context->env_frame = frame;
712 context->current_env = &env;
715 if (!frame->method->info) {
716 func = frame->method->info = mono_arch_create_trampoline (sig, string_ctor);
718 func = (MonoPIFunc)frame->method->info;
721 func = mono_arch_create_trampoline (sig, string_ctor);
724 context->current_frame = frame;
726 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
729 stackval_from_data (&mono_defaults.string_class->byval_arg,
730 frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
731 } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
732 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
734 context->current_frame = old_frame;
735 context->env_frame = old_env_frame;
736 context->current_env = old_env;
741 * runtime specifies that the implementation of the method is automatically
742 * provided by the runtime and is primarily used for the methods of delegates.
745 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
747 const char *name = frame->method->name;
748 MonoObject *obj = (MonoObject*)frame->obj;
753 mono_class_init (frame->method->klass);
755 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
756 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
757 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
760 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
761 nm = mono_marshal_get_delegate_invoke (frame->method);
762 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
763 ves_exec_method_with_context (&call, context);
767 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
768 nm = mono_marshal_get_delegate_begin_invoke (frame->method);
769 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
770 ves_exec_method_with_context (&call, context);
774 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
775 nm = mono_marshal_get_delegate_end_invoke (frame->method);
776 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
777 ves_exec_method_with_context (&call, context);
783 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
784 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
785 ves_array_set (frame);
788 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
789 ves_array_get (frame);
792 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
793 ves_array_element_address (frame);
798 g_error ("Don't know how to exec runtime method %s.%s::%s",
799 frame->method->klass->name_space, frame->method->klass->name,
800 frame->method->name);
804 dump_stack (stackval *stack, stackval *sp)
807 GString *str = g_string_new ("");
810 return g_string_free (str, FALSE);
814 #if SIZEOF_VOID_P == 4
815 case VAL_NATI: g_string_sprintfa (str, "[%d/0x%0x] ", s->data.nati, s->data.nati); break;
817 case VAL_NATI: g_string_sprintfa (str, "[%lld/0x%0llx] ", s->data.nati, s->data.nati); break;
819 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
820 case VAL_I64: g_string_sprintfa (str, "[%lldL] ", s->data.l); break;
821 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
823 if (!global_no_pointers)
824 g_string_sprintfa (str, "[vt: %p] ", s->data.vt);
826 g_string_sprintfa (str, "[vt%s] ", s->data.vt ? "" : "=null");
829 MonoObject *obj = s->data.p;
830 if (global_no_pointers && obj && obj->vtable) {
831 MonoClass *klass = mono_object_class (obj);
832 if (klass == mono_defaults.string_class) {
833 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
834 g_string_sprintfa (str, "[str:%s] ", utf8);
837 } else if (klass == mono_defaults.sbyte_class) {
838 g_string_sprintfa (str, "[b:%d] ",
839 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
841 } else if (klass == mono_defaults.int16_class) {
842 g_string_sprintfa (str, "[b:%d] ",
843 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
845 } else if (klass == mono_defaults.int32_class) {
846 g_string_sprintfa (str, "[b:%d] ",
847 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
849 } else if (klass == mono_defaults.byte_class) {
850 g_string_sprintfa (str, "[b:%u] ",
851 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
853 } else if (klass == mono_defaults.char_class
854 || klass == mono_defaults.uint16_class) {
855 g_string_sprintfa (str, "[b:%u] ",
856 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
858 } else if (klass == mono_defaults.uint32_class) {
859 g_string_sprintfa (str, "[b:%u] ",
860 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
862 } else if (klass == mono_defaults.int64_class) {
863 g_string_sprintfa (str, "[b:%lld] ",
864 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
866 } else if (klass == mono_defaults.uint64_class) {
867 g_string_sprintfa (str, "[b:%llu] ",
868 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
870 } else if (klass == mono_defaults.double_class) {
871 g_string_sprintfa (str, "[b:%0.5f] ",
872 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
874 } else if (klass == mono_defaults.single_class) {
875 g_string_sprintfa (str, "[b:%0.5f] ",
876 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
878 } else if (klass == mono_defaults.boolean_class) {
879 g_string_sprintfa (str, "[b:%s] ",
880 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
888 if (!global_no_pointers)
889 g_string_sprintfa (str, "[%c:%p] ", s->type == VAL_OBJ ? 'O' : s->type == VAL_MP ? 'M' : '?', s->data.p);
891 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
896 return g_string_free (str, FALSE);
900 dump_frame (MonoInvocation *inv)
902 GString *str = g_string_new ("");
905 for (i = 0; inv; inv = inv->parent, ++i) {
906 if (inv->method != NULL) {
910 const char * opname = "";
911 gchar *source = NULL;
918 k = inv->method->klass;
920 if ((inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
921 (inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
922 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
926 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
929 opname = mono_opcode_names [codep];
930 codep = inv->ip - hd->code;
932 source = mono_debug_source_location_from_il_offset (inv->method, codep, NULL);
935 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
937 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s) at %s\n", i, codep, opname,
938 k->name_space, k->name, inv->method->name, args, source);
940 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
941 k->name_space, k->name, inv->method->name, args);
946 return g_string_free (str, FALSE);
950 INLINE_STRING_LENGTH = 1,
951 INLINE_STRING_GET_CHARS,
954 INLINE_TYPE_ELEMENT_TYPE
959 MonoClassField *field;
960 } MonoRuntimeFieldInfo;
966 MonoRuntimeFieldInfo *field_info;
971 write32(unsigned char *p, guint32 v)
974 p[1] = (v >> 8) & 0xff;
975 p[2] = (v >> 16) & 0xff;
976 p[3] = (v >> 24) & 0xff;
979 static CRITICAL_SECTION calc_section;
982 calc_offsets (MonoImage *image, MonoMethod *method)
984 int i, align, size, offset = 0;
985 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
986 MonoMethodSignature *signature = method->signature;
987 register const unsigned char *ip, *end;
988 const MonoOpcode *opcode;
992 MonoDomain *domain = mono_domain_get ();
993 MethodRuntimeData *rtd;
996 mono_profiler_method_jit (method); /* sort of... */
997 /* intern the strings in the method. */
999 end = ip + header->code_size;
1006 opcode = &mono_opcodes [i];
1007 switch (opcode->argument) {
1008 case MonoInlineNone:
1011 case MonoInlineString:
1012 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
1015 case MonoInlineType:
1016 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1017 class = mono_class_get (image, read32 (ip + 1));
1018 mono_class_init (class);
1019 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
1020 mono_class_vtable (domain, class);
1024 case MonoInlineField:
1028 case MonoInlineMethod:
1029 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1030 m = mono_get_method (image, read32 (ip + 1), NULL);
1031 mono_class_init (m->klass);
1032 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
1033 mono_class_vtable (domain, m->klass);
1039 case MonoShortInlineR:
1041 case MonoInlineBrTarget:
1047 case MonoShortInlineVar:
1048 case MonoShortInlineI:
1049 case MonoShortInlineBrTarget:
1052 case MonoInlineSwitch: {
1065 g_assert_not_reached ();
1070 /* the rest needs to be locked so it is only done once */
1071 EnterCriticalSection(&calc_section);
1072 if (method->info != NULL) {
1073 LeaveCriticalSection(&calc_section);
1074 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1077 rtd = (MethodRuntimeData *)g_malloc0 (sizeof(MethodRuntimeData) + (header->num_locals - 1 + signature->hasthis + signature->param_count) * sizeof(guint32));
1078 for (i = 0; i < header->num_locals; ++i) {
1079 size = mono_type_size (header->locals [i], &align);
1080 offset += align - 1;
1081 offset &= ~(align - 1);
1082 rtd->offsets [i] = offset;
1085 rtd->locals_size = offset;
1087 if (signature->hasthis) {
1088 offset += sizeof (gpointer) - 1;
1089 offset &= ~(sizeof (gpointer) - 1);
1090 rtd->offsets [header->num_locals] = offset;
1091 offset += sizeof (gpointer);
1093 for (i = 0; i < signature->param_count; ++i) {
1094 if (signature->pinvoke) {
1095 size = mono_type_native_stack_size (signature->params [i], &align);
1099 size = mono_type_stack_size (signature->params [i], &align);
1100 offset += align - 1;
1101 offset &= ~(align - 1);
1102 rtd->offsets [signature->hasthis + header->num_locals + i] = offset;
1105 rtd->args_size = offset;
1106 rtd->field_info = g_malloc(n_fields * sizeof(MonoRuntimeFieldInfo));
1108 header->code = g_memdup(header->code, header->code_size);
1111 end = ip + header->code_size;
1118 opcode = &mono_opcodes [i];
1119 switch (opcode->argument) {
1120 case MonoInlineNone:
1123 case MonoInlineString:
1126 case MonoInlineType:
1129 case MonoInlineField:
1130 token = read32 (ip + 1);
1131 rtd->field_info[n_fields].field = mono_field_from_token (image, token, &class);
1132 mono_class_vtable (domain, class);
1133 g_assert(rtd->field_info[n_fields].field->parent == class);
1134 write32 ((unsigned char *)ip + 1, n_fields);
1138 case MonoInlineMethod:
1143 case MonoShortInlineR:
1145 case MonoInlineBrTarget:
1151 case MonoShortInlineVar:
1152 case MonoShortInlineI:
1153 case MonoShortInlineBrTarget:
1156 case MonoInlineSwitch: {
1169 g_assert_not_reached ();
1175 * We store the inline info in addr, since it's unused for IL methods.
1177 if (method->klass == mono_defaults.string_class) {
1178 if (strcmp (method->name, "get_Length") == 0)
1179 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
1180 else if (strcmp (method->name, "get_Chars") == 0)
1181 method->addr = GUINT_TO_POINTER (INLINE_STRING_GET_CHARS);
1182 } else if (method->klass == mono_defaults.array_class) {
1183 if (strcmp (method->name, "get_Length") == 0)
1184 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
1185 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
1186 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
1187 } else if (method->klass == mono_defaults.monotype_class) {
1188 if (strcmp (method->name, "GetElementType") == 0)
1189 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
1191 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1193 LeaveCriticalSection(&calc_section);
1196 #define LOCAL_POS(n) (frame->locals + rtd->offsets [n])
1197 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1199 #define ARG_POS(n) (args_pointers [(n)])
1200 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1201 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1203 typedef struct _vtallocation vtallocation;
1205 struct _vtallocation {
1210 char data [MONO_ZERO_LEN_ARRAY];
1211 double force_alignment;
1215 #define vt_allocmem(sz, var) \
1217 vtallocation *tmp, *prev; \
1220 while (tmp && (tmp->max_size < (sz))) { \
1225 tmp = alloca (sizeof (vtallocation) + (sz)); \
1226 tmp->max_size = (sz); \
1227 g_assert ((sz) < 10000); \
1231 prev->next = tmp->next; \
1233 vtalloc = tmp->next; \
1235 var = tmp->u.data; \
1238 #define vt_alloc(vtype,sp,native) \
1239 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1240 if (!(vtype)->byref) { \
1242 if (native) vtsize = mono_class_native_size ((vtype)->data.klass, NULL); \
1243 else vtsize = mono_class_value_size ((vtype)->data.klass, NULL); \
1244 vt_allocmem(vtsize, (sp)->data.vt); \
1248 #define vt_free(sp) \
1250 if ((sp)->type == VAL_VALUET) { \
1251 vtallocation *tmp = (vtallocation*)(((char*)(sp)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1252 tmp->next = vtalloc; \
1257 #define stackvalpush(val, sp) \
1259 (sp)->type = (val)->type; \
1260 (sp)->data = (val)->data; \
1261 if ((val)->type == VAL_VALUET) { \
1262 vtallocation *vala = (vtallocation*)(((char*)(val)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1263 vt_allocmem(vala->size, (sp)->data.vt); \
1264 memcpy((sp)->data.vt, (val)->data.vt, vala->size); \
1269 #define stackvalcpy(src, dest) \
1271 (dest)->type = (src)->type; \
1272 (dest)->data = (src)->data; \
1273 if ((dest)->type == VAL_VALUET) { \
1274 vtallocation *tmp = (vtallocation*)(((char*)(src)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1275 memcpy((dest)->data.vt, (src)->data.vt, tmp->size); \
1281 verify_method (MonoMethod *m)
1283 GSList *errors, *tmp;
1284 MonoVerifyInfo *info;
1286 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1288 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1289 for (tmp = errors; tmp; tmp = tmp->next) {
1291 g_print ("%s\n", info->message);
1295 mono_free_verify_list (errors);
1299 #define MYGUINT64_MAX 18446744073709551615ULL
1300 #define MYGINT64_MAX 9223372036854775807LL
1301 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1303 #define MYGUINT32_MAX 4294967295U
1304 #define MYGINT32_MAX 2147483647
1305 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1307 #define CHECK_ADD_OVERFLOW(a,b) \
1308 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1309 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1311 #define CHECK_SUB_OVERFLOW(a,b) \
1312 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1313 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1315 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1316 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1318 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1319 (guint32)(a) < (guint32)(b) ? -1 : 0
1321 #define CHECK_ADD_OVERFLOW64(a,b) \
1322 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1323 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1325 #define CHECK_SUB_OVERFLOW64(a,b) \
1326 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1327 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1329 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1330 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1332 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1333 (guint64)(a) < (guint64)(b) ? -1 : 0
1335 #if SIZEOF_VOID_P == 4
1336 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1337 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1339 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1340 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1343 /* Resolves to TRUE if the operands would overflow */
1344 #define CHECK_MUL_OVERFLOW(a,b) \
1345 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1346 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1347 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1348 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1349 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1350 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1351 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1353 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1354 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1355 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1357 #define CHECK_MUL_OVERFLOW64(a,b) \
1358 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1359 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1360 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1361 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1362 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1363 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1364 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1366 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1367 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1368 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1370 #if SIZEOF_VOID_P == 4
1371 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1372 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1374 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1375 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1379 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1381 MonoInvocation frame;
1382 ThreadContext *context = TlsGetValue (thread_context_id);
1383 MonoObject *retval = NULL;
1384 MonoMethodSignature *sig = method->signature;
1385 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1386 int i, type, isobject = 0;
1389 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1390 ThreadContext context_struct;
1391 MonoInvocation *old_frame;
1393 if (context == NULL) {
1394 context = &context_struct;
1395 context_struct.base_frame = &frame;
1396 context_struct.current_frame = NULL;
1397 context_struct.env_frame = NULL;
1398 context_struct.current_env = NULL;
1399 context_struct.search_for_handler = 0;
1400 TlsSetValue (thread_context_id, context);
1403 old_frame = context->current_frame;
1406 /* FIXME: Set frame for execption handling. */
1408 switch (sig->ret->type) {
1409 case MONO_TYPE_VOID:
1411 case MONO_TYPE_STRING:
1412 case MONO_TYPE_OBJECT:
1413 case MONO_TYPE_CLASS:
1414 case MONO_TYPE_ARRAY:
1415 case MONO_TYPE_SZARRAY:
1418 case MONO_TYPE_VALUETYPE:
1419 retval = mono_object_new (mono_domain_get (), klass);
1420 ret = ((char*)retval) + sizeof (MonoObject);
1421 if (!sig->ret->data.klass->enumtype)
1422 result.data.vt = ret;
1425 retval = mono_object_new (mono_domain_get (), klass);
1426 ret = ((char*)retval) + sizeof (MonoObject);
1430 for (i = 0; i < sig->param_count; ++i) {
1431 if (sig->params [i]->byref) {
1432 args [i].type = VAL_POINTER;
1433 args [i].data.p = params [i];
1436 type = sig->params [i]->type;
1441 case MONO_TYPE_BOOLEAN:
1442 args [i].type = VAL_I32;
1443 args [i].data.i = *(MonoBoolean*)params [i];
1447 case MONO_TYPE_CHAR:
1448 args [i].type = VAL_I32;
1449 args [i].data.i = *(gint16*)params [i];
1451 #if SIZEOF_VOID_P == 4
1452 case MONO_TYPE_U: /* use VAL_POINTER? */
1457 args [i].type = VAL_I32;
1458 args [i].data.i = *(gint32*)params [i];
1460 #if SIZEOF_VOID_P == 8
1466 args [i].type = VAL_I64;
1467 args [i].data.l = *(gint64*)params [i];
1469 case MONO_TYPE_VALUETYPE:
1470 if (sig->params [i]->data.klass->enumtype) {
1471 type = sig->params [i]->data.klass->enum_basetype->type;
1474 args [i].type = VAL_POINTER;
1475 args [i].data.p = params [i];
1478 case MONO_TYPE_STRING:
1479 case MONO_TYPE_CLASS:
1480 case MONO_TYPE_ARRAY:
1481 case MONO_TYPE_SZARRAY:
1482 case MONO_TYPE_OBJECT:
1483 args [i].type = VAL_OBJ;
1484 args [i].data.p = params [i];
1487 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1491 if (method->klass->valuetype)
1492 /* Unbox the instance, since valuetype methods expect an interior pointer. */
1493 obj = mono_object_unbox (obj);
1495 INIT_FRAME(&frame,context->current_frame,obj,args,&result,method);
1497 frame.invoke_trap = 1;
1498 ves_exec_method_with_context (&frame, context);
1499 if (context == &context_struct)
1500 TlsSetValue (thread_context_id, NULL);
1502 context->current_frame = old_frame;
1503 if (frame.ex != NULL) {
1505 *exc = (MonoObject*) frame.ex;
1506 if (*exc == (MonoObject *)quit_exception)
1507 mono_print_unhandled_exception(*exc);
1510 if (context->current_env != NULL) {
1511 context->env_frame->ex = frame.ex;
1512 longjmp(*context->current_env, 1);
1515 printf("dropped exception...\n");
1517 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1519 if (isobject || method->string_ctor)
1520 return result.data.p;
1521 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1525 static CRITICAL_SECTION create_method_pointer_mutex;
1527 static MonoGHashTable *method_pointer_hash = NULL;
1530 mono_create_method_pointer (MonoMethod *method)
1535 EnterCriticalSection (&create_method_pointer_mutex);
1536 if (!method_pointer_hash) {
1537 method_pointer_hash = mono_g_hash_table_new (NULL, NULL);
1539 addr = mono_g_hash_table_lookup (method_pointer_hash, method);
1541 LeaveCriticalSection (&create_method_pointer_mutex);
1546 * If it is a static P/Invoke method, we can just return the pointer
1547 * to the method implementation.
1549 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
1550 ji = g_new0 (MonoJitInfo, 1);
1551 ji->method = method;
1553 ji->code_start = method->addr;
1555 mono_jit_info_table_add (mono_root_domain, ji);
1557 addr = method->addr;
1560 addr = mono_arch_create_method_pointer (method);
1562 mono_g_hash_table_insert (method_pointer_hash, method, addr);
1563 LeaveCriticalSection (&create_method_pointer_mutex);
1569 get_native_wrapper(MonoMethod *method, ThreadContext *context)
1573 MonoMethod *wrapper;
1574 old_env = context->current_env;
1575 if (setjmp(env) != 0) {
1576 context->current_env = old_env;
1577 context->search_for_handler = 1;
1580 context->current_env = &env;
1581 wrapper = mono_marshal_get_native_wrapper (method);
1582 context->current_env = old_env;
1587 * Need to optimize ALU ops when natural int == int32
1589 * IDEA: if we maintain a stack of ip, sp to be checked
1590 * in the return opcode, we could inline simple methods that don't
1591 * use the stack or local variables....
1593 * The {,.S} versions of many opcodes can/should be merged to reduce code
1598 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
1600 MonoDomain *domain = mono_domain_get ();
1601 MonoInvocation child_frame;
1602 MonoMethodHeader *header;
1603 MonoMethodSignature *signature;
1605 GSList *finally_ips = NULL;
1606 const unsigned char *endfinally_ip = NULL;
1607 register const unsigned char *ip;
1608 register stackval *sp = NULL;
1609 MethodRuntimeData *rtd;
1610 void **args_pointers;
1611 gint tracing = global_tracing;
1612 unsigned char tail_recursion = 0;
1613 unsigned char unaligned_address = 0;
1614 unsigned char volatile_address = 0;
1615 vtallocation *vtalloc = NULL;
1616 MonoVTable *method_class_vt;
1620 frame->ip = ip = NULL;
1621 context->current_frame = frame;
1623 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1624 frame->method = get_native_wrapper (frame->method, context);
1625 if (frame->method == NULL)
1629 method_class_vt = mono_class_vtable (domain, frame->method->klass);
1630 if (!method_class_vt->initialized)
1631 mono_runtime_class_init (method_class_vt);
1632 signature = frame->method->signature;
1636 header = ((MonoMethodNormal *)frame->method)->header;
1638 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1639 if (!frame->method->addr) {
1640 /* assumes all internal calls with an array this are built in... */
1641 if (signature->hasthis && frame->method->klass->rank) {
1642 ves_runtime_method (frame, context);
1644 goto handle_exception;
1647 frame->method->addr = mono_lookup_internal_call (frame->method);
1649 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1650 frame->method->string_ctor, context);
1652 goto handle_exception;
1655 else if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1656 ves_runtime_method (frame, context);
1658 goto handle_exception;
1662 /*verify_method (frame->method);*/
1664 image = frame->method->klass->image;
1666 if (!frame->method->info)
1667 calc_offsets (image, frame->method);
1668 rtd = frame->method->info;
1671 * with alloca we get the expected huge performance gain
1672 * stackval *stack = g_new0(stackval, header->max_stack);
1674 g_assert (header->max_stack < 10000);
1675 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1677 if (header->num_locals) {
1678 g_assert (rtd->locals_size < 65536);
1679 frame->locals = alloca (rtd->locals_size);
1681 * yes, we do it unconditionally, because it needs to be done for
1682 * some cases anyway and checking for that would be even slower.
1684 memset (frame->locals, 0, rtd->locals_size);
1688 * Copy args from stack_args to args.
1690 if (signature->param_count || signature->hasthis) {
1692 int has_this = signature->hasthis;
1694 g_assert (rtd->args_size < 10000);
1695 frame->args = alloca (rtd->args_size);
1696 g_assert ((signature->param_count + has_this) < 1000);
1697 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1700 this_arg = args_pointers [0] = frame->args;
1701 *this_arg = frame->obj;
1703 for (i = 0; i < signature->param_count; ++i) {
1704 args_pointers [i + has_this] = frame->args + rtd->offsets [header->num_locals + has_this + i];
1705 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1709 child_frame.parent = frame;
1710 frame->child = &child_frame;
1717 * using while (ip < end) may result in a 15% performance drop,
1718 * but it may be useful for debug
1722 /*g_assert (sp >= stack);*/
1726 char *ins, *discode;
1727 if (sp > frame->stack) {
1728 ins = dump_stack (frame->stack, sp);
1730 ins = g_strdup ("");
1733 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1734 discode [strlen (discode) - 1] = 0; /* no \n */
1735 g_print ("(%u) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1747 G_BREAKPOINT (); /* this is not portable... */
1752 CASE (CEE_LDARG_3) {
1753 int n = (*ip)-CEE_LDARG_0;
1755 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1756 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1763 CASE (CEE_LDLOC_3) {
1764 int n = (*ip)-CEE_LDLOC_0;
1765 MonoType *vartype = LOCAL_TYPE (header, n);
1767 if (vartype->type == MONO_TYPE_I4) {
1769 sp->data.i = *(gint32*) LOCAL_POS (n);
1773 vt_alloc (vartype, sp, FALSE);
1774 stackval_from_data (vartype, sp, LOCAL_POS (n), FALSE);
1782 CASE (CEE_STLOC_3) {
1783 int n = (*ip)-CEE_STLOC_0;
1786 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1787 gint32 *p = (gint32*)LOCAL_POS (n);
1791 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1798 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1799 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1803 CASE (CEE_LDARGA_S) {
1805 sp->data.vt = ARG_POS (*ip);
1814 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1820 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1821 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1825 CASE (CEE_LDLOCA_S) {
1827 sp->data.p = LOCAL_POS (*ip);
1836 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1846 CASE (CEE_LDC_I4_M1)
1862 sp->data.i = (*ip) - CEE_LDC_I4_0;
1869 sp->data.i = *(const gint8 *)ip;
1876 sp->data.i = read32 (ip);
1883 sp->data.l = read64 (ip);
1890 sp->type = VAL_DOUBLE;
1899 sp->type = VAL_DOUBLE;
1900 readr8(ip, &sp->data.f);
1904 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1906 stackvalpush(sp - 1, sp);
1914 CASE (CEE_JMP) ves_abort(); BREAK;
1915 CASE (CEE_CALLVIRT) /* Fall through */
1916 CASE (CEE_CALLI) /* Fall through */
1918 MonoMethodSignature *csignature;
1920 stackval *endsp = sp;
1922 int virtual = *ip == CEE_CALLVIRT;
1923 int calli = *ip == CEE_CALLI;
1924 unsigned char *code = NULL;
1927 * We ignore tail recursion for now.
1934 token = read32 (ip);
1940 if (frame->method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE &&
1941 (ji = mono_jit_info_table_find (mono_root_domain, code)) != NULL) {
1942 child_frame.method = ji->method;
1943 csignature = ji->method->signature;
1945 else if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1946 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1947 child_frame.method = NULL;
1949 g_assert_not_reached ();
1953 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
1954 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
1956 child_frame.method = mono_get_method (image, token, NULL);
1957 if (!child_frame.method)
1958 THROW_EX (mono_get_exception_missing_method (), ip -5);
1959 csignature = child_frame.method->signature;
1961 stackval *this_arg = &sp [-csignature->param_count-1];
1962 if (!this_arg->data.p)
1963 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1964 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1965 if (!child_frame.method)
1966 THROW_EX (mono_get_exception_missing_method (), ip -5);
1970 if (frame->method->wrapper_type == MONO_WRAPPER_NONE)
1971 if (child_frame.method && child_frame.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1972 child_frame.method = mono_marshal_get_synchronized_wrapper (child_frame.method);
1974 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
1975 /* decrement by the actual number of args */
1976 if (csignature->param_count) {
1977 sp -= csignature->param_count;
1978 child_frame.stack_args = sp;
1980 child_frame.stack_args = NULL;
1982 if (csignature->hasthis) {
1983 g_assert (sp >= frame->stack);
1986 * It may also be a TP from LD(S)FLDA
1987 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_MP);
1989 if (sp->type == VAL_OBJ && child_frame.method &&
1990 child_frame.method->klass->valuetype) /* unbox it */
1991 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1993 child_frame.obj = sp->data.p;
1995 child_frame.obj = NULL;
1997 if (csignature->ret->type != MONO_TYPE_VOID) {
1998 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
1999 child_frame.retval = &retval;
2001 child_frame.retval = NULL;
2004 child_frame.ip = NULL;
2005 child_frame.ex = NULL;
2006 child_frame.ex_handler = NULL;
2008 if (!child_frame.method) {
2010 ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE, context);
2011 if (child_frame.ex) {
2012 frame->ex = child_frame.ex;
2013 goto handle_exception;
2015 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
2016 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
2017 g_assert (child_frame.method);
2018 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
2019 ves_exec_method_with_context (&child_frame, context);
2021 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
2022 case INLINE_STRING_LENGTH:
2023 retval.type = VAL_I32;
2024 retval.data.i = ((MonoString*)sp->data.p)->length;
2025 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
2027 case INLINE_STRING_GET_CHARS: {
2028 int idx = GET_NATI(sp [1]);
2029 if ((idx < 0) || (idx >= mono_string_length ((MonoString*)sp->data.p))) {
2030 child_frame.ex = mono_get_exception_index_out_of_range ();
2031 FILL_IN_TRACE(child_frame.ex, &child_frame);
2034 retval.type = VAL_I32;
2035 retval.data.i = mono_string_chars((MonoString*)sp->data.p)[idx];
2039 case INLINE_ARRAY_LENGTH:
2040 retval.type = VAL_I32;
2041 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
2043 case INLINE_ARRAY_RANK:
2044 retval.type = VAL_I32;
2045 retval.data.i = mono_object_class (sp->data.p)->rank;
2047 case INLINE_TYPE_ELEMENT_TYPE:
2048 retval.type = VAL_OBJ;
2050 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
2051 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
2052 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
2053 else if (c->element_class)
2054 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
2056 retval.data.p = NULL;
2060 ves_exec_method_with_context (&child_frame, context);
2064 context->current_frame = frame;
2066 while (endsp > sp) {
2071 if (child_frame.ex) {
2073 * An exception occurred, need to run finally, fault and catch handlers..
2075 frame->ex = child_frame.ex;
2076 if (context->search_for_handler) {
2077 context->search_for_handler = 0;
2078 goto handle_exception;
2080 goto handle_finally;
2083 /* need to handle typedbyref ... */
2084 if (csignature->ret->type != MONO_TYPE_VOID) {
2091 if (signature->ret->type != MONO_TYPE_VOID) {
2093 if (sp->type == VAL_VALUET) {
2094 /* the caller has already allocated the memory */
2095 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
2098 *frame->retval = *sp;
2101 if (sp > frame->stack)
2102 g_warning ("more values on stack: %d", sp-frame->stack);
2105 CASE (CEE_BR_S) /* Fall through */
2107 if (*ip == CEE_BR) {
2109 ip += (gint32) read32(ip);
2113 ip += (signed char) *ip;
2117 CASE (CEE_BRFALSE) /* Fall through */
2118 CASE (CEE_BRFALSE_S) {
2121 if (*ip == CEE_BRFALSE_S) {
2122 broffset = (signed char)ip [1];
2125 broffset = (gint32) read32 (ip + 1);
2130 case VAL_I32: result = sp->data.i == 0; break;
2131 case VAL_I64: result = sp->data.l == 0; break;
2132 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
2133 default: result = sp->data.p == NULL; break;
2139 CASE (CEE_BRTRUE) /* Fall through */
2140 CASE (CEE_BRTRUE_S) {
2143 if (*ip == CEE_BRTRUE_S) {
2144 broffset = (signed char)ip [1];
2147 broffset = (gint32) read32 (ip + 1);
2152 case VAL_I32: result = sp->data.i != 0; break;
2153 case VAL_I64: result = sp->data.l != 0; break;
2154 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
2155 default: result = sp->data.p != NULL; break;
2161 CASE (CEE_BEQ) /* Fall through */
2165 if (*ip == CEE_BEQ_S) {
2166 broffset = (signed char)ip [1];
2169 broffset = (gint32) read32 (ip + 1);
2173 if (sp->type == VAL_I32)
2174 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
2175 else if (sp->type == VAL_I64)
2176 result = sp [0].data.l == sp [1].data.l;
2177 else if (sp->type == VAL_DOUBLE)
2178 result = sp [0].data.f == sp [1].data.f;
2180 result = sp [0].data.nati == (mono_i)GET_NATI (sp [1]);
2185 CASE (CEE_BGE) /* Fall through */
2189 if (*ip == CEE_BGE_S) {
2190 broffset = (signed char)ip [1];
2193 broffset = (gint32) read32 (ip + 1);
2197 if (sp->type == VAL_I32)
2198 result = (mono_i)sp [0].data.i >= (mono_i)GET_NATI (sp [1]);
2199 else if (sp->type == VAL_I64)
2200 result = sp [0].data.l >= sp [1].data.l;
2201 else if (sp->type == VAL_DOUBLE)
2202 result = sp [0].data.f >= sp [1].data.f;
2204 result = (mono_i)sp [0].data.nati >= (mono_i)GET_NATI (sp [1]);
2209 CASE (CEE_BGT) /* Fall through */
2213 if (*ip == CEE_BGT_S) {
2214 broffset = (signed char)ip [1];
2217 broffset = (gint32) read32 (ip + 1);
2221 if (sp->type == VAL_I32)
2222 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
2223 else if (sp->type == VAL_I64)
2224 result = sp [0].data.l > sp [1].data.l;
2225 else if (sp->type == VAL_DOUBLE)
2226 result = sp [0].data.f > sp [1].data.f;
2228 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
2233 CASE (CEE_BLT) /* Fall through */
2237 if (*ip == CEE_BLT_S) {
2238 broffset = (signed char)ip [1];
2241 broffset = (gint32) read32 (ip + 1);
2245 if (sp->type == VAL_I32)
2246 result = (mono_i)sp[0].data.i < (mono_i)GET_NATI(sp[1]);
2247 else if (sp->type == VAL_I64)
2248 result = sp[0].data.l < sp[1].data.l;
2249 else if (sp->type == VAL_DOUBLE)
2250 result = sp[0].data.f < sp[1].data.f;
2252 result = (mono_i)sp[0].data.nati < (mono_i)GET_NATI(sp[1]);
2257 CASE (CEE_BLE) /* fall through */
2261 if (*ip == CEE_BLE_S) {
2262 broffset = (signed char)ip [1];
2265 broffset = (gint32) read32 (ip + 1);
2270 if (sp->type == VAL_I32)
2271 result = (mono_i)sp [0].data.i <= (mono_i)GET_NATI (sp [1]);
2272 else if (sp->type == VAL_I64)
2273 result = sp [0].data.l <= sp [1].data.l;
2274 else if (sp->type == VAL_DOUBLE)
2275 result = sp [0].data.f <= sp [1].data.f;
2277 result = (mono_i)sp [0].data.nati <= (mono_i)GET_NATI (sp [1]);
2283 CASE (CEE_BNE_UN) /* Fall through */
2284 CASE (CEE_BNE_UN_S) {
2287 if (*ip == CEE_BNE_UN_S) {
2288 broffset = (signed char)ip [1];
2291 broffset = (gint32) read32 (ip + 1);
2295 if (sp->type == VAL_I32)
2296 result = (mono_u)sp [0].data.i != (mono_u)GET_NATI (sp [1]);
2297 else if (sp->type == VAL_I64)
2298 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
2299 else if (sp->type == VAL_DOUBLE)
2300 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2301 (sp [0].data.f != sp [1].data.f);
2303 result = (mono_u)sp [0].data.nati != (mono_u)GET_NATI (sp [1]);
2308 CASE (CEE_BGE_UN) /* Fall through */
2309 CASE (CEE_BGE_UN_S) {
2312 if (*ip == CEE_BGE_UN_S) {
2313 broffset = (signed char)ip [1];
2316 broffset = (gint32) read32 (ip + 1);
2320 if (sp->type == VAL_I32)
2321 result = (mono_u)sp [0].data.i >= (mono_u)GET_NATI (sp [1]);
2322 else if (sp->type == VAL_I64)
2323 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
2324 else if (sp->type == VAL_DOUBLE)
2325 result = !isless (sp [0].data.f,sp [1].data.f);
2327 result = (mono_u)sp [0].data.nati >= (mono_u)GET_NATI (sp [1]);
2332 CASE (CEE_BGT_UN) /* Fall through */
2333 CASE (CEE_BGT_UN_S) {
2336 if (*ip == CEE_BGT_UN_S) {
2337 broffset = (signed char)ip [1];
2340 broffset = (gint32) read32 (ip + 1);
2344 if (sp->type == VAL_I32)
2345 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2346 else if (sp->type == VAL_I64)
2347 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2348 else if (sp->type == VAL_DOUBLE)
2349 result = isgreater (sp [0].data.f, sp [1].data.f);
2351 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
2356 CASE (CEE_BLE_UN) /* Fall through */
2357 CASE (CEE_BLE_UN_S) {
2360 if (*ip == CEE_BLE_UN_S) {
2361 broffset = (signed char)ip [1];
2364 broffset = (gint32) read32 (ip + 1);
2368 if (sp->type == VAL_I32)
2369 result = (mono_u)sp [0].data.i <= (mono_u)GET_NATI (sp [1]);
2370 else if (sp->type == VAL_I64)
2371 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2372 else if (sp->type == VAL_DOUBLE)
2373 result = islessequal (sp [0].data.f, sp [1].data.f);
2375 result = (mono_u)sp [0].data.nati <= (mono_u)GET_NATI (sp [1]);
2380 CASE (CEE_BLT_UN) /* Fall through */
2381 CASE (CEE_BLT_UN_S) {
2384 if (*ip == CEE_BLT_UN_S) {
2385 broffset = (signed char)ip [1];
2388 broffset = (gint32) read32 (ip + 1);
2392 if (sp->type == VAL_I32)
2393 result = (mono_u)sp[0].data.i < (mono_u)GET_NATI(sp[1]);
2394 else if (sp->type == VAL_I64)
2395 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2396 else if (sp->type == VAL_DOUBLE)
2397 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2398 (sp [0].data.f < sp [1].data.f);
2400 result = (mono_u)sp[0].data.nati < (mono_u)GET_NATI(sp[1]);
2407 const unsigned char *st;
2411 st = ip + sizeof (gint32) * n;
2413 if ((guint32)sp->data.i < n) {
2415 ip += sizeof (gint32) * (guint32)sp->data.i;
2416 offset = read32 (ip);
2425 sp[-1].type = VAL_I32;
2426 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2430 sp[-1].type = VAL_I32;
2431 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2435 sp[-1].type = VAL_I32;
2436 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2440 sp[-1].type = VAL_I32;
2441 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2443 CASE (CEE_LDIND_I4) /* Fall through */
2446 sp[-1].type = VAL_I32;
2447 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2451 sp[-1].type = VAL_I64;
2452 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2456 sp[-1].type = VAL_NATI;
2457 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2461 sp[-1].type = VAL_DOUBLE;
2462 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2466 sp[-1].type = VAL_DOUBLE;
2467 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2469 CASE (CEE_LDIND_REF)
2471 sp[-1].type = VAL_OBJ;
2472 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2474 CASE (CEE_STIND_REF) {
2482 CASE (CEE_STIND_I1) {
2487 *p = (gint8)sp[1].data.i;
2490 CASE (CEE_STIND_I2) {
2495 *p = (gint16)sp[1].data.i;
2498 CASE (CEE_STIND_I4) {
2506 CASE (CEE_STIND_I) {
2511 *p = (mono_i)sp[1].data.p;
2514 CASE (CEE_STIND_I8) {
2522 CASE (CEE_STIND_R4) {
2527 *p = (gfloat)sp[1].data.f;
2530 CASE (CEE_STIND_R8) {
2541 /* should probably consider the pointers as unsigned */
2542 if (sp->type == VAL_I32) {
2543 if (sp [-1].type == VAL_I32)
2544 sp [-1].data.i += sp [0].data.i;
2546 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.i;
2547 } else if (sp->type == VAL_I64)
2548 sp [-1].data.l += sp [0].data.l;
2549 else if (sp->type == VAL_DOUBLE)
2550 sp [-1].data.f += sp [0].data.f;
2552 if (sp [-1].type == VAL_I32) {
2553 sp [-1].data.nati = sp [-1].data.i + sp [0].data.nati;
2554 sp [-1].type = sp [0].type;
2556 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.nati;
2562 /* should probably consider the pointers as unsigned */
2563 if (sp->type == VAL_I32) {
2564 if (sp [-1].type == VAL_I32)
2565 sp [-1].data.i -= sp [0].data.i;
2567 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
2568 sp [-1].type = VAL_NATI;
2570 } else if (sp->type == VAL_I64)
2571 sp [-1].data.l -= sp [0].data.l;
2572 else if (sp->type == VAL_DOUBLE)
2573 sp [-1].data.f -= sp [0].data.f;
2575 if (sp [-1].type == VAL_I32) {
2576 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
2577 sp [-1].type = sp [0].type;
2579 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
2585 if (sp->type == VAL_I32) {
2586 if (sp [-1].type == VAL_I32)
2587 sp [-1].data.i *= sp [0].data.i;
2589 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
2590 } else if (sp->type == VAL_I64)
2591 sp [-1].data.l *= sp [0].data.l;
2592 else if (sp->type == VAL_DOUBLE)
2593 sp [-1].data.f *= sp [0].data.f;
2595 if (sp [-1].type == VAL_NATI)
2596 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.nati;
2598 sp [-1].data.nati = sp [-1].data.i * sp [0].data.nati;
2599 sp [-1].type = VAL_NATI;
2606 if (sp->type == VAL_I32) {
2607 if (sp [0].data.i == 0)
2608 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2609 if (sp [-1].type == VAL_I32)
2610 sp [-1].data.i /= sp [0].data.i;
2612 sp [-1].data.nati /= sp [0].data.i;
2613 } else if (sp->type == VAL_I64) {
2614 if (sp [0].data.l == 0)
2615 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2616 sp [-1].data.l /= sp [0].data.l;
2617 } else if (sp->type == VAL_DOUBLE) {
2618 /* set NaN is divisor is 0.0 */
2619 sp [-1].data.f /= sp [0].data.f;
2621 if (sp [-1].type == VAL_NATI)
2622 sp [-1].data.nati = sp [-1].data.nati / sp [0].data.nati;
2624 sp [-1].data.nati = sp [-1].data.i / sp [0].data.nati;
2625 sp [-1].type = VAL_NATI;
2632 if (sp->type == VAL_I32) {
2633 if (sp [0].data.i == 0)
2634 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2635 if (sp [-1].type == VAL_NATI)
2636 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.i;
2638 sp [-1].data.i = (guint32)sp [-1].data.i / (guint32)sp [0].data.i;
2639 } else if (sp->type == VAL_I64) {
2641 if (sp [0].data.l == 0)
2642 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2643 val = sp [-1].data.l;
2644 val /= (guint64)sp [0].data.l;
2645 sp [-1].data.l = val;
2647 if (sp [0].data.nati == 0)
2648 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2649 if (sp [-1].type == VAL_NATI)
2650 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.nati;
2652 sp [-1].data.nati = (mono_u)sp [-1].data.i / (mono_u)sp [0].data.nati;
2653 sp [-1].type = VAL_NATI;
2660 if (sp->type == VAL_I32) {
2661 if (sp [0].data.i == 0)
2662 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2663 if (sp [-1].type == VAL_NATI)
2664 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.i;
2666 sp [-1].data.i = sp [-1].data.i % sp [0].data.i;
2667 } else if (sp->type == VAL_I64) {
2668 if (sp [0].data.l == 0)
2669 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2670 sp [-1].data.l %= sp [0].data.l;
2671 } else if (sp->type == VAL_DOUBLE) {
2672 /* FIXME: what do we actually do here? */
2673 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2675 if (sp [0].data.nati == 0)
2676 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2677 if (sp [-1].type == VAL_NATI)
2678 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.nati;
2680 sp [-1].data.nati = (mono_i)sp [-1].data.i % (mono_i)sp [0].data.nati;
2681 sp [-1].type = VAL_NATI;
2688 if (sp->type == VAL_I32) {
2689 if (sp [0].data.i == 0)
2690 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2691 if (sp [-1].type == VAL_NATI)
2692 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.i;
2694 sp [-1].data.i = (guint32)sp [-1].data.i % (guint32)sp [0].data.i;
2695 } else if (sp->type == VAL_I64) {
2696 if (sp [0].data.l == 0)
2697 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2698 sp [-1].data.l = (guint64)sp [-1].data.l % (guint64)sp [0].data.l;
2699 } else if (sp->type == VAL_DOUBLE) {
2700 /* unspecified behaviour according to the spec */
2702 if (sp [0].data.nati == 0)
2703 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2704 if (sp [-1].type == VAL_NATI)
2705 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.nati;
2707 sp [-1].data.nati = (mono_u)sp [-1].data.i % (mono_u)sp [0].data.nati;
2708 sp [-1].type = VAL_NATI;
2715 if (sp->type == VAL_I32) {
2716 if (sp [-1].type == VAL_NATI)
2717 sp [-1].data.nati &= sp [0].data.i;
2719 sp [-1].data.i &= sp [0].data.i;
2721 else if (sp->type == VAL_I64)
2722 sp [-1].data.l &= sp [0].data.l;
2724 if (sp [-1].type == VAL_NATI)
2725 sp [-1].data.nati = (mono_i)sp [-1].data.nati & (mono_i)sp [0].data.nati;
2727 sp [-1].data.nati = (mono_i)sp [-1].data.i & (mono_i)sp [0].data.nati;
2728 sp [-1].type = VAL_NATI;
2735 if (sp->type == VAL_I32) {
2736 if (sp [-1].type == VAL_NATI)
2737 sp [-1].data.nati |= sp [0].data.i;
2739 sp [-1].data.i |= sp [0].data.i;
2741 else if (sp->type == VAL_I64)
2742 sp [-1].data.l |= sp [0].data.l;
2744 if (sp [-1].type == VAL_NATI)
2745 sp [-1].data.nati = (mono_i)sp [-1].data.nati | (mono_i)sp [0].data.nati;
2747 sp [-1].data.nati = (mono_i)sp [-1].data.i | (mono_i)sp [0].data.nati;
2748 sp [-1].type = VAL_NATI;
2755 if (sp->type == VAL_I32) {
2756 if (sp [-1].type == VAL_NATI)
2757 sp [-1].data.nati ^= sp [0].data.i;
2759 sp [-1].data.i ^= sp [0].data.i;
2761 else if (sp->type == VAL_I64)
2762 sp [-1].data.l ^= sp [0].data.l;
2764 if (sp [-1].type == VAL_NATI)
2765 sp [-1].data.nati = (mono_i)sp [-1].data.nati ^ (mono_i)sp [0].data.nati;
2767 sp [-1].data.nati = (mono_i)sp [-1].data.i ^ (mono_i)sp [0].data.nati;
2768 sp [-1].type = VAL_NATI;
2775 if (sp [-1].type == VAL_I32)
2776 sp [-1].data.i <<= GET_NATI (sp [0]);
2777 else if (sp [-1].type == VAL_I64)
2778 sp [-1].data.l <<= GET_NATI (sp [0]);
2780 sp [-1].data.nati <<= GET_NATI (sp [0]);
2785 if (sp [-1].type == VAL_I32)
2786 sp [-1].data.i >>= GET_NATI (sp [0]);
2787 else if (sp [-1].type == VAL_I64)
2788 sp [-1].data.l >>= GET_NATI (sp [0]);
2790 sp [-1].data.nati = ((mono_i)sp [-1].data.nati) >> GET_NATI (sp [0]);
2795 if (sp [-1].type == VAL_I32)
2796 sp [-1].data.i = (guint)sp [-1].data.i >> GET_NATI (sp [0]);
2797 else if (sp [-1].type == VAL_I64)
2798 sp [-1].data.l = (guint64)sp [-1].data.l >> GET_NATI (sp [0]);
2800 sp [-1].data.nati = ((mono_u)sp[-1].data.nati) >> GET_NATI (sp [0]);
2805 if (sp->type == VAL_I32)
2806 sp->data.i = - sp->data.i;
2807 else if (sp->type == VAL_I64)
2808 sp->data.l = - sp->data.l;
2809 else if (sp->type == VAL_DOUBLE)
2810 sp->data.f = - sp->data.f;
2811 else if (sp->type == VAL_NATI)
2812 sp->data.nati = - (mono_i)sp->data.nati;
2818 if (sp->type == VAL_I32)
2819 sp->data.i = ~ sp->data.i;
2820 else if (sp->type == VAL_I64)
2821 sp->data.l = ~ sp->data.l;
2822 else if (sp->type == VAL_NATI)
2823 sp->data.nati = ~ (mono_i)sp->data.p;
2826 CASE (CEE_CONV_U1) {
2828 switch (sp [-1].type) {
2830 sp [-1].data.i = (guint8)sp [-1].data.f;
2833 sp [-1].data.i = (guint8)sp [-1].data.l;
2838 sp [-1].data.i = (guint8)sp [-1].data.i;
2841 sp [-1].data.i = (guint8)sp [-1].data.nati;
2844 sp [-1].type = VAL_I32;
2847 CASE (CEE_CONV_I1) {
2849 switch (sp [-1].type) {
2851 sp [-1].data.i = (gint8)sp [-1].data.f;
2854 sp [-1].data.i = (gint8)sp [-1].data.l;
2859 sp [-1].data.i = (gint8)sp [-1].data.i;
2862 sp [-1].data.i = (gint8)sp [-1].data.nati;
2865 sp [-1].type = VAL_I32;
2868 CASE (CEE_CONV_U2) {
2870 switch (sp [-1].type) {
2872 sp [-1].data.i = (guint16)sp [-1].data.f;
2875 sp [-1].data.i = (guint16)sp [-1].data.l;
2880 sp [-1].data.i = (guint16)sp [-1].data.i;
2883 sp [-1].data.i = (guint16)sp [-1].data.nati;
2886 sp [-1].type = VAL_I32;
2889 CASE (CEE_CONV_I2) {
2891 switch (sp [-1].type) {
2893 sp [-1].data.i = (gint16)sp [-1].data.f;
2896 sp [-1].data.i = (gint16)sp [-1].data.l;
2901 sp [-1].data.i = (gint16)sp [-1].data.i;
2904 sp [-1].data.i = (gint16)sp [-1].data.nati;
2907 sp [-1].type = VAL_I32;
2910 CASE (CEE_CONV_U4) /* Fall through */
2911 #if SIZEOF_VOID_P == 4
2912 CASE (CEE_CONV_I) /* Fall through */
2913 CASE (CEE_CONV_U) /* Fall through */
2915 CASE (CEE_CONV_I4) {
2917 switch (sp [-1].type) {
2919 sp [-1].data.i = (gint32)sp [-1].data.f;
2922 sp [-1].data.i = (gint32)sp [-1].data.l;
2929 sp [-1].data.i = (gint32)sp [-1].data.p;
2932 sp [-1].type = VAL_I32;
2935 #if SIZEOF_VOID_P == 8
2936 CASE (CEE_CONV_I) /* Fall through */
2940 switch (sp [-1].type) {
2942 sp [-1].data.l = (gint64)sp [-1].data.f;
2949 sp [-1].data.l = (gint64)sp [-1].data.i;
2952 sp [-1].data.l = (gint64)sp [-1].data.nati;
2955 sp [-1].type = ip[-1] == CEE_CONV_I ? VAL_NATI : VAL_I64;
2957 CASE (CEE_CONV_R4) {
2959 switch (sp [-1].type) {
2961 sp [-1].data.f = (float)sp [-1].data.f;
2964 sp [-1].data.f = (float)sp [-1].data.l;
2969 sp [-1].data.f = (float)sp [-1].data.i;
2972 sp [-1].data.f = (float)sp [-1].data.nati;
2975 sp [-1].type = VAL_DOUBLE;
2978 CASE (CEE_CONV_R8) {
2980 switch (sp [-1].type) {
2982 sp [-1].data.f = (double)sp [-1].data.f;
2985 sp [-1].data.f = (double)sp [-1].data.l;
2990 sp [-1].data.f = (double)sp [-1].data.i;
2993 sp [-1].data.f = (double)sp [-1].data.nati;
2996 sp [-1].type = VAL_DOUBLE;
2999 #if SIZEOF_VOID_P == 8
3000 CASE (CEE_CONV_U) /* Fall through */
3005 switch (sp [-1].type){
3007 sp [-1].data.l = (guint64)sp [-1].data.f;
3014 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3017 sp [-1].data.l = (guint64) sp [-1].data.nati;
3020 sp [-1].type = ip[-1] == CEE_CONV_U ? VAL_NATI : VAL_I64;
3025 vtklass = mono_class_get (image, read32 (ip));
3028 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
3037 token = read32 (ip);
3040 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3041 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3043 c = mono_class_get (image, token);
3045 addr = sp [-1].data.vt;
3046 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
3047 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
3055 str_index = mono_metadata_token_index (read32 (ip));
3058 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
3059 o = (MonoObject *)mono_string_new_wrapper(
3060 mono_method_get_wrapper_data (frame->method, str_index));
3063 o = (MonoObject*)mono_ldstr (domain, image, str_index);
3072 MonoClass *newobj_class;
3073 MonoMethodSignature *csig;
3074 stackval valuetype_this;
3075 stackval *endsp = sp;
3082 token = read32 (ip);
3085 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3086 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
3088 child_frame.method = mono_get_method (image, token, NULL);
3089 if (!child_frame.method)
3090 THROW_EX (mono_get_exception_missing_method (), ip -5);
3092 csig = child_frame.method->signature;
3093 newobj_class = child_frame.method->klass;
3094 /*if (profiling_classes) {
3095 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3097 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3101 if (newobj_class->parent == mono_defaults.array_class) {
3102 sp -= csig->param_count;
3103 o = ves_array_create (domain, newobj_class, csig, sp);
3104 goto array_constructed;
3108 * First arg is the object.
3110 if (newobj_class->valuetype) {
3112 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
3113 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
3114 zero = valuetype_this.data.vt;
3115 child_frame.obj = valuetype_this.data.vt;
3117 memset (&valuetype_this, 0, sizeof (stackval));
3118 zero = &valuetype_this;
3119 child_frame.obj = &valuetype_this;
3121 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
3123 if (newobj_class != mono_defaults.string_class) {
3124 o = mono_object_new (domain, newobj_class);
3125 child_frame.obj = o;
3127 child_frame.retval = &retval;
3131 if (csig->param_count) {
3132 sp -= csig->param_count;
3133 child_frame.stack_args = sp;
3135 child_frame.stack_args = NULL;
3138 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3140 child_frame.ip = NULL;
3141 child_frame.ex = NULL;
3142 child_frame.ex_handler = NULL;
3144 ves_exec_method_with_context (&child_frame, context);
3146 context->current_frame = frame;
3148 while (endsp > sp) {
3153 if (child_frame.ex) {
3155 * An exception occurred, need to run finally, fault and catch handlers..
3157 frame->ex = child_frame.ex;
3158 goto handle_finally;
3161 * a constructor returns void, but we need to return the object we created
3164 if (newobj_class->valuetype && !newobj_class->enumtype) {
3165 *sp = valuetype_this;
3166 } else if (newobj_class == mono_defaults.string_class) {
3175 CASE (CEE_CASTCLASS) /* Fall through */
3180 int do_isinst = *ip == CEE_ISINST;
3183 token = read32 (ip);
3184 c = mono_class_get (image, token);
3186 g_assert (sp [-1].type == VAL_OBJ);
3188 if ((o = sp [-1].data.p)) {
3189 if (!mono_object_isinst (o, c)) {
3191 sp [-1].data.p = NULL;
3193 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3199 CASE (CEE_CONV_R_UN)
3201 switch (sp [-1].type) {
3205 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3210 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3213 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
3216 sp [-1].type = VAL_DOUBLE;
3219 CASE (CEE_UNUSED1) ves_abort(); BREAK;
3226 token = read32 (ip);
3228 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3229 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3231 c = mono_class_get (image, token);
3235 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3237 if (!(mono_object_isinst (o, c) ||
3238 ((o->vtable->klass->rank == 0) &&
3239 (o->vtable->klass->element_class == c->element_class))))
3240 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3242 sp [-1].type = VAL_MP;
3243 sp [-1].data.p = (char *)o + sizeof (MonoObject);
3250 frame->ex_handler = NULL;
3252 sp->data.p = mono_get_exception_null_reference ();
3253 THROW_EX ((MonoException *)sp->data.p, ip);
3255 CASE (CEE_LDFLDA) /* Fall through */
3258 MonoClassField *field;
3260 int load_addr = *ip == CEE_LDFLDA;
3263 if (!sp [-1].data.p)
3264 THROW_EX (mono_get_exception_null_reference (), ip);
3267 token = read32 (ip);
3268 field = rtd->field_info[token].field;
3271 if (sp [-1].type == VAL_OBJ) {
3272 obj = sp [-1].data.p;
3273 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3274 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3275 addr = mono_load_remote_field (obj, klass, field, NULL);
3277 addr = (char*)obj + field->offset;
3280 obj = sp [-1].data.vt;
3281 addr = (char*)obj + field->offset - sizeof (MonoObject);
3285 sp [-1].type = VAL_MP;
3286 sp [-1].data.p = addr;
3288 vt_alloc (field->type, &sp [-1], FALSE);
3289 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3295 MonoClassField *field;
3296 guint32 token, offset;
3301 THROW_EX (mono_get_exception_null_reference (), ip);
3304 token = read32 (ip);
3305 field = rtd->field_info[token].field;
3308 if (sp [0].type == VAL_OBJ) {
3309 obj = sp [0].data.p;
3311 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3312 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3313 mono_store_remote_field (obj, klass, field, &sp [1].data);
3315 offset = field->offset;
3316 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3320 obj = sp [0].data.vt;
3321 offset = field->offset - sizeof (MonoObject);
3322 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3328 CASE (CEE_LDSFLD) /* Fall through */
3329 CASE (CEE_LDSFLDA) {
3331 MonoClassField *field;
3333 int load_addr = *ip == CEE_LDSFLDA;
3337 token = read32 (ip);
3338 field = rtd->field_info[token].field;
3341 vt = mono_class_vtable (domain, field->parent);
3342 if (!vt->initialized)
3343 mono_runtime_class_init (vt);
3345 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3346 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3348 addr = (char*)(vt->data) + field->offset;
3354 vt_alloc (field->type, sp, FALSE);
3355 stackval_from_data (field->type, sp, addr, FALSE);
3362 MonoClassField *field;
3367 token = read32 (ip);
3368 field = rtd->field_info[token].field;
3372 vt = mono_class_vtable (domain, field->parent);
3373 if (!vt->initialized)
3374 mono_runtime_class_init (vt);
3376 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3377 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3379 addr = (char*)(vt->data) + field->offset;
3381 stackval_to_data (field->type, sp, addr, FALSE);
3388 vtklass = mono_class_get (image, read32 (ip));
3393 * LAMESPEC: According to the spec, the stack should contain a
3394 * pointer to a value type. In reality, it can contain anything.
3396 if (sp [1].type == VAL_VALUET)
3397 memcpy (sp [0].data.p, sp [1].data.vt, mono_class_value_size (vtklass, NULL));
3399 memcpy (sp [0].data.p, &sp [1].data, mono_class_value_size (vtklass, NULL));
3402 #if SIZEOF_VOID_P == 8
3403 CASE (CEE_CONV_OVF_I_UN)
3405 CASE (CEE_CONV_OVF_I8_UN) {
3406 switch (sp [-1].type) {
3408 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
3409 THROW_EX (mono_get_exception_overflow (), ip);
3410 sp [-1].data.l = (guint64)sp [-1].data.f;
3417 /* Can't overflow */
3418 sp [-1].data.l = (guint64)sp [-1].data.i;
3421 sp [-1].data.l = (guint64)sp [-1].data.nati;
3424 sp [-1].type = VAL_I64;
3428 #if SIZEOF_VOID_P == 8
3429 CASE (CEE_CONV_OVF_U_UN)
3431 CASE (CEE_CONV_OVF_U8_UN) {
3432 switch (sp [-1].type) {
3434 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
3435 THROW_EX (mono_get_exception_overflow (), ip);
3436 sp [-1].data.l = (guint64)sp [-1].data.f;
3444 /* Can't overflow */
3445 sp [-1].data.l = (guint64)sp [-1].data.i;
3448 /* Can't overflow */
3449 sp [-1].data.l = (guint64)sp [-1].data.nati;
3452 sp [-1].type = VAL_I64;
3456 #if SIZEOF_VOID_P == 4
3457 CASE (CEE_CONV_OVF_I_UN)
3458 CASE (CEE_CONV_OVF_U_UN)
3460 CASE (CEE_CONV_OVF_I1_UN)
3461 CASE (CEE_CONV_OVF_I2_UN)
3462 CASE (CEE_CONV_OVF_I4_UN)
3463 CASE (CEE_CONV_OVF_U1_UN)
3464 CASE (CEE_CONV_OVF_U2_UN)
3465 CASE (CEE_CONV_OVF_U4_UN) {
3467 switch (sp [-1].type) {
3469 if (sp [-1].data.f <= -1.0)
3470 THROW_EX (mono_get_exception_overflow (), ip);
3471 value = (guint64)sp [-1].data.f;
3474 value = (guint64)sp [-1].data.l;
3479 value = (guint64)sp [-1].data.i;
3482 value = (guint64)sp [-1].data.nati;
3486 case CEE_CONV_OVF_I1_UN:
3488 THROW_EX (mono_get_exception_overflow (), ip);
3489 sp [-1].data.i = value;
3490 sp [-1].type = VAL_I32;
3492 case CEE_CONV_OVF_I2_UN:
3494 THROW_EX (mono_get_exception_overflow (), ip);
3495 sp [-1].data.i = value;
3496 sp [-1].type = VAL_I32;
3498 #if SIZEOF_VOID_P == 4
3499 case CEE_CONV_OVF_I_UN: /* Fall through */
3501 case CEE_CONV_OVF_I4_UN:
3502 if (value > MYGUINT32_MAX)
3503 THROW_EX (mono_get_exception_overflow (), ip);
3504 sp [-1].data.i = value;
3505 sp [-1].type = VAL_I32;
3507 case CEE_CONV_OVF_U1_UN:
3509 THROW_EX (mono_get_exception_overflow (), ip);
3510 sp [-1].data.i = value;
3511 sp [-1].type = VAL_I32;
3513 case CEE_CONV_OVF_U2_UN:
3515 THROW_EX (mono_get_exception_overflow (), ip);
3516 sp [-1].data.i = value;
3517 sp [-1].type = VAL_I32;
3519 #if SIZEOF_VOID_P == 4
3520 case CEE_CONV_OVF_U_UN: /* Fall through */
3522 case CEE_CONV_OVF_U4_UN:
3523 if (value > 4294967295U)
3524 THROW_EX (mono_get_exception_overflow (), ip);
3525 sp [-1].data.i = value;
3526 sp [-1].type = VAL_I32;
3529 g_assert_not_reached ();
3539 token = read32 (ip);
3541 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3542 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3544 class = mono_class_get (image, token);
3545 g_assert (class != NULL);
3547 sp [-1].type = VAL_OBJ;
3548 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3549 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3551 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3552 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3554 /* need to vt_free (sp); */
3566 token = read32 (ip);
3568 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3569 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3571 class = mono_class_get (image, token);
3573 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3576 sp [-1].type = VAL_OBJ;
3578 /*if (profiling_classes) {
3579 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3581 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3591 g_assert (sp [-1].type == VAL_OBJ);
3595 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3597 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3599 sp [-1].type = VAL_I32;
3600 sp [-1].data.i = mono_array_length (o);
3604 CASE (CEE_LDELEMA) {
3606 guint32 esize, token;
3610 token = read32 (ip);
3614 g_assert (sp [0].type == VAL_OBJ);
3617 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3619 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3620 if (aindex >= mono_array_length (o))
3621 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3623 /* check the array element corresponds to token */
3624 esize = mono_array_element_size (o->obj.vtable->klass);
3627 sp->data.p = mono_array_addr_with_size (o, esize, aindex);
3632 CASE (CEE_LDELEM_I1) /* fall through */
3633 CASE (CEE_LDELEM_U1) /* fall through */
3634 CASE (CEE_LDELEM_I2) /* fall through */
3635 CASE (CEE_LDELEM_U2) /* fall through */
3636 CASE (CEE_LDELEM_I4) /* fall through */
3637 CASE (CEE_LDELEM_U4) /* fall through */
3638 CASE (CEE_LDELEM_I8) /* fall through */
3639 CASE (CEE_LDELEM_I) /* fall through */
3640 CASE (CEE_LDELEM_R4) /* fall through */
3641 CASE (CEE_LDELEM_R8) /* fall through */
3642 CASE (CEE_LDELEM_REF) {
3648 g_assert (sp [0].type == VAL_OBJ);
3651 THROW_EX (mono_get_exception_null_reference (), ip);
3653 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3655 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3656 if (aindex >= mono_array_length (o))
3657 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3660 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3664 sp [0].data.i = mono_array_get (o, gint8, aindex);
3665 sp [0].type = VAL_I32;
3668 sp [0].data.i = mono_array_get (o, guint8, aindex);
3669 sp [0].type = VAL_I32;
3672 sp [0].data.i = mono_array_get (o, gint16, aindex);
3673 sp [0].type = VAL_I32;
3676 sp [0].data.i = mono_array_get (o, guint16, aindex);
3677 sp [0].type = VAL_I32;
3680 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3681 sp [0].type = VAL_NATI;
3684 sp [0].data.i = mono_array_get (o, gint32, aindex);
3685 sp [0].type = VAL_I32;
3688 sp [0].data.i = mono_array_get (o, guint32, aindex);
3689 sp [0].type = VAL_I32;
3692 sp [0].data.l = mono_array_get (o, guint64, aindex);
3693 sp [0].type = VAL_I64;
3696 sp [0].data.f = mono_array_get (o, float, aindex);
3697 sp [0].type = VAL_DOUBLE;
3700 sp [0].data.f = mono_array_get (o, double, aindex);
3701 sp [0].type = VAL_DOUBLE;
3703 case CEE_LDELEM_REF:
3704 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3705 sp [0].type = VAL_OBJ;
3715 CASE (CEE_STELEM_I) /* fall through */
3716 CASE (CEE_STELEM_I1) /* fall through */
3717 CASE (CEE_STELEM_I2) /* fall through */
3718 CASE (CEE_STELEM_I4) /* fall through */
3719 CASE (CEE_STELEM_I8) /* fall through */
3720 CASE (CEE_STELEM_R4) /* fall through */
3721 CASE (CEE_STELEM_R8) /* fall through */
3722 CASE (CEE_STELEM_REF) {
3729 g_assert (sp [0].type == VAL_OBJ);
3732 THROW_EX (mono_get_exception_null_reference (), ip);
3734 ac = o->obj.vtable->klass;
3735 g_assert (MONO_CLASS_IS_ARRAY (ac));
3737 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3738 if (aindex >= mono_array_length (o))
3739 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3742 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3746 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3749 mono_array_set (o, gint8, aindex, sp [2].data.i);
3752 mono_array_set (o, gint16, aindex, sp [2].data.i);
3755 mono_array_set (o, gint32, aindex, sp [2].data.i);
3758 mono_array_set (o, gint64, aindex, sp [2].data.l);
3761 mono_array_set (o, float, aindex, sp [2].data.f);
3764 mono_array_set (o, double, aindex, sp [2].data.f);
3766 case CEE_STELEM_REF:
3767 g_assert (sp [2].type == VAL_OBJ);
3768 if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
3769 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3770 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3781 CASE (CEE_UNBOX_ANY)
3794 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3796 #if SIZEOF_VOID_P == 4
3797 CASE (CEE_CONV_OVF_I)
3798 CASE (CEE_CONV_OVF_U)
3800 CASE (CEE_CONV_OVF_I1)
3801 CASE (CEE_CONV_OVF_I2)
3802 CASE (CEE_CONV_OVF_I4)
3803 CASE (CEE_CONV_OVF_U1)
3804 CASE (CEE_CONV_OVF_U2)
3805 CASE (CEE_CONV_OVF_U4) {
3807 switch (sp [-1].type) {
3809 value = (gint64)sp [-1].data.f;
3812 value = (gint64)sp [-1].data.l;
3817 value = (gint64)sp [-1].data.i;
3820 value = (gint64)sp [-1].data.nati;
3824 case CEE_CONV_OVF_I1:
3825 if (value < -128 || value > 127)
3826 THROW_EX (mono_get_exception_overflow (), ip);
3827 sp [-1].data.i = value;
3828 sp [-1].type = VAL_I32;
3830 case CEE_CONV_OVF_I2:
3831 if (value < -32768 || value > 32767)
3832 THROW_EX (mono_get_exception_overflow (), ip);
3833 sp [-1].data.i = value;
3834 sp [-1].type = VAL_I32;
3836 #if SIZEOF_VOID_P == 4
3837 case CEE_CONV_OVF_I: /* Fall through */
3839 case CEE_CONV_OVF_I4:
3840 if (value < MYGINT32_MIN || value > MYGINT32_MAX)
3841 THROW_EX (mono_get_exception_overflow (), ip);
3842 sp [-1].data.i = value;
3843 sp [-1].type = VAL_I32;
3845 case CEE_CONV_OVF_U1:
3846 if (value < 0 || value > 255)
3847 THROW_EX (mono_get_exception_overflow (), ip);
3848 sp [-1].data.i = value;
3849 sp [-1].type = VAL_I32;
3851 case CEE_CONV_OVF_U2:
3852 if (value < 0 || value > 65535)
3853 THROW_EX (mono_get_exception_overflow (), ip);
3854 sp [-1].data.i = value;
3855 sp [-1].type = VAL_I32;
3857 #if SIZEOF_VOID_P == 4
3858 case CEE_CONV_OVF_U: /* Fall through */
3860 case CEE_CONV_OVF_U4:
3861 if (value < 0 || value > MYGUINT32_MAX)
3862 THROW_EX (mono_get_exception_overflow (), ip);
3863 sp [-1].data.i = value;
3864 sp [-1].type = VAL_I32;
3867 g_assert_not_reached ();
3873 #if SIZEOF_VOID_P == 8
3874 CASE (CEE_CONV_OVF_I)
3876 CASE (CEE_CONV_OVF_I8)
3877 /* FIXME: handle other cases */
3878 if (sp [-1].type == VAL_I32) {
3879 sp [-1].data.l = (guint64)sp [-1].data.i;
3880 sp [-1].type = VAL_I64;
3881 } else if(sp [-1].type == VAL_I64) {
3882 /* defined as NOP */
3889 #if SIZEOF_VOID_P == 8
3890 CASE (CEE_CONV_OVF_U)
3892 CASE (CEE_CONV_OVF_U8)
3893 /* FIXME: handle other cases */
3894 if (sp [-1].type == VAL_I32) {
3895 sp [-1].data.l = (guint64) sp [-1].data.i;
3896 sp [-1].type = VAL_I64;
3897 } else if(sp [-1].type == VAL_I64) {
3898 /* defined as NOP */
3910 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3911 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3913 if (!finite(sp [-1].data.f))
3914 THROW_EX (mono_get_exception_arithmetic (), ip);
3917 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3918 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3919 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3928 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3929 CASE (CEE_LDTOKEN) {
3931 MonoClass *handle_class;
3933 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3935 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3936 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3942 /* FIXME: check overflow */
3943 if (sp->type == VAL_I32) {
3944 if (sp [-1].type == VAL_I32) {
3945 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3946 THROW_EX (mono_get_exception_overflow (), ip);
3947 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)sp [0].data.i;
3949 if (CHECK_ADD_OVERFLOW_NAT (sp [-1].data.nati, (mono_i)sp [0].data.i))
3950 THROW_EX (mono_get_exception_overflow (), ip);
3951 sp [-1].data.nati = sp [-1].data.nati + (mono_i)sp [0].data.i;
3953 } else if (sp->type == VAL_I64) {
3954 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3955 THROW_EX (mono_get_exception_overflow (), ip);
3956 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3957 } else if (sp->type == VAL_DOUBLE)
3958 sp [-1].data.f += sp [0].data.f;
3960 char *p = sp [-1].data.p;
3961 p += GET_NATI (sp [0]);
3966 CASE (CEE_ADD_OVF_UN)
3968 /* FIXME: check overflow, make unsigned */
3969 if (sp->type == VAL_I32) {
3970 if (sp [-1].type == VAL_I32) {
3971 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
3972 THROW_EX (mono_get_exception_overflow (), ip);
3973 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)sp [0].data.i;
3975 if (CHECK_ADD_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
3976 THROW_EX (mono_get_exception_overflow (), ip);
3977 sp [-1].data.nati = (mono_u)sp [-1].data.nati + (mono_u)sp [0].data.i;
3979 } else if (sp->type == VAL_I64) {
3980 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3981 THROW_EX (mono_get_exception_overflow (), ip);
3982 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3983 } else if (sp->type == VAL_DOUBLE)
3984 sp [-1].data.f += sp [0].data.f;
3986 char *p = sp [-1].data.p;
3987 p += GET_NATI (sp [0]);
3994 /* FIXME: check overflow */
3995 if (sp->type == VAL_I32) {
3996 if (sp [-1].type == VAL_NATI) {
3997 if (CHECK_MUL_OVERFLOW_NAT (sp [-1].data.nati, sp [0].data.i))
3998 THROW_EX (mono_get_exception_overflow (), ip);
3999 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
4000 sp [-1].type = VAL_NATI;
4002 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4003 THROW_EX (mono_get_exception_overflow (), ip);
4004 sp [-1].data.i *= sp [0].data.i;
4007 else if (sp->type == VAL_I64) {
4008 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4009 THROW_EX (mono_get_exception_overflow (), ip);
4010 sp [-1].data.l *= sp [0].data.l;
4012 else if (sp->type == VAL_DOUBLE)
4013 sp [-1].data.f *= sp [0].data.f;
4018 CASE (CEE_MUL_OVF_UN)
4020 /* FIXME: check overflow, make unsigned */
4021 if (sp->type == VAL_I32) {
4022 if (sp [-1].type == VAL_NATI) {
4023 if (CHECK_MUL_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
4024 THROW_EX (mono_get_exception_overflow (), ip);
4025 sp [-1].data.nati = (mono_u)sp [-1].data.nati * (mono_u)sp [0].data.i;
4026 sp [-1].type = VAL_NATI;
4028 if (CHECK_MUL_OVERFLOW_UN ((guint32)sp [-1].data.i, (guint32)sp [0].data.i))
4029 THROW_EX (mono_get_exception_overflow (), ip);
4030 sp [-1].data.i *= sp [0].data.i;
4033 else if (sp->type == VAL_I64) {
4034 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4035 THROW_EX (mono_get_exception_overflow (), ip);
4036 sp [-1].data.l *= sp [0].data.l;
4038 else if (sp->type == VAL_DOUBLE)
4039 sp [-1].data.f *= sp [0].data.f;
4046 /* FIXME: handle undeflow/unsigned */
4047 /* should probably consider the pointers as unsigned */
4048 if (sp->type == VAL_I32) {
4049 if (sp [-1].type == VAL_I32) {
4050 if (CHECK_SUB_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4051 THROW_EX (mono_get_exception_overflow (), ip);
4052 sp [-1].data.i -= sp [0].data.i;
4054 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4055 sp [-1].type = VAL_NATI;
4058 else if (sp->type == VAL_I64) {
4059 if (CHECK_SUB_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4060 THROW_EX (mono_get_exception_overflow (), ip);
4061 sp [-1].data.l -= sp [0].data.l;
4063 else if (sp->type == VAL_DOUBLE)
4064 sp [-1].data.f -= sp [0].data.f;
4066 if (sp [-1].type == VAL_I32) {
4067 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4068 sp [-1].type = sp [0].type;
4070 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4074 CASE (CEE_SUB_OVF_UN)
4076 /* FIXME: handle undeflow/unsigned */
4077 /* should probably consider the pointers as unsigned */
4078 if (sp->type == VAL_I32) {
4079 if (sp [-1].type == VAL_I32) {
4080 if (CHECK_SUB_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
4081 THROW_EX (mono_get_exception_overflow (), ip);
4082 sp [-1].data.i -= sp [0].data.i;
4084 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4085 sp [-1].type = VAL_NATI;
4088 else if (sp->type == VAL_I64) {
4089 if (CHECK_SUB_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4090 THROW_EX (mono_get_exception_overflow (), ip);
4091 sp [-1].data.l -= sp [0].data.l;
4093 else if (sp->type == VAL_DOUBLE)
4094 sp [-1].data.f -= sp [0].data.f;
4096 if (sp [-1].type == VAL_I32) {
4097 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4098 sp [-1].type = sp [0].type;
4100 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4104 CASE (CEE_ENDFINALLY)
4106 ip = finally_ips->data;
4107 finally_ips = g_slist_remove (finally_ips, ip);
4114 CASE (CEE_LEAVE) /* Fall through */
4116 while (sp > frame->stack) {
4121 if (*ip == CEE_LEAVE_S) {
4123 ip += (signed char) *ip;
4127 ip += (gint32) read32 (ip);
4131 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - header->code)) {
4132 frame->ex_handler = NULL;
4135 goto handle_finally;
4140 case CEE_MONO_FUNC1: {
4141 MonoMarshalConv conv;
4150 sp->type = VAL_NATI;
4153 case MONO_MARSHAL_CONV_STR_LPWSTR:
4154 sp->data.p = mono_string_to_utf16 (sp->data.p);
4156 case MONO_MARSHAL_CONV_LPSTR_STR:
4157 sp->data.p = mono_string_new_wrapper (sp->data.p);
4159 case MONO_MARSHAL_CONV_STR_LPTSTR:
4160 case MONO_MARSHAL_CONV_STR_LPSTR:
4161 sp->data.p = mono_string_to_utf8 (sp->data.p);
4163 case MONO_MARSHAL_CONV_STR_BSTR:
4164 sp->data.p = mono_string_to_bstr (sp->data.p);
4166 case MONO_MARSHAL_CONV_STR_TBSTR:
4167 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4168 sp->data.p = mono_string_to_ansibstr (sp->data.p);
4170 case MONO_MARSHAL_CONV_SB_LPSTR:
4171 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
4173 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4174 sp->data.p = mono_array_to_savearray (sp->data.p);
4176 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4177 sp->data.p = mono_array_to_lparray (sp->data.p);
4179 case MONO_MARSHAL_CONV_DEL_FTN:
4180 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
4182 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4183 sp->data.p = mono_marshal_string_array (sp->data.p);
4185 case MONO_MARSHAL_CONV_LPWSTR_STR:
4186 sp->data.p = mono_string_from_utf16 (sp->data.p);
4189 fprintf(stderr, "MONO_FUNC1 %d", conv);
4190 g_assert_not_reached ();
4195 case CEE_MONO_PROC2: {
4196 MonoMarshalConv conv;
4204 case MONO_MARSHAL_CONV_LPSTR_SB:
4205 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
4207 case MONO_MARSHAL_FREE_ARRAY:
4208 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
4211 g_assert_not_reached ();
4215 case CEE_MONO_PROC3: {
4216 MonoMarshalConv conv;
4224 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4225 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4227 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4228 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4231 g_assert_not_reached ();
4235 case CEE_MONO_VTADDR: {
4238 sp [-1].type = VAL_MP;
4242 case CEE_MONO_LDPTR: {
4246 token = read32 (ip);
4249 sp->type = VAL_NATI;
4250 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
4254 case CEE_MONO_FREE: {
4258 g_free (sp->data.p);
4261 case CEE_MONO_OBJADDR: {
4268 case CEE_MONO_NEWOBJ: {
4273 token = read32 (ip);
4276 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4277 sp->data.p = mono_object_new (domain, class);
4281 case CEE_MONO_RETOBJ: {
4286 token = read32 (ip);
4291 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4293 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
4295 if (sp > frame->stack)
4296 g_warning ("more values on stack: %d", sp-frame->stack);
4299 case CEE_MONO_LDNATIVEOBJ: {
4304 token = read32 (ip);
4307 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4308 g_assert(class->valuetype);
4310 sp [-1].type = VAL_MP;
4315 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
4346 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
4348 * Note: Exceptions thrown when executing a prefixed opcode need
4349 * to take into account the number of prefix bytes (usually the
4350 * throw point is just (ip - n_prefix_bytes).
4355 case CEE_ARGLIST: ves_abort(); break;
4361 if (sp->type == VAL_I32)
4362 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
4363 else if (sp->type == VAL_I64)
4364 result = sp [0].data.l == sp [1].data.l;
4365 else if (sp->type == VAL_DOUBLE) {
4366 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4369 result = sp [0].data.f == sp [1].data.f;
4371 result = sp [0].data.nati == GET_NATI (sp [1]);
4373 sp->data.i = result;
4383 if (sp->type == VAL_I32)
4384 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
4385 else if (sp->type == VAL_I64)
4386 result = sp [0].data.l > sp [1].data.l;
4387 else if (sp->type == VAL_DOUBLE) {
4388 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4391 result = sp [0].data.f > sp [1].data.f;
4393 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
4395 sp->data.i = result;
4405 if (sp->type == VAL_I32)
4406 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
4407 else if (sp->type == VAL_I64)
4408 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
4409 else if (sp->type == VAL_DOUBLE)
4410 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4411 sp[0].data.f > sp[1].data.f;
4413 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
4415 sp->data.i = result;
4425 if (sp->type == VAL_I32)
4426 result = (mono_i)sp [0].data.i < (mono_i)GET_NATI (sp [1]);
4427 else if (sp->type == VAL_I64)
4428 result = sp [0].data.l < sp [1].data.l;
4429 else if (sp->type == VAL_DOUBLE) {
4430 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4433 result = sp [0].data.f < sp [1].data.f;
4435 result = (mono_i)sp [0].data.nati < (mono_i)GET_NATI (sp [1]);
4437 sp->data.i = result;
4447 if (sp->type == VAL_I32)
4448 result = (mono_u)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
4449 else if (sp->type == VAL_I64)
4450 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
4451 else if (sp->type == VAL_DOUBLE)
4452 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4453 sp[0].data.f < sp[1].data.f;
4455 result = (mono_u)sp [0].data.nati < (mono_u)GET_NATI (sp [1]);
4457 sp->data.i = result;
4463 case CEE_LDVIRTFTN: {
4464 int virtual = *ip == CEE_LDVIRTFTN;
4468 token = read32 (ip);
4471 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
4472 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
4474 m = mono_get_method (image, token, NULL);
4477 THROW_EX (mono_get_exception_missing_method (), ip - 5);
4481 THROW_EX (mono_get_exception_null_reference (), ip - 5);
4483 m = get_virtual_method (domain, m, sp);
4487 * This prevents infinite cycles since the wrapper contains
4490 if (frame->method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
4491 if (m && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4492 m = mono_marshal_get_synchronized_wrapper (m);
4494 sp->type = VAL_NATI;
4495 sp->data.p = mono_create_method_pointer (m);
4499 case CEE_UNUSED56: ves_abort(); break;
4503 arg_pos = read16 (ip);
4505 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
4506 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4515 sp->data.vt = ARG_POS (anum);
4523 arg_pos = read16 (ip);
4526 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4533 loc_pos = read16 (ip);
4535 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4536 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4545 loc_pos = read16 (ip);
4547 t = LOCAL_TYPE (header, loc_pos);
4548 sp->data.vt = LOCAL_POS (loc_pos);
4558 loc_pos = read16 (ip);
4561 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4567 if (sp != frame->stack)
4568 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4570 sp->data.p = alloca (sp->data.i);
4574 case CEE_UNUSED57: ves_abort(); break;
4575 case CEE_ENDFILTER: ves_abort(); break;
4576 case CEE_UNALIGNED_:
4578 unaligned_address = 1;
4582 volatile_address = 1;
4593 token = read32 (ip);
4596 class = mono_class_get (image, token);
4599 g_assert (sp->type == VAL_TP || sp->type == VAL_MP);
4600 memset (sp->data.vt, 0, mono_class_value_size (class, NULL));
4603 case CEE_CONSTRAINED_: {
4605 /* FIXME: implement */
4607 token = read32 (ip);
4613 if (!sp [0].data.p || !sp [1].data.p)
4614 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4616 /* FIXME: value and size may be int64... */
4617 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4622 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4624 /* FIXME: value and size may be int64... */
4625 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4628 /* FIXME: implement */
4633 * need to clarify what this should actually do:
4634 * start the search from the last found handler in
4635 * this method or continue in the caller or what.
4636 * Also, do we need to run finally/fault handlers after a retrow?
4637 * Well, this implementation will follow the usual search
4638 * for an handler, considering the current ip as throw spot.
4639 * We need to NULL frame->ex_handler for the later code to
4640 * actually run the new found handler.
4642 frame->ex_handler = NULL;
4643 THROW_EX (frame->ex, ip - 1);
4645 case CEE_UNUSED: ves_abort(); break;
4650 token = read32 (ip);
4652 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4653 MonoType *type = mono_type_create_from_typespec (image, token);
4654 sp->data.i = mono_type_size (type, &align);
4656 MonoClass *szclass = mono_class_get (image, token);
4657 mono_class_init (szclass);
4658 if (!szclass->valuetype)
4659 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4660 sp->data.i = mono_class_value_size (szclass, &align);
4666 case CEE_REFANYTYPE: ves_abort(); break;
4668 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4675 g_assert_not_reached ();
4677 * Exception handling code.
4678 * The exception object is stored in frame->ex.
4685 MonoInvocation *inv;
4686 MonoMethodHeader *hd;
4687 MonoExceptionClause *clause;
4693 g_print ("* Handling exception '%s' at IL_%04x\n", frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, frame->ip - header->code);
4695 if (die_on_exception)
4698 if (frame->ex == quit_exception)
4699 goto handle_finally;
4701 for (inv = frame; inv; inv = inv->parent) {
4702 if (inv->method == NULL)
4704 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4706 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4708 hd = ((MonoMethodNormal*)inv->method)->header;
4709 ip_offset = inv->ip - hd->code;
4710 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4711 for (i = 0; i < hd->num_clauses; ++i) {
4712 clause = &hd->clauses [i];
4713 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4714 if (!clause->flags) {
4715 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4717 * OK, we found an handler, now we need to execute the finally
4718 * and fault blocks before branching to the handler code.
4720 inv->ex_handler = clause;
4723 g_print ("* Found handler at '%s'\n", inv->method->name);
4725 goto handle_finally;
4728 /* FIXME: handle filter clauses */
4735 * If we get here, no handler was found: print a stack trace.
4737 for (inv = frame; inv; inv = inv->parent) {
4738 if (inv->invoke_trap)
4739 goto handle_finally;
4742 ex_obj = (MonoObject*)frame->ex;
4743 mono_unhandled_exception (ex_obj);
4750 MonoExceptionClause *clause;
4751 GSList *old_list = finally_ips;
4755 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - header->code);
4757 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4758 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4761 ip_offset = frame->ip - header->code;
4763 if (endfinally_ip != NULL)
4764 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4765 for (i = 0; i < header->num_clauses; ++i)
4766 if (frame->ex_handler == &header->clauses [i])
4770 clause = &header->clauses [i];
4771 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code)))) {
4772 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4773 ip = header->code + clause->handler_offset;
4774 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4777 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4783 endfinally_ip = NULL;
4785 if (old_list != finally_ips && finally_ips) {
4786 ip = finally_ips->data;
4787 finally_ips = g_slist_remove (finally_ips, ip);
4788 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4793 * If an exception is set, we need to execute the fault handler, too,
4794 * otherwise, we continue normally.
4804 MonoExceptionClause *clause;
4808 g_print ("* Handle fault\n");
4810 ip_offset = frame->ip - header->code;
4811 for (i = 0; i < header->num_clauses; ++i) {
4812 clause = &header->clauses [i];
4813 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4814 ip = header->code + clause->handler_offset;
4817 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4823 * If the handler for the exception was found in this method, we jump
4824 * to it right away, otherwise we return and let the caller run
4825 * the finally, fault and catch blocks.
4826 * This same code should be present in the endfault opcode, but it
4827 * is corrently not assigned in the ECMA specs: LAMESPEC.
4829 if (frame->ex_handler) {
4832 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4834 ip = header->code + frame->ex_handler->handler_offset;
4837 sp->data.p = frame->ex;
4848 ves_exec_method (MonoInvocation *frame)
4850 ThreadContext *context = TlsGetValue (thread_context_id);
4851 ThreadContext context_struct;
4852 if (context == NULL) {
4853 context = &context_struct;
4854 context_struct.base_frame = frame;
4855 context_struct.current_frame = NULL;
4856 context_struct.current_env = NULL;
4857 context_struct.search_for_handler = 0;
4858 TlsSetValue (thread_context_id, context);
4861 frame->parent = context->current_frame;
4862 ves_exec_method_with_context(frame, context);
4864 if (context->current_env) {
4865 context->env_frame->ex = frame->ex;
4866 longjmp (*context->current_env, 1);
4869 mono_unhandled_exception ((MonoObject*)frame->ex);
4871 if (context->base_frame == frame)
4872 TlsSetValue (thread_context_id, NULL);
4874 context->current_frame = frame->parent;
4878 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4880 MonoImage *image = assembly->image;
4881 MonoCLIImageInfo *iinfo;
4883 MonoObject *exc = NULL;
4886 iinfo = image->image_info;
4887 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4889 g_error ("No entry point method found in %s", image->name);
4891 rval = mono_runtime_run_main (method, argc, argv, &exc);
4893 mono_unhandled_exception (exc);
4902 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4903 "Usage is: mint [options] executable args...\n\n", VERSION);
4905 "Runtime Debugging:\n"
4910 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4913 " --traceclassinit\n"
4916 " --debug method_name\n"
4922 " --config filename load the specified config file instead of the default\n"
4923 " --workers n maximum number of worker threads\n"
4930 test_load_class (MonoImage* image)
4932 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4936 for (i = 1; i <= t->rows; ++i) {
4937 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4938 mono_class_init (klass);
4943 static MonoException * segv_exception = NULL;
4946 segv_handler (int signum)
4948 signal (signum, segv_handler);
4949 mono_raise_exception (segv_exception);
4954 quit_handler (int signum)
4956 signal (signum, quit_handler);
4957 mono_raise_exception (quit_exception);
4961 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4962 MonoReflectionMethod **method,
4963 gint32 *iloffset, gint32 *native_offset,
4964 MonoString **file, gint32 *line, gint32 *column)
4977 *file = mono_string_new (mono_domain_get (), "unknown");
4983 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4991 int enable_debugging;
4997 static void main_thread_handler (gpointer user_data)
4999 MainThreadArgs *main_args=(MainThreadArgs *)user_data;
5000 MonoAssembly *assembly;
5003 if (main_args->enable_debugging)
5004 mono_debug_init (main_args->domain, MONO_DEBUG_FORMAT_MONO);
5006 assembly = mono_domain_assembly_open (main_args->domain,
5010 fprintf (stderr, "Can not open image %s\n", main_args->file);
5014 if (main_args->enable_debugging)
5015 mono_debug_init_2 (assembly);
5018 test_load_class (assembly->image);
5020 error = mono_verify_corlib ();
5022 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5025 segv_exception = mono_get_exception_null_reference ();
5026 segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
5027 signal (SIGSEGV, segv_handler);
5028 /* perhaps we should use a different class for this exception... */
5029 quit_exception = mono_get_exception_null_reference ();
5030 quit_exception->message = mono_string_new (main_args->domain, "Quit");
5031 signal (SIGINT, quit_handler);
5033 ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
5038 mono_runtime_install_handlers (void)
5040 /* FIXME: anything to do here? */
5044 quit_function (MonoDomain *domain, gpointer user_data)
5046 mono_profiler_shutdown ();
5048 mono_runtime_cleanup (domain);
5049 mono_domain_free (domain, TRUE);
5054 mono_interp_cleanup(MonoDomain *domain)
5056 quit_function (domain, NULL);
5060 mono_interp_exec(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
5062 return ves_exec (domain, assembly, argc, argv);
5066 mono_interp_init(const char *file)
5070 g_set_prgname (file);
5071 mono_set_rootdir ();
5073 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
5074 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
5076 g_thread_init (NULL);
5078 thread_context_id = TlsAlloc ();
5079 TlsSetValue (thread_context_id, NULL);
5080 InitializeCriticalSection(&calc_section);
5081 InitializeCriticalSection(&create_method_pointer_mutex);
5083 mono_install_compile_method (mono_create_method_pointer);
5084 mono_install_runtime_invoke (interp_mono_runtime_invoke);
5085 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
5087 mono_install_handler (interp_ex_handler);
5088 mono_install_stack_walk (interp_walk_stack);
5089 mono_runtime_install_cleanup (quit_function);
5091 domain = mono_init (file);
5092 #ifdef __hpux /* generates very big stack frames */
5093 mono_threads_set_default_stacksize(32*1024*1024);
5096 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
5097 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
5098 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
5100 mono_runtime_init (domain, NULL, NULL);
5106 mono_main (int argc, char *argv [])
5109 int retval = 0, i, ocount = 0;
5110 char *file, *config_file = NULL;
5111 int enable_debugging = FALSE;
5112 MainThreadArgs main_args;
5118 for (i = 1; i < argc && argv [i][0] == '-'; i++){
5119 if (strcmp (argv [i], "--trace") == 0)
5121 if (strcmp (argv [i], "--noptr") == 0)
5122 global_no_pointers = 1;
5123 if (strcmp (argv [i], "--traceops") == 0)
5125 if (strcmp (argv [i], "--dieonex") == 0) {
5126 die_on_exception = 1;
5127 enable_debugging = 1;
5129 if (strcmp (argv [i], "--print-vtable") == 0)
5130 mono_print_vtable = TRUE;
5131 if (strcmp (argv [i], "--profile") == 0)
5132 mono_profiler_load (NULL);
5133 if (strcmp (argv [i], "--opcode-count") == 0)
5135 if (strcmp (argv [i], "--config") == 0)
5136 config_file = argv [++i];
5137 if (strcmp (argv [i], "--workers") == 0) {
5138 mono_max_worker_threads = atoi (argv [++i]);
5139 if (mono_max_worker_threads < 1)
5140 mono_max_worker_threads = 1;
5142 if (strcmp (argv [i], "--help") == 0)
5145 if (strcmp (argv [i], "--debug") == 0) {
5146 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
5148 g_error ("Invalid method name '%s'", argv [i]);
5149 db_methods = g_list_append (db_methods, desc);
5159 domain = mono_interp_init(file);
5160 mono_config_parse (config_file);
5162 error = mono_verify_corlib ();
5164 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5168 error = mono_check_corlib_version ();
5170 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5171 fprintf (stderr, "Download a newer corlib at http://go-mono/daily.\n");
5175 main_args.domain=domain;
5176 main_args.file=file;
5177 main_args.argc=argc-i;
5178 main_args.argv=argv+i;
5179 main_args.enable_debugging=enable_debugging;
5181 mono_runtime_exec_managed_code (domain, main_thread_handler,
5184 quit_function (domain, NULL);
5186 /* Get the return value from System.Environment.ExitCode */
5187 retval=mono_environment_exitcode_get ();
5191 fprintf (stderr, "opcode count: %ld\n", opcode_count);
5192 fprintf (stderr, "fcall count: %ld\n", fcall_count);