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.
27 #include <mono/os/gc_wrapper.h>
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/blob.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/io-layer/io-layer.h>
56 #include <mono/metadata/socket-io.h>
57 #include <mono/metadata/mono-config.h>
58 #include <mono/metadata/marshal.h>
59 #include <mono/metadata/environment.h>
60 #include <mono/metadata/mono-debug.h>
61 #include <mono/os/util.h>
63 /*#include <mono/cli/types.h>*/
68 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
71 #define finite _finite
75 #define finite isfinite
79 /* If true, then we output the opcodes as we interpret them */
80 static int global_tracing = 0;
81 static int global_no_pointers = 0;
83 static int debug_indent_level = 0;
86 * Pull the list of opcodes
88 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
92 #include "mono/cil/opcode.def"
97 #if SIZEOF_VOID_P == 8
98 #define GET_NATI(sp) ((sp).type == VAL_I32 ? (sp).data.i : (sp).data.nati)
100 #define GET_NATI(sp) (sp).data.i
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 if ((sp [ac->rank].type == VAL_OBJ) && sp [ac->rank].data.p && !mono_object_isinst (sp [ac->rank].data.p, mono_object_class (o)->element_class)) {
577 frame->ex = mono_get_exception_array_type_mismatch ();
578 FILL_IN_TRACE (frame->ex, frame);
582 esize = mono_array_element_size (ac);
583 ea = mono_array_addr_with_size (ao, esize, pos);
585 mt = frame->method->signature->params [ac->rank];
586 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
590 ves_array_get (MonoInvocation *frame)
592 stackval *sp = frame->stack_args;
596 gint32 i, t, pos, esize;
602 ac = o->vtable->klass;
604 g_assert (ac->rank >= 1);
607 if (ao->bounds != NULL) {
608 pos -= ao->bounds [0].lower_bound;
609 for (i = 1; i < ac->rank; i++) {
610 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
611 ao->bounds [i].length) {
612 frame->ex = mono_get_exception_index_out_of_range ();
613 FILL_IN_TRACE(frame->ex, frame);
617 pos = pos*ao->bounds [i].length + sp [i].data.i -
618 ao->bounds [i].lower_bound;
620 } else if (pos >= ao->max_length) {
621 frame->ex = mono_get_exception_index_out_of_range ();
622 FILL_IN_TRACE(frame->ex, frame);
626 esize = mono_array_element_size (ac);
627 ea = mono_array_addr_with_size (ao, esize, pos);
629 mt = frame->method->signature->ret;
630 stackval_from_data (mt, frame->retval, ea, FALSE);
634 ves_array_element_address (MonoInvocation *frame)
636 stackval *sp = frame->stack_args;
640 gint32 i, t, pos, esize;
645 ac = o->vtable->klass;
647 g_assert (ac->rank >= 1);
650 if (ao->bounds != NULL) {
651 pos -= ao->bounds [0].lower_bound;
652 for (i = 1; i < ac->rank; i++) {
653 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
654 ao->bounds [i].length) {
655 frame->ex = mono_get_exception_index_out_of_range ();
656 FILL_IN_TRACE(frame->ex, frame);
659 pos = pos*ao->bounds [i].length + sp [i].data.i -
660 ao->bounds [i].lower_bound;
662 } else if (pos >= ao->max_length) {
663 frame->ex = mono_get_exception_index_out_of_range ();
664 FILL_IN_TRACE(frame->ex, frame);
668 esize = mono_array_element_size (ac);
669 ea = mono_array_addr_with_size (ao, esize, pos);
671 frame->retval->type = VAL_MP;
672 frame->retval->data.p = ea;
676 interp_walk_stack (MonoStackWalk func, gpointer user_data)
678 ThreadContext *context = TlsGetValue (thread_context_id);
679 MonoInvocation *frame = context->current_frame;
681 MonoMethodHeader *hd;
684 gboolean managed = FALSE;
685 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
686 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
689 hd = ((MonoMethodNormal*)frame->method)->header;
690 il_offset = frame->ip - hd->code;
691 if (!frame->method->wrapper_type)
694 if (func (frame->method, -1, il_offset, managed, user_data))
696 frame = frame->parent;
701 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor, ThreadContext *context)
705 MonoInvocation *old_frame = context->current_frame;
706 MonoInvocation *old_env_frame = context->env_frame;
707 jmp_buf *old_env = context->current_env;
710 context->current_frame = old_frame;
711 context->env_frame = old_env_frame;
712 context->current_env = old_env;
713 context->search_for_handler = 0;
717 context->env_frame = frame;
718 context->current_env = &env;
721 if (!frame->method->info) {
722 func = frame->method->info = mono_arch_create_trampoline (sig, string_ctor);
724 func = (MonoPIFunc)frame->method->info;
727 func = mono_arch_create_trampoline (sig, string_ctor);
730 context->current_frame = frame;
732 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
735 stackval_from_data (&mono_defaults.string_class->byval_arg,
736 frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
737 } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
738 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
740 context->current_frame = old_frame;
741 context->env_frame = old_env_frame;
742 context->current_env = old_env;
747 * runtime specifies that the implementation of the method is automatically
748 * provided by the runtime and is primarily used for the methods of delegates.
751 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
753 const char *name = frame->method->name;
754 MonoObject *obj = (MonoObject*)frame->obj;
759 mono_class_init (frame->method->klass);
761 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
762 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
763 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
766 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
767 nm = mono_marshal_get_delegate_invoke (frame->method);
768 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
769 ves_exec_method_with_context (&call, context);
773 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
774 nm = mono_marshal_get_delegate_begin_invoke (frame->method);
775 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
776 ves_exec_method_with_context (&call, context);
780 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
781 nm = mono_marshal_get_delegate_end_invoke (frame->method);
782 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
783 ves_exec_method_with_context (&call, context);
789 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
790 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
791 ves_array_set (frame);
794 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
795 ves_array_get (frame);
798 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
799 ves_array_element_address (frame);
804 g_error ("Don't know how to exec runtime method %s.%s::%s",
805 frame->method->klass->name_space, frame->method->klass->name,
806 frame->method->name);
810 dump_stack (stackval *stack, stackval *sp)
813 GString *str = g_string_new ("");
816 return g_string_free (str, FALSE);
820 #if SIZEOF_VOID_P == 4
821 case VAL_NATI: g_string_sprintfa (str, "[%d/0x%0x] ", s->data.nati, s->data.nati); break;
823 case VAL_NATI: g_string_sprintfa (str, "[%lld/0x%0llx] ", s->data.nati, s->data.nati); break;
825 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
826 case VAL_I64: g_string_sprintfa (str, "[%lldL] ", s->data.l); break;
827 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
829 if (!global_no_pointers)
830 g_string_sprintfa (str, "[vt: %p] ", s->data.vt);
832 g_string_sprintfa (str, "[vt%s] ", s->data.vt ? "" : "=null");
835 MonoObject *obj = s->data.p;
836 if (global_no_pointers && obj && obj->vtable) {
837 MonoClass *klass = mono_object_class (obj);
838 if (klass == mono_defaults.string_class) {
839 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
840 g_string_sprintfa (str, "[str:%s] ", utf8);
843 } else if (klass == mono_defaults.sbyte_class) {
844 g_string_sprintfa (str, "[b:%d] ",
845 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
847 } else if (klass == mono_defaults.int16_class) {
848 g_string_sprintfa (str, "[b:%d] ",
849 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
851 } else if (klass == mono_defaults.int32_class) {
852 g_string_sprintfa (str, "[b:%d] ",
853 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
855 } else if (klass == mono_defaults.byte_class) {
856 g_string_sprintfa (str, "[b:%u] ",
857 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
859 } else if (klass == mono_defaults.char_class
860 || klass == mono_defaults.uint16_class) {
861 g_string_sprintfa (str, "[b:%u] ",
862 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
864 } else if (klass == mono_defaults.uint32_class) {
865 g_string_sprintfa (str, "[b:%u] ",
866 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
868 } else if (klass == mono_defaults.int64_class) {
869 g_string_sprintfa (str, "[b:%lld] ",
870 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
872 } else if (klass == mono_defaults.uint64_class) {
873 g_string_sprintfa (str, "[b:%llu] ",
874 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
876 } else if (klass == mono_defaults.double_class) {
877 g_string_sprintfa (str, "[b:%0.5f] ",
878 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
880 } else if (klass == mono_defaults.single_class) {
881 g_string_sprintfa (str, "[b:%0.5f] ",
882 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
884 } else if (klass == mono_defaults.boolean_class) {
885 g_string_sprintfa (str, "[b:%s] ",
886 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
894 if (!global_no_pointers)
895 g_string_sprintfa (str, "[%c:%p] ", s->type == VAL_OBJ ? 'O' : s->type == VAL_MP ? 'M' : '?', s->data.p);
897 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
902 return g_string_free (str, FALSE);
906 dump_frame (MonoInvocation *inv)
908 GString *str = g_string_new ("");
911 for (i = 0; inv; inv = inv->parent, ++i) {
912 if (inv->method != NULL) {
916 const char * opname = "";
917 gchar *source = NULL;
924 k = inv->method->klass;
926 if ((inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
927 (inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
928 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
932 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
935 opname = mono_opcode_names [codep];
936 codep = inv->ip - hd->code;
938 source = mono_debug_source_location_from_il_offset (inv->method, codep, NULL);
941 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
943 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s) at %s\n", i, codep, opname,
944 k->name_space, k->name, inv->method->name, args, source);
946 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
947 k->name_space, k->name, inv->method->name, args);
952 return g_string_free (str, FALSE);
956 INLINE_STRING_LENGTH = 1,
957 INLINE_STRING_GET_CHARS,
960 INLINE_TYPE_ELEMENT_TYPE
965 MonoClassField *field;
966 } MonoRuntimeFieldInfo;
972 MonoRuntimeFieldInfo *field_info;
977 write32(unsigned char *p, guint32 v)
980 p[1] = (v >> 8) & 0xff;
981 p[2] = (v >> 16) & 0xff;
982 p[3] = (v >> 24) & 0xff;
985 static CRITICAL_SECTION calc_section;
988 calc_offsets (MonoImage *image, MonoMethod *method)
990 int i, align, size, offset = 0;
991 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
992 MonoMethodSignature *signature = method->signature;
993 register const unsigned char *ip, *end;
994 const MonoOpcode *opcode;
998 MonoDomain *domain = mono_domain_get ();
999 MethodRuntimeData *rtd;
1002 mono_profiler_method_jit (method); /* sort of... */
1003 /* intern the strings in the method. */
1005 end = ip + header->code_size;
1012 opcode = &mono_opcodes [i];
1013 switch (opcode->argument) {
1014 case MonoInlineNone:
1017 case MonoInlineString:
1018 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
1021 case MonoInlineType:
1022 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1023 class = mono_class_get (image, read32 (ip + 1));
1024 mono_class_init (class);
1025 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
1026 mono_class_vtable (domain, class);
1030 case MonoInlineField:
1034 case MonoInlineMethod:
1035 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1036 m = mono_get_method (image, read32 (ip + 1), NULL);
1037 mono_class_init (m->klass);
1038 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
1039 mono_class_vtable (domain, m->klass);
1045 case MonoShortInlineR:
1047 case MonoInlineBrTarget:
1053 case MonoShortInlineVar:
1054 case MonoShortInlineI:
1055 case MonoShortInlineBrTarget:
1058 case MonoInlineSwitch: {
1071 g_assert_not_reached ();
1076 /* the rest needs to be locked so it is only done once */
1077 EnterCriticalSection(&calc_section);
1078 if (method->info != NULL) {
1079 LeaveCriticalSection(&calc_section);
1080 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1083 rtd = (MethodRuntimeData *)g_malloc0 (sizeof(MethodRuntimeData) + (header->num_locals - 1 + signature->hasthis + signature->param_count) * sizeof(guint32));
1084 for (i = 0; i < header->num_locals; ++i) {
1085 size = mono_type_size (header->locals [i], &align);
1086 offset += align - 1;
1087 offset &= ~(align - 1);
1088 rtd->offsets [i] = offset;
1091 rtd->locals_size = offset;
1093 if (signature->hasthis) {
1094 offset += sizeof (gpointer) - 1;
1095 offset &= ~(sizeof (gpointer) - 1);
1096 rtd->offsets [header->num_locals] = offset;
1097 offset += sizeof (gpointer);
1099 for (i = 0; i < signature->param_count; ++i) {
1100 if (signature->pinvoke) {
1101 size = mono_type_native_stack_size (signature->params [i], &align);
1105 size = mono_type_stack_size (signature->params [i], &align);
1106 offset += align - 1;
1107 offset &= ~(align - 1);
1108 rtd->offsets [signature->hasthis + header->num_locals + i] = offset;
1111 rtd->args_size = offset;
1112 rtd->field_info = g_malloc(n_fields * sizeof(MonoRuntimeFieldInfo));
1114 header->code = g_memdup(header->code, header->code_size);
1117 end = ip + header->code_size;
1124 opcode = &mono_opcodes [i];
1125 switch (opcode->argument) {
1126 case MonoInlineNone:
1129 case MonoInlineString:
1132 case MonoInlineType:
1135 case MonoInlineField:
1136 token = read32 (ip + 1);
1137 rtd->field_info[n_fields].field = mono_field_from_token (image, token, &class);
1138 mono_class_vtable (domain, class);
1139 g_assert(rtd->field_info[n_fields].field->parent == class);
1140 write32 ((unsigned char *)ip + 1, n_fields);
1144 case MonoInlineMethod:
1149 case MonoShortInlineR:
1151 case MonoInlineBrTarget:
1157 case MonoShortInlineVar:
1158 case MonoShortInlineI:
1159 case MonoShortInlineBrTarget:
1162 case MonoInlineSwitch: {
1175 g_assert_not_reached ();
1181 * We store the inline info in addr, since it's unused for IL methods.
1183 if (method->klass == mono_defaults.string_class) {
1184 if (strcmp (method->name, "get_Length") == 0)
1185 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
1186 else if (strcmp (method->name, "get_Chars") == 0)
1187 method->addr = GUINT_TO_POINTER (INLINE_STRING_GET_CHARS);
1188 } else if (method->klass == mono_defaults.array_class) {
1189 if (strcmp (method->name, "get_Length") == 0)
1190 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
1191 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
1192 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
1193 } else if (method->klass == mono_defaults.monotype_class) {
1194 if (strcmp (method->name, "GetElementType") == 0)
1195 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
1197 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1199 LeaveCriticalSection(&calc_section);
1202 #define LOCAL_POS(n) (frame->locals + rtd->offsets [n])
1203 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1205 #define ARG_POS(n) (args_pointers [(n)])
1206 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1207 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1209 typedef struct _vtallocation vtallocation;
1211 struct _vtallocation {
1216 char data [MONO_ZERO_LEN_ARRAY];
1217 double force_alignment;
1221 #define vt_allocmem(sz, var) \
1223 vtallocation *tmp, *prev; \
1226 while (tmp && (tmp->max_size < (sz))) { \
1231 tmp = alloca (sizeof (vtallocation) + (sz)); \
1232 tmp->max_size = (sz); \
1233 g_assert ((sz) < 10000); \
1237 prev->next = tmp->next; \
1239 vtalloc = tmp->next; \
1241 var = tmp->u.data; \
1244 #define vt_alloc(vtype,sp,native) \
1245 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1246 if (!(vtype)->byref) { \
1248 if (native) vtsize = mono_class_native_size ((vtype)->data.klass, NULL); \
1249 else vtsize = mono_class_value_size ((vtype)->data.klass, NULL); \
1250 vt_allocmem(vtsize, (sp)->data.vt); \
1254 #define vt_free(sp) \
1256 if ((sp)->type == VAL_VALUET) { \
1257 vtallocation *tmp = (vtallocation*)(((char*)(sp)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1258 tmp->next = vtalloc; \
1263 #define stackvalpush(val, sp) \
1265 (sp)->type = (val)->type; \
1266 (sp)->data = (val)->data; \
1267 if ((val)->type == VAL_VALUET) { \
1268 vtallocation *vala = (vtallocation*)(((char*)(val)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1269 vt_allocmem(vala->size, (sp)->data.vt); \
1270 memcpy((sp)->data.vt, (val)->data.vt, vala->size); \
1275 #define stackvalcpy(src, dest) \
1277 (dest)->type = (src)->type; \
1278 (dest)->data = (src)->data; \
1279 if ((dest)->type == VAL_VALUET) { \
1280 vtallocation *tmp = (vtallocation*)(((char*)(src)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1281 memcpy((dest)->data.vt, (src)->data.vt, tmp->size); \
1287 verify_method (MonoMethod *m)
1289 GSList *errors, *tmp;
1290 MonoVerifyInfo *info;
1292 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1294 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1295 for (tmp = errors; tmp; tmp = tmp->next) {
1297 g_print ("%s\n", info->message);
1301 mono_free_verify_list (errors);
1305 #define MYGUINT64_MAX 18446744073709551615ULL
1306 #define MYGINT64_MAX 9223372036854775807LL
1307 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1309 #define MYGUINT32_MAX 4294967295U
1310 #define MYGINT32_MAX 2147483647
1311 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1313 #define CHECK_ADD_OVERFLOW(a,b) \
1314 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1315 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1317 #define CHECK_SUB_OVERFLOW(a,b) \
1318 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1319 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1321 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1322 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1324 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1325 (guint32)(a) < (guint32)(b) ? -1 : 0
1327 #define CHECK_ADD_OVERFLOW64(a,b) \
1328 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1329 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1331 #define CHECK_SUB_OVERFLOW64(a,b) \
1332 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1333 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1335 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1336 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1338 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1339 (guint64)(a) < (guint64)(b) ? -1 : 0
1341 #if SIZEOF_VOID_P == 4
1342 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1343 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1345 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1346 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1349 /* Resolves to TRUE if the operands would overflow */
1350 #define CHECK_MUL_OVERFLOW(a,b) \
1351 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1352 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1353 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1354 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1355 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1356 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1357 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1359 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1360 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1361 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1363 #define CHECK_MUL_OVERFLOW64(a,b) \
1364 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1365 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1366 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1367 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1368 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1369 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1370 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1372 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1373 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1374 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1376 #if SIZEOF_VOID_P == 4
1377 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1378 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1380 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1381 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1385 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1387 MonoInvocation frame;
1388 ThreadContext *context = TlsGetValue (thread_context_id);
1389 MonoObject *retval = NULL;
1390 MonoMethodSignature *sig = method->signature;
1391 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1392 int i, type, isobject = 0;
1395 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1396 ThreadContext context_struct;
1397 MonoInvocation *old_frame;
1399 if (context == NULL) {
1400 context = &context_struct;
1401 context_struct.base_frame = &frame;
1402 context_struct.current_frame = NULL;
1403 context_struct.env_frame = NULL;
1404 context_struct.current_env = NULL;
1405 context_struct.search_for_handler = 0;
1406 TlsSetValue (thread_context_id, context);
1409 old_frame = context->current_frame;
1412 /* FIXME: Set frame for execption handling. */
1414 switch (sig->ret->type) {
1415 case MONO_TYPE_VOID:
1417 case MONO_TYPE_STRING:
1418 case MONO_TYPE_OBJECT:
1419 case MONO_TYPE_CLASS:
1420 case MONO_TYPE_ARRAY:
1421 case MONO_TYPE_SZARRAY:
1424 case MONO_TYPE_VALUETYPE:
1425 retval = mono_object_new (mono_domain_get (), klass);
1426 ret = ((char*)retval) + sizeof (MonoObject);
1427 if (!sig->ret->data.klass->enumtype)
1428 result.data.vt = ret;
1431 retval = mono_object_new (mono_domain_get (), klass);
1432 ret = ((char*)retval) + sizeof (MonoObject);
1436 for (i = 0; i < sig->param_count; ++i) {
1437 if (sig->params [i]->byref) {
1438 args [i].type = VAL_POINTER;
1439 args [i].data.p = params [i];
1442 type = sig->params [i]->type;
1447 case MONO_TYPE_BOOLEAN:
1448 args [i].type = VAL_I32;
1449 args [i].data.i = *(MonoBoolean*)params [i];
1453 case MONO_TYPE_CHAR:
1454 args [i].type = VAL_I32;
1455 args [i].data.i = *(gint16*)params [i];
1457 #if SIZEOF_VOID_P == 4
1458 case MONO_TYPE_U: /* use VAL_POINTER? */
1463 args [i].type = VAL_I32;
1464 args [i].data.i = *(gint32*)params [i];
1466 #if SIZEOF_VOID_P == 8
1472 args [i].type = VAL_I64;
1473 args [i].data.l = *(gint64*)params [i];
1475 case MONO_TYPE_VALUETYPE:
1476 if (sig->params [i]->data.klass->enumtype) {
1477 type = sig->params [i]->data.klass->enum_basetype->type;
1480 args [i].type = VAL_POINTER;
1481 args [i].data.p = params [i];
1484 case MONO_TYPE_STRING:
1485 case MONO_TYPE_CLASS:
1486 case MONO_TYPE_ARRAY:
1487 case MONO_TYPE_SZARRAY:
1488 case MONO_TYPE_OBJECT:
1489 args [i].type = VAL_OBJ;
1490 args [i].data.p = params [i];
1493 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1497 if (method->klass->valuetype)
1498 /* Unbox the instance, since valuetype methods expect an interior pointer. */
1499 obj = mono_object_unbox (obj);
1501 INIT_FRAME(&frame,context->current_frame,obj,args,&result,method);
1503 frame.invoke_trap = 1;
1504 ves_exec_method_with_context (&frame, context);
1505 if (context == &context_struct)
1506 TlsSetValue (thread_context_id, NULL);
1508 context->current_frame = old_frame;
1509 if (frame.ex != NULL) {
1511 *exc = (MonoObject*) frame.ex;
1512 if (*exc == (MonoObject *)quit_exception)
1513 mono_print_unhandled_exception(*exc);
1516 if (context->current_env != NULL) {
1517 context->env_frame->ex = frame.ex;
1518 longjmp(*context->current_env, 1);
1521 printf("dropped exception...\n");
1523 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1525 if (isobject || method->string_ctor)
1526 return result.data.p;
1527 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1531 static CRITICAL_SECTION create_method_pointer_mutex;
1533 static MonoGHashTable *method_pointer_hash = NULL;
1536 mono_create_method_pointer (MonoMethod *method)
1541 EnterCriticalSection (&create_method_pointer_mutex);
1542 if (!method_pointer_hash) {
1543 method_pointer_hash = mono_g_hash_table_new (NULL, NULL);
1545 addr = mono_g_hash_table_lookup (method_pointer_hash, method);
1547 LeaveCriticalSection (&create_method_pointer_mutex);
1552 * If it is a static P/Invoke method, we can just return the pointer
1553 * to the method implementation.
1555 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
1556 ji = g_new0 (MonoJitInfo, 1);
1557 ji->method = method;
1559 ji->code_start = method->addr;
1561 mono_jit_info_table_add (mono_root_domain, ji);
1563 addr = method->addr;
1566 addr = mono_arch_create_method_pointer (method);
1568 mono_g_hash_table_insert (method_pointer_hash, method, addr);
1569 LeaveCriticalSection (&create_method_pointer_mutex);
1575 * Need to optimize ALU ops when natural int == int32
1577 * IDEA: if we maintain a stack of ip, sp to be checked
1578 * in the return opcode, we could inline simple methods that don't
1579 * use the stack or local variables....
1581 * The {,.S} versions of many opcodes can/should be merged to reduce code
1586 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
1588 MonoDomain *domain = mono_domain_get ();
1589 MonoInvocation child_frame;
1590 MonoMethodHeader *header;
1591 MonoMethodSignature *signature;
1593 GSList *finally_ips = NULL;
1594 const unsigned char *endfinally_ip = NULL;
1595 register const unsigned char *ip;
1596 register stackval *sp = NULL;
1597 MethodRuntimeData *rtd;
1598 void **args_pointers;
1599 gint tracing = global_tracing;
1600 unsigned char tail_recursion = 0;
1601 unsigned char unaligned_address = 0;
1602 unsigned char volatile_address = 0;
1603 vtallocation *vtalloc = NULL;
1604 MonoVTable *method_class_vt;
1608 frame->ip = ip = NULL;
1609 context->current_frame = frame;
1611 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1612 frame->method = mono_marshal_get_native_wrapper (frame->method);
1613 if (frame->method == NULL)
1617 method_class_vt = mono_class_vtable (domain, frame->method->klass);
1618 if (!method_class_vt->initialized)
1619 mono_runtime_class_init (method_class_vt);
1620 signature = frame->method->signature;
1624 header = ((MonoMethodNormal *)frame->method)->header;
1626 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1627 if (!frame->method->addr) {
1628 /* assumes all internal calls with an array this are built in... */
1629 if (signature->hasthis && frame->method->klass->rank) {
1630 ves_runtime_method (frame, context);
1632 goto handle_exception;
1635 frame->method->addr = mono_lookup_internal_call (frame->method);
1637 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1638 frame->method->string_ctor, context);
1640 goto handle_exception;
1643 else if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1644 ves_runtime_method (frame, context);
1646 goto handle_exception;
1650 /*verify_method (frame->method);*/
1652 image = frame->method->klass->image;
1654 if (!frame->method->info)
1655 calc_offsets (image, frame->method);
1656 rtd = frame->method->info;
1659 * with alloca we get the expected huge performance gain
1660 * stackval *stack = g_new0(stackval, header->max_stack);
1662 g_assert (header->max_stack < 10000);
1663 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1665 if (header->num_locals) {
1666 g_assert (rtd->locals_size < 65536);
1667 frame->locals = alloca (rtd->locals_size);
1669 * yes, we do it unconditionally, because it needs to be done for
1670 * some cases anyway and checking for that would be even slower.
1672 memset (frame->locals, 0, rtd->locals_size);
1676 * Copy args from stack_args to args.
1678 if (signature->param_count || signature->hasthis) {
1680 int has_this = signature->hasthis;
1682 g_assert (rtd->args_size < 10000);
1683 frame->args = alloca (rtd->args_size);
1684 g_assert ((signature->param_count + has_this) < 1000);
1685 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1688 this_arg = args_pointers [0] = frame->args;
1689 *this_arg = frame->obj;
1691 for (i = 0; i < signature->param_count; ++i) {
1692 args_pointers [i + has_this] = frame->args + rtd->offsets [header->num_locals + has_this + i];
1693 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1697 child_frame.parent = frame;
1698 frame->child = &child_frame;
1705 * using while (ip < end) may result in a 15% performance drop,
1706 * but it may be useful for debug
1710 /*g_assert (sp >= stack);*/
1714 char *ins, *discode;
1715 if (sp > frame->stack) {
1716 ins = dump_stack (frame->stack, sp);
1718 ins = g_strdup ("");
1721 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1722 discode [strlen (discode) - 1] = 0; /* no \n */
1723 g_print ("(%u) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1735 G_BREAKPOINT (); /* this is not portable... */
1740 CASE (CEE_LDARG_3) {
1741 int n = (*ip)-CEE_LDARG_0;
1743 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1744 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1751 CASE (CEE_LDLOC_3) {
1752 int n = (*ip)-CEE_LDLOC_0;
1753 MonoType *vartype = LOCAL_TYPE (header, n);
1755 if (vartype->type == MONO_TYPE_I4) {
1757 sp->data.i = *(gint32*) LOCAL_POS (n);
1761 vt_alloc (vartype, sp, FALSE);
1762 stackval_from_data (vartype, sp, LOCAL_POS (n), FALSE);
1770 CASE (CEE_STLOC_3) {
1771 int n = (*ip)-CEE_STLOC_0;
1774 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1775 gint32 *p = (gint32*)LOCAL_POS (n);
1779 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1786 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1787 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1791 CASE (CEE_LDARGA_S) {
1793 sp->data.vt = ARG_POS (*ip);
1802 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1808 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1809 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1813 CASE (CEE_LDLOCA_S) {
1815 sp->data.p = LOCAL_POS (*ip);
1824 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1834 CASE (CEE_LDC_I4_M1)
1850 sp->data.i = (*ip) - CEE_LDC_I4_0;
1857 sp->data.i = *(const gint8 *)ip;
1864 sp->data.i = read32 (ip);
1871 sp->data.l = read64 (ip);
1878 sp->type = VAL_DOUBLE;
1887 sp->type = VAL_DOUBLE;
1888 readr8(ip, &sp->data.f);
1892 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1894 stackvalpush(sp - 1, sp);
1902 CASE (CEE_JMP) ves_abort(); BREAK;
1903 CASE (CEE_CALLVIRT) /* Fall through */
1904 CASE (CEE_CALLI) /* Fall through */
1906 MonoMethodSignature *csignature;
1908 stackval *endsp = sp;
1910 int virtual = *ip == CEE_CALLVIRT;
1911 int calli = *ip == CEE_CALLI;
1912 unsigned char *code = NULL;
1915 * We ignore tail recursion for now.
1922 token = read32 (ip);
1928 if (frame->method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE &&
1929 (ji = mono_jit_info_table_find (mono_root_domain, code)) != NULL) {
1930 child_frame.method = ji->method;
1931 csignature = ji->method->signature;
1933 else if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1934 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1935 child_frame.method = NULL;
1937 g_assert_not_reached ();
1941 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
1942 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
1944 child_frame.method = mono_get_method (image, token, NULL);
1945 if (!child_frame.method)
1946 THROW_EX (mono_get_exception_missing_method (), ip -5);
1947 csignature = child_frame.method->signature;
1949 stackval *this_arg = &sp [-csignature->param_count-1];
1950 if (!this_arg->data.p)
1951 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1952 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1953 if (!child_frame.method)
1954 THROW_EX (mono_get_exception_missing_method (), ip -5);
1958 if (frame->method->wrapper_type == MONO_WRAPPER_NONE)
1959 if (child_frame.method && child_frame.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1960 child_frame.method = mono_marshal_get_synchronized_wrapper (child_frame.method);
1962 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
1963 /* decrement by the actual number of args */
1964 if (csignature->param_count) {
1965 sp -= csignature->param_count;
1966 child_frame.stack_args = sp;
1968 child_frame.stack_args = NULL;
1970 if (csignature->hasthis) {
1971 g_assert (sp >= frame->stack);
1974 * It may also be a TP from LD(S)FLDA
1975 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_MP);
1977 if (sp->type == VAL_OBJ && child_frame.method &&
1978 child_frame.method->klass->valuetype) /* unbox it */
1979 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1981 child_frame.obj = sp->data.p;
1983 child_frame.obj = NULL;
1985 if (csignature->ret->type != MONO_TYPE_VOID) {
1986 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
1987 child_frame.retval = &retval;
1989 child_frame.retval = NULL;
1992 child_frame.ip = NULL;
1993 child_frame.ex = NULL;
1994 child_frame.ex_handler = NULL;
1996 if (!child_frame.method) {
1998 ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE, context);
1999 if (child_frame.ex) {
2000 frame->ex = child_frame.ex;
2001 goto handle_exception;
2003 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
2004 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
2005 g_assert (child_frame.method);
2006 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
2007 ves_exec_method_with_context (&child_frame, context);
2009 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
2010 case INLINE_STRING_LENGTH:
2011 retval.type = VAL_I32;
2012 retval.data.i = ((MonoString*)sp->data.p)->length;
2013 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
2015 case INLINE_STRING_GET_CHARS: {
2016 int idx = GET_NATI(sp [1]);
2017 if ((idx < 0) || (idx >= mono_string_length ((MonoString*)sp->data.p))) {
2018 child_frame.ex = mono_get_exception_index_out_of_range ();
2019 FILL_IN_TRACE(child_frame.ex, &child_frame);
2022 retval.type = VAL_I32;
2023 retval.data.i = mono_string_chars((MonoString*)sp->data.p)[idx];
2027 case INLINE_ARRAY_LENGTH:
2028 retval.type = VAL_I32;
2029 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
2031 case INLINE_ARRAY_RANK:
2032 retval.type = VAL_I32;
2033 retval.data.i = mono_object_class (sp->data.p)->rank;
2035 case INLINE_TYPE_ELEMENT_TYPE:
2036 retval.type = VAL_OBJ;
2038 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
2039 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
2040 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
2041 else if (c->element_class)
2042 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
2044 retval.data.p = NULL;
2048 ves_exec_method_with_context (&child_frame, context);
2052 context->current_frame = frame;
2054 while (endsp > sp) {
2059 if (child_frame.ex) {
2061 * An exception occurred, need to run finally, fault and catch handlers..
2063 frame->ex = child_frame.ex;
2064 if (context->search_for_handler) {
2065 context->search_for_handler = 0;
2066 goto handle_exception;
2068 goto handle_finally;
2071 /* need to handle typedbyref ... */
2072 if (csignature->ret->type != MONO_TYPE_VOID) {
2079 if (signature->ret->type != MONO_TYPE_VOID) {
2081 if (sp->type == VAL_VALUET) {
2082 /* the caller has already allocated the memory */
2083 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
2086 *frame->retval = *sp;
2089 if (sp > frame->stack)
2090 g_warning ("more values on stack: %d", sp-frame->stack);
2093 CASE (CEE_BR_S) /* Fall through */
2095 if (*ip == CEE_BR) {
2097 ip += (gint32) read32(ip);
2101 ip += (signed char) *ip;
2105 CASE (CEE_BRFALSE) /* Fall through */
2106 CASE (CEE_BRFALSE_S) {
2109 if (*ip == CEE_BRFALSE_S) {
2110 broffset = (signed char)ip [1];
2113 broffset = (gint32) read32 (ip + 1);
2118 case VAL_I32: result = sp->data.i == 0; break;
2119 case VAL_I64: result = sp->data.l == 0; break;
2120 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
2121 default: result = sp->data.p == NULL; break;
2127 CASE (CEE_BRTRUE) /* Fall through */
2128 CASE (CEE_BRTRUE_S) {
2131 if (*ip == CEE_BRTRUE_S) {
2132 broffset = (signed char)ip [1];
2135 broffset = (gint32) read32 (ip + 1);
2140 case VAL_I32: result = sp->data.i != 0; break;
2141 case VAL_I64: result = sp->data.l != 0; break;
2142 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
2143 default: result = sp->data.p != NULL; break;
2149 CASE (CEE_BEQ) /* Fall through */
2153 if (*ip == CEE_BEQ_S) {
2154 broffset = (signed char)ip [1];
2157 broffset = (gint32) read32 (ip + 1);
2161 if (sp->type == VAL_I32)
2162 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
2163 else if (sp->type == VAL_I64)
2164 result = sp [0].data.l == sp [1].data.l;
2165 else if (sp->type == VAL_DOUBLE)
2166 result = sp [0].data.f == sp [1].data.f;
2168 result = sp [0].data.nati == (mono_i)GET_NATI (sp [1]);
2173 CASE (CEE_BGE) /* Fall through */
2177 if (*ip == CEE_BGE_S) {
2178 broffset = (signed char)ip [1];
2181 broffset = (gint32) read32 (ip + 1);
2185 if (sp->type == VAL_I32)
2186 result = (mono_i)sp [0].data.i >= (mono_i)GET_NATI (sp [1]);
2187 else if (sp->type == VAL_I64)
2188 result = sp [0].data.l >= sp [1].data.l;
2189 else if (sp->type == VAL_DOUBLE)
2190 result = sp [0].data.f >= sp [1].data.f;
2192 result = (mono_i)sp [0].data.nati >= (mono_i)GET_NATI (sp [1]);
2197 CASE (CEE_BGT) /* Fall through */
2201 if (*ip == CEE_BGT_S) {
2202 broffset = (signed char)ip [1];
2205 broffset = (gint32) read32 (ip + 1);
2209 if (sp->type == VAL_I32)
2210 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
2211 else if (sp->type == VAL_I64)
2212 result = sp [0].data.l > sp [1].data.l;
2213 else if (sp->type == VAL_DOUBLE)
2214 result = sp [0].data.f > sp [1].data.f;
2216 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
2221 CASE (CEE_BLT) /* Fall through */
2225 if (*ip == CEE_BLT_S) {
2226 broffset = (signed char)ip [1];
2229 broffset = (gint32) read32 (ip + 1);
2233 if (sp->type == VAL_I32)
2234 result = (mono_i)sp[0].data.i < (mono_i)GET_NATI(sp[1]);
2235 else if (sp->type == VAL_I64)
2236 result = sp[0].data.l < sp[1].data.l;
2237 else if (sp->type == VAL_DOUBLE)
2238 result = sp[0].data.f < sp[1].data.f;
2240 result = (mono_i)sp[0].data.nati < (mono_i)GET_NATI(sp[1]);
2245 CASE (CEE_BLE) /* fall through */
2249 if (*ip == CEE_BLE_S) {
2250 broffset = (signed char)ip [1];
2253 broffset = (gint32) read32 (ip + 1);
2258 if (sp->type == VAL_I32)
2259 result = (mono_i)sp [0].data.i <= (mono_i)GET_NATI (sp [1]);
2260 else if (sp->type == VAL_I64)
2261 result = sp [0].data.l <= sp [1].data.l;
2262 else if (sp->type == VAL_DOUBLE)
2263 result = sp [0].data.f <= sp [1].data.f;
2265 result = (mono_i)sp [0].data.nati <= (mono_i)GET_NATI (sp [1]);
2271 CASE (CEE_BNE_UN) /* Fall through */
2272 CASE (CEE_BNE_UN_S) {
2275 if (*ip == CEE_BNE_UN_S) {
2276 broffset = (signed char)ip [1];
2279 broffset = (gint32) read32 (ip + 1);
2283 if (sp->type == VAL_I32)
2284 result = (mono_u)sp [0].data.i != (mono_u)GET_NATI (sp [1]);
2285 else if (sp->type == VAL_I64)
2286 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
2287 else if (sp->type == VAL_DOUBLE)
2288 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2289 (sp [0].data.f != sp [1].data.f);
2291 result = (mono_u)sp [0].data.nati != (mono_u)GET_NATI (sp [1]);
2296 CASE (CEE_BGE_UN) /* Fall through */
2297 CASE (CEE_BGE_UN_S) {
2300 if (*ip == CEE_BGE_UN_S) {
2301 broffset = (signed char)ip [1];
2304 broffset = (gint32) read32 (ip + 1);
2308 if (sp->type == VAL_I32)
2309 result = (mono_u)sp [0].data.i >= (mono_u)GET_NATI (sp [1]);
2310 else if (sp->type == VAL_I64)
2311 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
2312 else if (sp->type == VAL_DOUBLE)
2313 result = !isless (sp [0].data.f,sp [1].data.f);
2315 result = (mono_u)sp [0].data.nati >= (mono_u)GET_NATI (sp [1]);
2320 CASE (CEE_BGT_UN) /* Fall through */
2321 CASE (CEE_BGT_UN_S) {
2324 if (*ip == CEE_BGT_UN_S) {
2325 broffset = (signed char)ip [1];
2328 broffset = (gint32) read32 (ip + 1);
2332 if (sp->type == VAL_I32)
2333 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2334 else if (sp->type == VAL_I64)
2335 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2336 else if (sp->type == VAL_DOUBLE)
2337 result = isgreater (sp [0].data.f, sp [1].data.f);
2339 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
2344 CASE (CEE_BLE_UN) /* Fall through */
2345 CASE (CEE_BLE_UN_S) {
2348 if (*ip == CEE_BLE_UN_S) {
2349 broffset = (signed char)ip [1];
2352 broffset = (gint32) read32 (ip + 1);
2356 if (sp->type == VAL_I32)
2357 result = (mono_u)sp [0].data.i <= (mono_u)GET_NATI (sp [1]);
2358 else if (sp->type == VAL_I64)
2359 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2360 else if (sp->type == VAL_DOUBLE)
2361 result = islessequal (sp [0].data.f, sp [1].data.f);
2363 result = (mono_u)sp [0].data.nati <= (mono_u)GET_NATI (sp [1]);
2368 CASE (CEE_BLT_UN) /* Fall through */
2369 CASE (CEE_BLT_UN_S) {
2372 if (*ip == CEE_BLT_UN_S) {
2373 broffset = (signed char)ip [1];
2376 broffset = (gint32) read32 (ip + 1);
2380 if (sp->type == VAL_I32)
2381 result = (mono_u)sp[0].data.i < (mono_u)GET_NATI(sp[1]);
2382 else if (sp->type == VAL_I64)
2383 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2384 else if (sp->type == VAL_DOUBLE)
2385 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2386 (sp [0].data.f < sp [1].data.f);
2388 result = (mono_u)sp[0].data.nati < (mono_u)GET_NATI(sp[1]);
2395 const unsigned char *st;
2399 st = ip + sizeof (gint32) * n;
2401 if ((guint32)sp->data.i < n) {
2403 ip += sizeof (gint32) * (guint32)sp->data.i;
2404 offset = read32 (ip);
2413 sp[-1].type = VAL_I32;
2414 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2418 sp[-1].type = VAL_I32;
2419 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2423 sp[-1].type = VAL_I32;
2424 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2428 sp[-1].type = VAL_I32;
2429 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2431 CASE (CEE_LDIND_I4) /* Fall through */
2434 sp[-1].type = VAL_I32;
2435 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2439 sp[-1].type = VAL_I64;
2440 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2444 sp[-1].type = VAL_NATI;
2445 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2449 sp[-1].type = VAL_DOUBLE;
2450 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2454 sp[-1].type = VAL_DOUBLE;
2455 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2457 CASE (CEE_LDIND_REF)
2459 sp[-1].type = VAL_OBJ;
2460 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2462 CASE (CEE_STIND_REF) {
2470 CASE (CEE_STIND_I1) {
2475 *p = (gint8)sp[1].data.i;
2478 CASE (CEE_STIND_I2) {
2483 *p = (gint16)sp[1].data.i;
2486 CASE (CEE_STIND_I4) {
2494 CASE (CEE_STIND_I) {
2499 *p = (mono_i)sp[1].data.p;
2502 CASE (CEE_STIND_I8) {
2510 CASE (CEE_STIND_R4) {
2515 *p = (gfloat)sp[1].data.f;
2518 CASE (CEE_STIND_R8) {
2529 /* should probably consider the pointers as unsigned */
2530 if (sp->type == VAL_I32) {
2531 if (sp [-1].type == VAL_I32)
2532 sp [-1].data.i += sp [0].data.i;
2534 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.i;
2535 } else if (sp->type == VAL_I64)
2536 sp [-1].data.l += sp [0].data.l;
2537 else if (sp->type == VAL_DOUBLE)
2538 sp [-1].data.f += sp [0].data.f;
2540 if (sp [-1].type == VAL_I32) {
2541 sp [-1].data.nati = sp [-1].data.i + sp [0].data.nati;
2542 sp [-1].type = sp [0].type;
2544 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.nati;
2550 /* should probably consider the pointers as unsigned */
2551 if (sp->type == VAL_I32) {
2552 if (sp [-1].type == VAL_I32)
2553 sp [-1].data.i -= sp [0].data.i;
2555 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
2556 sp [-1].type = VAL_NATI;
2558 } else if (sp->type == VAL_I64)
2559 sp [-1].data.l -= sp [0].data.l;
2560 else if (sp->type == VAL_DOUBLE)
2561 sp [-1].data.f -= sp [0].data.f;
2563 if (sp [-1].type == VAL_I32) {
2564 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
2565 sp [-1].type = sp [0].type;
2567 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
2573 if (sp->type == VAL_I32) {
2574 if (sp [-1].type == VAL_I32)
2575 sp [-1].data.i *= sp [0].data.i;
2577 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
2578 } else if (sp->type == VAL_I64)
2579 sp [-1].data.l *= sp [0].data.l;
2580 else if (sp->type == VAL_DOUBLE)
2581 sp [-1].data.f *= sp [0].data.f;
2583 if (sp [-1].type == VAL_NATI)
2584 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.nati;
2586 sp [-1].data.nati = sp [-1].data.i * sp [0].data.nati;
2587 sp [-1].type = VAL_NATI;
2594 if (sp->type == VAL_I32) {
2595 if (sp [0].data.i == 0)
2596 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2597 if (sp [-1].type == VAL_I32)
2598 sp [-1].data.i /= sp [0].data.i;
2600 sp [-1].data.nati /= sp [0].data.i;
2601 } else if (sp->type == VAL_I64) {
2602 if (sp [0].data.l == 0)
2603 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2604 sp [-1].data.l /= sp [0].data.l;
2605 } else if (sp->type == VAL_DOUBLE) {
2606 /* set NaN is divisor is 0.0 */
2607 sp [-1].data.f /= sp [0].data.f;
2609 if (sp [-1].type == VAL_NATI)
2610 sp [-1].data.nati = sp [-1].data.nati / sp [0].data.nati;
2612 sp [-1].data.nati = sp [-1].data.i / sp [0].data.nati;
2613 sp [-1].type = VAL_NATI;
2620 if (sp->type == VAL_I32) {
2621 if (sp [0].data.i == 0)
2622 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2623 if (sp [-1].type == VAL_NATI)
2624 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.i;
2626 sp [-1].data.i = (guint32)sp [-1].data.i / (guint32)sp [0].data.i;
2627 } else if (sp->type == VAL_I64) {
2629 if (sp [0].data.l == 0)
2630 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2631 val = sp [-1].data.l;
2632 val /= (guint64)sp [0].data.l;
2633 sp [-1].data.l = val;
2635 if (sp [0].data.nati == 0)
2636 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2637 if (sp [-1].type == VAL_NATI)
2638 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.nati;
2640 sp [-1].data.nati = (mono_u)sp [-1].data.i / (mono_u)sp [0].data.nati;
2641 sp [-1].type = VAL_NATI;
2648 if (sp->type == VAL_I32) {
2649 if (sp [0].data.i == 0)
2650 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2651 if (sp [-1].type == VAL_NATI)
2652 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.i;
2654 sp [-1].data.i = sp [-1].data.i % sp [0].data.i;
2655 } else if (sp->type == VAL_I64) {
2656 if (sp [0].data.l == 0)
2657 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2658 sp [-1].data.l %= sp [0].data.l;
2659 } else if (sp->type == VAL_DOUBLE) {
2660 /* FIXME: what do we actually do here? */
2661 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2663 if (sp [0].data.nati == 0)
2664 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2665 if (sp [-1].type == VAL_NATI)
2666 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.nati;
2668 sp [-1].data.nati = (mono_i)sp [-1].data.i % (mono_i)sp [0].data.nati;
2669 sp [-1].type = VAL_NATI;
2676 if (sp->type == VAL_I32) {
2677 if (sp [0].data.i == 0)
2678 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2679 if (sp [-1].type == VAL_NATI)
2680 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.i;
2682 sp [-1].data.i = (guint32)sp [-1].data.i % (guint32)sp [0].data.i;
2683 } else if (sp->type == VAL_I64) {
2684 if (sp [0].data.l == 0)
2685 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2686 sp [-1].data.l = (guint64)sp [-1].data.l % (guint64)sp [0].data.l;
2687 } else if (sp->type == VAL_DOUBLE) {
2688 /* unspecified behaviour according to the spec */
2690 if (sp [0].data.nati == 0)
2691 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2692 if (sp [-1].type == VAL_NATI)
2693 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.nati;
2695 sp [-1].data.nati = (mono_u)sp [-1].data.i % (mono_u)sp [0].data.nati;
2696 sp [-1].type = VAL_NATI;
2703 if (sp->type == VAL_I32) {
2704 if (sp [-1].type == VAL_NATI)
2705 sp [-1].data.nati &= sp [0].data.i;
2707 sp [-1].data.i &= sp [0].data.i;
2709 else if (sp->type == VAL_I64)
2710 sp [-1].data.l &= sp [0].data.l;
2712 if (sp [-1].type == VAL_NATI)
2713 sp [-1].data.nati = (mono_i)sp [-1].data.nati & (mono_i)sp [0].data.nati;
2715 sp [-1].data.nati = (mono_i)sp [-1].data.i & (mono_i)sp [0].data.nati;
2716 sp [-1].type = VAL_NATI;
2723 if (sp->type == VAL_I32) {
2724 if (sp [-1].type == VAL_NATI)
2725 sp [-1].data.nati |= sp [0].data.i;
2727 sp [-1].data.i |= sp [0].data.i;
2729 else if (sp->type == VAL_I64)
2730 sp [-1].data.l |= sp [0].data.l;
2732 if (sp [-1].type == VAL_NATI)
2733 sp [-1].data.nati = (mono_i)sp [-1].data.nati | (mono_i)sp [0].data.nati;
2735 sp [-1].data.nati = (mono_i)sp [-1].data.i | (mono_i)sp [0].data.nati;
2736 sp [-1].type = VAL_NATI;
2743 if (sp->type == VAL_I32) {
2744 if (sp [-1].type == VAL_NATI)
2745 sp [-1].data.nati ^= sp [0].data.i;
2747 sp [-1].data.i ^= sp [0].data.i;
2749 else if (sp->type == VAL_I64)
2750 sp [-1].data.l ^= sp [0].data.l;
2752 if (sp [-1].type == VAL_NATI)
2753 sp [-1].data.nati = (mono_i)sp [-1].data.nati ^ (mono_i)sp [0].data.nati;
2755 sp [-1].data.nati = (mono_i)sp [-1].data.i ^ (mono_i)sp [0].data.nati;
2756 sp [-1].type = VAL_NATI;
2763 if (sp [-1].type == VAL_I32)
2764 sp [-1].data.i <<= GET_NATI (sp [0]);
2765 else if (sp [-1].type == VAL_I64)
2766 sp [-1].data.l <<= GET_NATI (sp [0]);
2768 sp [-1].data.nati <<= GET_NATI (sp [0]);
2773 if (sp [-1].type == VAL_I32)
2774 sp [-1].data.i >>= GET_NATI (sp [0]);
2775 else if (sp [-1].type == VAL_I64)
2776 sp [-1].data.l >>= GET_NATI (sp [0]);
2778 sp [-1].data.nati = ((mono_i)sp [-1].data.nati) >> GET_NATI (sp [0]);
2783 if (sp [-1].type == VAL_I32)
2784 sp [-1].data.i = (guint)sp [-1].data.i >> GET_NATI (sp [0]);
2785 else if (sp [-1].type == VAL_I64)
2786 sp [-1].data.l = (guint64)sp [-1].data.l >> GET_NATI (sp [0]);
2788 sp [-1].data.nati = ((mono_u)sp[-1].data.nati) >> GET_NATI (sp [0]);
2793 if (sp->type == VAL_I32)
2794 sp->data.i = - sp->data.i;
2795 else if (sp->type == VAL_I64)
2796 sp->data.l = - sp->data.l;
2797 else if (sp->type == VAL_DOUBLE)
2798 sp->data.f = - sp->data.f;
2799 else if (sp->type == VAL_NATI)
2800 sp->data.nati = - (mono_i)sp->data.nati;
2806 if (sp->type == VAL_I32)
2807 sp->data.i = ~ sp->data.i;
2808 else if (sp->type == VAL_I64)
2809 sp->data.l = ~ sp->data.l;
2810 else if (sp->type == VAL_NATI)
2811 sp->data.nati = ~ (mono_i)sp->data.p;
2814 CASE (CEE_CONV_U1) {
2816 switch (sp [-1].type) {
2818 sp [-1].data.i = (guint8)sp [-1].data.f;
2821 sp [-1].data.i = (guint8)sp [-1].data.l;
2826 sp [-1].data.i = (guint8)sp [-1].data.i;
2829 sp [-1].data.i = (guint8)sp [-1].data.nati;
2832 sp [-1].type = VAL_I32;
2835 CASE (CEE_CONV_I1) {
2837 switch (sp [-1].type) {
2839 sp [-1].data.i = (gint8)sp [-1].data.f;
2842 sp [-1].data.i = (gint8)sp [-1].data.l;
2847 sp [-1].data.i = (gint8)sp [-1].data.i;
2850 sp [-1].data.i = (gint8)sp [-1].data.nati;
2853 sp [-1].type = VAL_I32;
2856 CASE (CEE_CONV_U2) {
2858 switch (sp [-1].type) {
2860 sp [-1].data.i = (guint16)sp [-1].data.f;
2863 sp [-1].data.i = (guint16)sp [-1].data.l;
2868 sp [-1].data.i = (guint16)sp [-1].data.i;
2871 sp [-1].data.i = (guint16)sp [-1].data.nati;
2874 sp [-1].type = VAL_I32;
2877 CASE (CEE_CONV_I2) {
2879 switch (sp [-1].type) {
2881 sp [-1].data.i = (gint16)sp [-1].data.f;
2884 sp [-1].data.i = (gint16)sp [-1].data.l;
2889 sp [-1].data.i = (gint16)sp [-1].data.i;
2892 sp [-1].data.i = (gint16)sp [-1].data.nati;
2895 sp [-1].type = VAL_I32;
2898 CASE (CEE_CONV_U4) /* Fall through */
2899 #if SIZEOF_VOID_P == 4
2900 CASE (CEE_CONV_I) /* Fall through */
2901 CASE (CEE_CONV_U) /* Fall through */
2903 CASE (CEE_CONV_I4) {
2905 switch (sp [-1].type) {
2907 sp [-1].data.i = (gint32)sp [-1].data.f;
2910 sp [-1].data.i = (gint32)sp [-1].data.l;
2917 sp [-1].data.i = (gint32)sp [-1].data.p;
2920 sp [-1].type = VAL_I32;
2923 #if SIZEOF_VOID_P == 8
2924 CASE (CEE_CONV_I) /* Fall through */
2928 switch (sp [-1].type) {
2930 sp [-1].data.l = (gint64)sp [-1].data.f;
2937 sp [-1].data.l = (gint64)sp [-1].data.i;
2940 sp [-1].data.l = (gint64)sp [-1].data.nati;
2943 sp [-1].type = ip[-1] == CEE_CONV_I ? VAL_NATI : VAL_I64;
2945 CASE (CEE_CONV_R4) {
2947 switch (sp [-1].type) {
2949 sp [-1].data.f = (float)sp [-1].data.f;
2952 sp [-1].data.f = (float)sp [-1].data.l;
2957 sp [-1].data.f = (float)sp [-1].data.i;
2960 sp [-1].data.f = (float)sp [-1].data.nati;
2963 sp [-1].type = VAL_DOUBLE;
2966 CASE (CEE_CONV_R8) {
2968 switch (sp [-1].type) {
2970 sp [-1].data.f = (double)sp [-1].data.f;
2973 sp [-1].data.f = (double)sp [-1].data.l;
2978 sp [-1].data.f = (double)sp [-1].data.i;
2981 sp [-1].data.f = (double)sp [-1].data.nati;
2984 sp [-1].type = VAL_DOUBLE;
2987 #if SIZEOF_VOID_P == 8
2988 CASE (CEE_CONV_U) /* Fall through */
2993 switch (sp [-1].type){
2995 sp [-1].data.l = (guint64)sp [-1].data.f;
3002 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3005 sp [-1].data.l = (guint64) sp [-1].data.nati;
3008 sp [-1].type = ip[-1] == CEE_CONV_U ? VAL_NATI : VAL_I64;
3013 vtklass = mono_class_get (image, read32 (ip));
3016 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
3025 token = read32 (ip);
3028 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3029 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3031 c = mono_class_get (image, token);
3033 addr = sp [-1].data.vt;
3034 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
3035 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
3043 str_index = mono_metadata_token_index (read32 (ip));
3046 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
3047 o = (MonoObject *)mono_string_new_wrapper(
3048 mono_method_get_wrapper_data (frame->method, str_index));
3051 o = (MonoObject*)mono_ldstr (domain, image, str_index);
3060 MonoClass *newobj_class;
3061 MonoMethodSignature *csig;
3062 stackval valuetype_this;
3063 stackval *endsp = sp;
3070 token = read32 (ip);
3073 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3074 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
3076 child_frame.method = mono_get_method (image, token, NULL);
3077 if (!child_frame.method)
3078 THROW_EX (mono_get_exception_missing_method (), ip -5);
3080 csig = child_frame.method->signature;
3081 newobj_class = child_frame.method->klass;
3082 /*if (profiling_classes) {
3083 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3085 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3089 if (newobj_class->parent == mono_defaults.array_class) {
3090 sp -= csig->param_count;
3091 o = ves_array_create (domain, newobj_class, csig, sp);
3092 goto array_constructed;
3096 * First arg is the object.
3098 if (newobj_class->valuetype) {
3100 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
3101 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
3102 zero = valuetype_this.data.vt;
3103 child_frame.obj = valuetype_this.data.vt;
3105 memset (&valuetype_this, 0, sizeof (stackval));
3106 zero = &valuetype_this;
3107 child_frame.obj = &valuetype_this;
3109 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
3111 if (newobj_class != mono_defaults.string_class) {
3112 o = mono_object_new (domain, newobj_class);
3113 child_frame.obj = o;
3115 child_frame.retval = &retval;
3119 if (csig->param_count) {
3120 sp -= csig->param_count;
3121 child_frame.stack_args = sp;
3123 child_frame.stack_args = NULL;
3126 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3128 child_frame.ip = NULL;
3129 child_frame.ex = NULL;
3130 child_frame.ex_handler = NULL;
3132 ves_exec_method_with_context (&child_frame, context);
3134 context->current_frame = frame;
3136 while (endsp > sp) {
3141 if (child_frame.ex) {
3143 * An exception occurred, need to run finally, fault and catch handlers..
3145 frame->ex = child_frame.ex;
3146 goto handle_finally;
3149 * a constructor returns void, but we need to return the object we created
3152 if (newobj_class->valuetype && !newobj_class->enumtype) {
3153 *sp = valuetype_this;
3154 } else if (newobj_class == mono_defaults.string_class) {
3163 CASE (CEE_CASTCLASS) /* Fall through */
3168 int do_isinst = *ip == CEE_ISINST;
3171 token = read32 (ip);
3172 c = mono_class_get (image, token);
3174 g_assert (sp [-1].type == VAL_OBJ);
3176 if ((o = sp [-1].data.p)) {
3177 if (!mono_object_isinst (o, c)) {
3179 sp [-1].data.p = NULL;
3181 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3187 CASE (CEE_CONV_R_UN)
3189 switch (sp [-1].type) {
3193 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3198 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3201 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
3204 sp [-1].type = VAL_DOUBLE;
3207 CASE (CEE_UNUSED1) ves_abort(); BREAK;
3214 token = read32 (ip);
3216 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3217 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3219 c = mono_class_get (image, token);
3223 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3225 if (!(mono_object_isinst (o, c) ||
3226 ((o->vtable->klass->rank == 0) &&
3227 (o->vtable->klass->element_class == c->element_class))))
3228 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3230 sp [-1].type = VAL_MP;
3231 sp [-1].data.p = (char *)o + sizeof (MonoObject);
3238 frame->ex_handler = NULL;
3240 sp->data.p = mono_get_exception_null_reference ();
3241 THROW_EX ((MonoException *)sp->data.p, ip);
3243 CASE (CEE_LDFLDA) /* Fall through */
3246 MonoClassField *field;
3248 int load_addr = *ip == CEE_LDFLDA;
3251 if (!sp [-1].data.p)
3252 THROW_EX (mono_get_exception_null_reference (), ip);
3255 token = read32 (ip);
3256 field = rtd->field_info[token].field;
3259 if (sp [-1].type == VAL_OBJ) {
3260 obj = sp [-1].data.p;
3261 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3262 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3263 addr = mono_load_remote_field (obj, klass, field, NULL);
3265 addr = (char*)obj + field->offset;
3268 obj = sp [-1].data.vt;
3269 addr = (char*)obj + field->offset - sizeof (MonoObject);
3273 sp [-1].type = VAL_MP;
3274 sp [-1].data.p = addr;
3276 vt_alloc (field->type, &sp [-1], FALSE);
3277 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3283 MonoClassField *field;
3284 guint32 token, offset;
3289 THROW_EX (mono_get_exception_null_reference (), ip);
3292 token = read32 (ip);
3293 field = rtd->field_info[token].field;
3296 if (sp [0].type == VAL_OBJ) {
3297 obj = sp [0].data.p;
3299 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3300 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3301 mono_store_remote_field (obj, klass, field, &sp [1].data);
3303 offset = field->offset;
3304 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3308 obj = sp [0].data.vt;
3309 offset = field->offset - sizeof (MonoObject);
3310 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3316 CASE (CEE_LDSFLD) /* Fall through */
3317 CASE (CEE_LDSFLDA) {
3319 MonoClassField *field;
3321 int load_addr = *ip == CEE_LDSFLDA;
3325 token = read32 (ip);
3326 field = rtd->field_info[token].field;
3329 vt = mono_class_vtable (domain, field->parent);
3330 if (!vt->initialized)
3331 mono_runtime_class_init (vt);
3333 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3334 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3336 addr = (char*)(vt->data) + field->offset;
3342 vt_alloc (field->type, sp, FALSE);
3343 stackval_from_data (field->type, sp, addr, FALSE);
3350 MonoClassField *field;
3355 token = read32 (ip);
3356 field = rtd->field_info[token].field;
3360 vt = mono_class_vtable (domain, field->parent);
3361 if (!vt->initialized)
3362 mono_runtime_class_init (vt);
3364 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3365 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3367 addr = (char*)(vt->data) + field->offset;
3369 stackval_to_data (field->type, sp, addr, FALSE);
3376 vtklass = mono_class_get (image, read32 (ip));
3381 * LAMESPEC: According to the spec, the stack should contain a
3382 * pointer to a value type. In reality, it can contain anything.
3384 if (sp [1].type == VAL_VALUET)
3385 memcpy (sp [0].data.p, sp [1].data.vt, mono_class_value_size (vtklass, NULL));
3387 memcpy (sp [0].data.p, &sp [1].data, mono_class_value_size (vtklass, NULL));
3390 #if SIZEOF_VOID_P == 8
3391 CASE (CEE_CONV_OVF_I_UN)
3393 CASE (CEE_CONV_OVF_I8_UN) {
3394 switch (sp [-1].type) {
3396 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
3397 THROW_EX (mono_get_exception_overflow (), ip);
3398 sp [-1].data.l = (guint64)sp [-1].data.f;
3405 /* Can't overflow */
3406 sp [-1].data.l = (guint64)sp [-1].data.i;
3409 sp [-1].data.l = (guint64)sp [-1].data.nati;
3412 sp [-1].type = VAL_I64;
3416 #if SIZEOF_VOID_P == 8
3417 CASE (CEE_CONV_OVF_U_UN)
3419 CASE (CEE_CONV_OVF_U8_UN) {
3420 switch (sp [-1].type) {
3422 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
3423 THROW_EX (mono_get_exception_overflow (), ip);
3424 sp [-1].data.l = (guint64)sp [-1].data.f;
3432 /* Can't overflow */
3433 sp [-1].data.l = (guint64)sp [-1].data.i;
3436 /* Can't overflow */
3437 sp [-1].data.l = (guint64)sp [-1].data.nati;
3440 sp [-1].type = VAL_I64;
3444 #if SIZEOF_VOID_P == 4
3445 CASE (CEE_CONV_OVF_I_UN)
3446 CASE (CEE_CONV_OVF_U_UN)
3448 CASE (CEE_CONV_OVF_I1_UN)
3449 CASE (CEE_CONV_OVF_I2_UN)
3450 CASE (CEE_CONV_OVF_I4_UN)
3451 CASE (CEE_CONV_OVF_U1_UN)
3452 CASE (CEE_CONV_OVF_U2_UN)
3453 CASE (CEE_CONV_OVF_U4_UN) {
3455 switch (sp [-1].type) {
3457 if (sp [-1].data.f <= -1.0)
3458 THROW_EX (mono_get_exception_overflow (), ip);
3459 value = (guint64)sp [-1].data.f;
3462 value = (guint64)sp [-1].data.l;
3467 value = (guint64)sp [-1].data.i;
3470 value = (guint64)sp [-1].data.nati;
3474 case CEE_CONV_OVF_I1_UN:
3476 THROW_EX (mono_get_exception_overflow (), ip);
3477 sp [-1].data.i = value;
3478 sp [-1].type = VAL_I32;
3480 case CEE_CONV_OVF_I2_UN:
3482 THROW_EX (mono_get_exception_overflow (), ip);
3483 sp [-1].data.i = value;
3484 sp [-1].type = VAL_I32;
3486 #if SIZEOF_VOID_P == 4
3487 case CEE_CONV_OVF_I_UN: /* Fall through */
3489 case CEE_CONV_OVF_I4_UN:
3490 if (value > MYGUINT32_MAX)
3491 THROW_EX (mono_get_exception_overflow (), ip);
3492 sp [-1].data.i = value;
3493 sp [-1].type = VAL_I32;
3495 case CEE_CONV_OVF_U1_UN:
3497 THROW_EX (mono_get_exception_overflow (), ip);
3498 sp [-1].data.i = value;
3499 sp [-1].type = VAL_I32;
3501 case CEE_CONV_OVF_U2_UN:
3503 THROW_EX (mono_get_exception_overflow (), ip);
3504 sp [-1].data.i = value;
3505 sp [-1].type = VAL_I32;
3507 #if SIZEOF_VOID_P == 4
3508 case CEE_CONV_OVF_U_UN: /* Fall through */
3510 case CEE_CONV_OVF_U4_UN:
3511 if (value > 4294967295U)
3512 THROW_EX (mono_get_exception_overflow (), ip);
3513 sp [-1].data.i = value;
3514 sp [-1].type = VAL_I32;
3517 g_assert_not_reached ();
3527 token = read32 (ip);
3529 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3530 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3532 class = mono_class_get (image, token);
3533 g_assert (class != NULL);
3535 sp [-1].type = VAL_OBJ;
3536 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3537 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3539 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3540 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3542 /* need to vt_free (sp); */
3554 token = read32 (ip);
3556 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3557 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3559 class = mono_class_get (image, token);
3561 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3564 sp [-1].type = VAL_OBJ;
3566 /*if (profiling_classes) {
3567 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3569 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3579 g_assert (sp [-1].type == VAL_OBJ);
3583 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3585 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3587 sp [-1].type = VAL_I32;
3588 sp [-1].data.i = mono_array_length (o);
3592 CASE (CEE_LDELEMA) {
3594 guint32 esize, token;
3598 token = read32 (ip);
3602 g_assert (sp [0].type == VAL_OBJ);
3605 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3607 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3608 if (aindex >= mono_array_length (o))
3609 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3611 /* check the array element corresponds to token */
3612 esize = mono_array_element_size (o->obj.vtable->klass);
3615 sp->data.p = mono_array_addr_with_size (o, esize, aindex);
3620 CASE (CEE_LDELEM_I1) /* fall through */
3621 CASE (CEE_LDELEM_U1) /* fall through */
3622 CASE (CEE_LDELEM_I2) /* fall through */
3623 CASE (CEE_LDELEM_U2) /* fall through */
3624 CASE (CEE_LDELEM_I4) /* fall through */
3625 CASE (CEE_LDELEM_U4) /* fall through */
3626 CASE (CEE_LDELEM_I8) /* fall through */
3627 CASE (CEE_LDELEM_I) /* fall through */
3628 CASE (CEE_LDELEM_R4) /* fall through */
3629 CASE (CEE_LDELEM_R8) /* fall through */
3630 CASE (CEE_LDELEM_REF) {
3636 g_assert (sp [0].type == VAL_OBJ);
3639 THROW_EX (mono_get_exception_null_reference (), ip);
3641 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3643 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3644 if (aindex >= mono_array_length (o))
3645 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3648 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3652 sp [0].data.i = mono_array_get (o, gint8, aindex);
3653 sp [0].type = VAL_I32;
3656 sp [0].data.i = mono_array_get (o, guint8, aindex);
3657 sp [0].type = VAL_I32;
3660 sp [0].data.i = mono_array_get (o, gint16, aindex);
3661 sp [0].type = VAL_I32;
3664 sp [0].data.i = mono_array_get (o, guint16, aindex);
3665 sp [0].type = VAL_I32;
3668 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3669 sp [0].type = VAL_NATI;
3672 sp [0].data.i = mono_array_get (o, gint32, aindex);
3673 sp [0].type = VAL_I32;
3676 sp [0].data.i = mono_array_get (o, guint32, aindex);
3677 sp [0].type = VAL_I32;
3680 sp [0].data.l = mono_array_get (o, guint64, aindex);
3681 sp [0].type = VAL_I64;
3684 sp [0].data.f = mono_array_get (o, float, aindex);
3685 sp [0].type = VAL_DOUBLE;
3688 sp [0].data.f = mono_array_get (o, double, aindex);
3689 sp [0].type = VAL_DOUBLE;
3691 case CEE_LDELEM_REF:
3692 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3693 sp [0].type = VAL_OBJ;
3703 CASE (CEE_STELEM_I) /* fall through */
3704 CASE (CEE_STELEM_I1) /* fall through */
3705 CASE (CEE_STELEM_I2) /* fall through */
3706 CASE (CEE_STELEM_I4) /* fall through */
3707 CASE (CEE_STELEM_I8) /* fall through */
3708 CASE (CEE_STELEM_R4) /* fall through */
3709 CASE (CEE_STELEM_R8) /* fall through */
3710 CASE (CEE_STELEM_REF) {
3717 g_assert (sp [0].type == VAL_OBJ);
3720 THROW_EX (mono_get_exception_null_reference (), ip);
3722 ac = o->obj.vtable->klass;
3723 g_assert (MONO_CLASS_IS_ARRAY (ac));
3725 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3726 if (aindex >= mono_array_length (o))
3727 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3731 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3734 mono_array_set (o, gint8, aindex, sp [2].data.i);
3737 mono_array_set (o, gint16, aindex, sp [2].data.i);
3740 mono_array_set (o, gint32, aindex, sp [2].data.i);
3743 mono_array_set (o, gint64, aindex, sp [2].data.l);
3746 mono_array_set (o, float, aindex, sp [2].data.f);
3749 mono_array_set (o, double, aindex, sp [2].data.f);
3751 case CEE_STELEM_REF:
3752 g_assert (sp [2].type == VAL_OBJ);
3753 if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
3754 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3755 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3766 CASE (CEE_UNBOX_ANY)
3779 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3781 #if SIZEOF_VOID_P == 4
3782 CASE (CEE_CONV_OVF_I)
3783 CASE (CEE_CONV_OVF_U)
3785 CASE (CEE_CONV_OVF_I1)
3786 CASE (CEE_CONV_OVF_I2)
3787 CASE (CEE_CONV_OVF_I4)
3788 CASE (CEE_CONV_OVF_U1)
3789 CASE (CEE_CONV_OVF_U2)
3790 CASE (CEE_CONV_OVF_U4) {
3792 switch (sp [-1].type) {
3794 value = (gint64)sp [-1].data.f;
3797 value = (gint64)sp [-1].data.l;
3802 value = (gint64)sp [-1].data.i;
3805 value = (gint64)sp [-1].data.nati;
3809 case CEE_CONV_OVF_I1:
3810 if (value < -128 || value > 127)
3811 THROW_EX (mono_get_exception_overflow (), ip);
3812 sp [-1].data.i = value;
3813 sp [-1].type = VAL_I32;
3815 case CEE_CONV_OVF_I2:
3816 if (value < -32768 || value > 32767)
3817 THROW_EX (mono_get_exception_overflow (), ip);
3818 sp [-1].data.i = value;
3819 sp [-1].type = VAL_I32;
3821 #if SIZEOF_VOID_P == 4
3822 case CEE_CONV_OVF_I: /* Fall through */
3824 case CEE_CONV_OVF_I4:
3825 if (value < MYGINT32_MIN || value > MYGINT32_MAX)
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_U1:
3831 if (value < 0 || value > 255)
3832 THROW_EX (mono_get_exception_overflow (), ip);
3833 sp [-1].data.i = value;
3834 sp [-1].type = VAL_I32;
3836 case CEE_CONV_OVF_U2:
3837 if (value < 0 || value > 65535)
3838 THROW_EX (mono_get_exception_overflow (), ip);
3839 sp [-1].data.i = value;
3840 sp [-1].type = VAL_I32;
3842 #if SIZEOF_VOID_P == 4
3843 case CEE_CONV_OVF_U: /* Fall through */
3845 case CEE_CONV_OVF_U4:
3846 if (value < 0 || value > MYGUINT32_MAX)
3847 THROW_EX (mono_get_exception_overflow (), ip);
3848 sp [-1].data.i = value;
3849 sp [-1].type = VAL_I32;
3852 g_assert_not_reached ();
3858 #if SIZEOF_VOID_P == 8
3859 CASE (CEE_CONV_OVF_I)
3861 CASE (CEE_CONV_OVF_I8)
3862 /* FIXME: handle other cases */
3863 if (sp [-1].type == VAL_I32) {
3864 sp [-1].data.l = (guint64)sp [-1].data.i;
3865 sp [-1].type = VAL_I64;
3866 } else if(sp [-1].type == VAL_I64) {
3867 /* defined as NOP */
3874 #if SIZEOF_VOID_P == 8
3875 CASE (CEE_CONV_OVF_U)
3877 CASE (CEE_CONV_OVF_U8)
3878 /* FIXME: handle other cases */
3879 if (sp [-1].type == VAL_I32) {
3880 sp [-1].data.l = (guint64) sp [-1].data.i;
3881 sp [-1].type = VAL_I64;
3882 } else if(sp [-1].type == VAL_I64) {
3883 /* defined as NOP */
3895 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3896 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3898 if (!finite(sp [-1].data.f))
3899 THROW_EX (mono_get_exception_arithmetic (), ip);
3902 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3903 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3904 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3913 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3914 CASE (CEE_LDTOKEN) {
3916 MonoClass *handle_class;
3918 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3920 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3921 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3927 /* FIXME: check overflow */
3928 if (sp->type == VAL_I32) {
3929 if (sp [-1].type == VAL_I32) {
3930 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3931 THROW_EX (mono_get_exception_overflow (), ip);
3932 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)sp [0].data.i;
3934 if (CHECK_ADD_OVERFLOW_NAT (sp [-1].data.nati, (mono_i)sp [0].data.i))
3935 THROW_EX (mono_get_exception_overflow (), ip);
3936 sp [-1].data.nati = sp [-1].data.nati + (mono_i)sp [0].data.i;
3938 } else if (sp->type == VAL_I64) {
3939 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3940 THROW_EX (mono_get_exception_overflow (), ip);
3941 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3942 } else if (sp->type == VAL_DOUBLE)
3943 sp [-1].data.f += sp [0].data.f;
3945 char *p = sp [-1].data.p;
3946 p += GET_NATI (sp [0]);
3951 CASE (CEE_ADD_OVF_UN)
3953 /* FIXME: check overflow, make unsigned */
3954 if (sp->type == VAL_I32) {
3955 if (sp [-1].type == VAL_I32) {
3956 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
3957 THROW_EX (mono_get_exception_overflow (), ip);
3958 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)sp [0].data.i;
3960 if (CHECK_ADD_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
3961 THROW_EX (mono_get_exception_overflow (), ip);
3962 sp [-1].data.nati = (mono_u)sp [-1].data.nati + (mono_u)sp [0].data.i;
3964 } else if (sp->type == VAL_I64) {
3965 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3966 THROW_EX (mono_get_exception_overflow (), ip);
3967 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3968 } else if (sp->type == VAL_DOUBLE)
3969 sp [-1].data.f += sp [0].data.f;
3971 char *p = sp [-1].data.p;
3972 p += GET_NATI (sp [0]);
3979 /* FIXME: check overflow */
3980 if (sp->type == VAL_I32) {
3981 if (sp [-1].type == VAL_NATI) {
3982 if (CHECK_MUL_OVERFLOW_NAT (sp [-1].data.nati, sp [0].data.i))
3983 THROW_EX (mono_get_exception_overflow (), ip);
3984 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
3985 sp [-1].type = VAL_NATI;
3987 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3988 THROW_EX (mono_get_exception_overflow (), ip);
3989 sp [-1].data.i *= sp [0].data.i;
3992 else if (sp->type == VAL_I64) {
3993 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3994 THROW_EX (mono_get_exception_overflow (), ip);
3995 sp [-1].data.l *= sp [0].data.l;
3997 else if (sp->type == VAL_DOUBLE)
3998 sp [-1].data.f *= sp [0].data.f;
4003 CASE (CEE_MUL_OVF_UN)
4005 /* FIXME: check overflow, make unsigned */
4006 if (sp->type == VAL_I32) {
4007 if (sp [-1].type == VAL_NATI) {
4008 if (CHECK_MUL_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
4009 THROW_EX (mono_get_exception_overflow (), ip);
4010 sp [-1].data.nati = (mono_u)sp [-1].data.nati * (mono_u)sp [0].data.i;
4011 sp [-1].type = VAL_NATI;
4013 if (CHECK_MUL_OVERFLOW_UN ((guint32)sp [-1].data.i, (guint32)sp [0].data.i))
4014 THROW_EX (mono_get_exception_overflow (), ip);
4015 sp [-1].data.i *= sp [0].data.i;
4018 else if (sp->type == VAL_I64) {
4019 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4020 THROW_EX (mono_get_exception_overflow (), ip);
4021 sp [-1].data.l *= sp [0].data.l;
4023 else if (sp->type == VAL_DOUBLE)
4024 sp [-1].data.f *= sp [0].data.f;
4031 /* FIXME: handle undeflow/unsigned */
4032 /* should probably consider the pointers as unsigned */
4033 if (sp->type == VAL_I32) {
4034 if (sp [-1].type == VAL_I32) {
4035 if (CHECK_SUB_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4036 THROW_EX (mono_get_exception_overflow (), ip);
4037 sp [-1].data.i -= sp [0].data.i;
4039 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4040 sp [-1].type = VAL_NATI;
4043 else if (sp->type == VAL_I64) {
4044 if (CHECK_SUB_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4045 THROW_EX (mono_get_exception_overflow (), ip);
4046 sp [-1].data.l -= sp [0].data.l;
4048 else if (sp->type == VAL_DOUBLE)
4049 sp [-1].data.f -= sp [0].data.f;
4051 if (sp [-1].type == VAL_I32) {
4052 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4053 sp [-1].type = sp [0].type;
4055 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4059 CASE (CEE_SUB_OVF_UN)
4061 /* FIXME: handle undeflow/unsigned */
4062 /* should probably consider the pointers as unsigned */
4063 if (sp->type == VAL_I32) {
4064 if (sp [-1].type == VAL_I32) {
4065 if (CHECK_SUB_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
4066 THROW_EX (mono_get_exception_overflow (), ip);
4067 sp [-1].data.i -= sp [0].data.i;
4069 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4070 sp [-1].type = VAL_NATI;
4073 else if (sp->type == VAL_I64) {
4074 if (CHECK_SUB_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4075 THROW_EX (mono_get_exception_overflow (), ip);
4076 sp [-1].data.l -= sp [0].data.l;
4078 else if (sp->type == VAL_DOUBLE)
4079 sp [-1].data.f -= sp [0].data.f;
4081 if (sp [-1].type == VAL_I32) {
4082 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4083 sp [-1].type = sp [0].type;
4085 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4089 CASE (CEE_ENDFINALLY)
4091 ip = finally_ips->data;
4092 finally_ips = g_slist_remove (finally_ips, ip);
4099 CASE (CEE_LEAVE) /* Fall through */
4101 while (sp > frame->stack) {
4106 if (*ip == CEE_LEAVE_S) {
4108 ip += (signed char) *ip;
4112 ip += (gint32) read32 (ip);
4116 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - header->code)) {
4117 frame->ex_handler = NULL;
4120 goto handle_finally;
4125 case CEE_MONO_FUNC1: {
4126 MonoMarshalConv conv;
4135 sp->type = VAL_NATI;
4138 case MONO_MARSHAL_CONV_STR_LPWSTR:
4139 sp->data.p = mono_string_to_utf16 (sp->data.p);
4141 case MONO_MARSHAL_CONV_LPSTR_STR:
4142 sp->data.p = mono_string_new_wrapper (sp->data.p);
4144 case MONO_MARSHAL_CONV_STR_LPTSTR:
4145 case MONO_MARSHAL_CONV_STR_LPSTR:
4146 sp->data.p = mono_string_to_utf8 (sp->data.p);
4148 case MONO_MARSHAL_CONV_STR_BSTR:
4149 sp->data.p = mono_string_to_bstr (sp->data.p);
4151 case MONO_MARSHAL_CONV_STR_TBSTR:
4152 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4153 sp->data.p = mono_string_to_ansibstr (sp->data.p);
4155 case MONO_MARSHAL_CONV_SB_LPSTR:
4156 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
4158 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4159 sp->data.p = mono_array_to_savearray (sp->data.p);
4161 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4162 sp->data.p = mono_array_to_lparray (sp->data.p);
4164 case MONO_MARSHAL_CONV_DEL_FTN:
4165 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
4167 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4168 sp->data.p = mono_marshal_string_array (sp->data.p);
4170 case MONO_MARSHAL_CONV_LPWSTR_STR:
4171 sp->data.p = mono_string_from_utf16 (sp->data.p);
4174 fprintf(stderr, "MONO_FUNC1 %d", conv);
4175 g_assert_not_reached ();
4180 case CEE_MONO_PROC2: {
4181 MonoMarshalConv conv;
4189 case MONO_MARSHAL_CONV_LPSTR_SB:
4190 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
4192 case MONO_MARSHAL_FREE_ARRAY:
4193 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
4196 g_assert_not_reached ();
4200 case CEE_MONO_PROC3: {
4201 MonoMarshalConv conv;
4209 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4210 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4212 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4213 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4216 g_assert_not_reached ();
4220 case CEE_MONO_VTADDR: {
4223 sp [-1].type = VAL_MP;
4227 case CEE_MONO_LDPTR: {
4231 token = read32 (ip);
4234 sp->type = VAL_NATI;
4235 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
4239 case CEE_MONO_FREE: {
4243 g_free (sp->data.p);
4246 case CEE_MONO_OBJADDR: {
4253 case CEE_MONO_NEWOBJ: {
4258 token = read32 (ip);
4261 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4262 sp->data.p = mono_object_new (domain, class);
4266 case CEE_MONO_RETOBJ: {
4271 token = read32 (ip);
4276 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4278 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
4280 if (sp > frame->stack)
4281 g_warning ("more values on stack: %d", sp-frame->stack);
4284 case CEE_MONO_LDNATIVEOBJ: {
4289 token = read32 (ip);
4292 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4293 g_assert(class->valuetype);
4295 sp [-1].type = VAL_MP;
4300 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
4331 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
4333 * Note: Exceptions thrown when executing a prefixed opcode need
4334 * to take into account the number of prefix bytes (usually the
4335 * throw point is just (ip - n_prefix_bytes).
4340 case CEE_ARGLIST: ves_abort(); break;
4346 if (sp->type == VAL_I32)
4347 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
4348 else if (sp->type == VAL_I64)
4349 result = sp [0].data.l == sp [1].data.l;
4350 else if (sp->type == VAL_DOUBLE) {
4351 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4354 result = sp [0].data.f == sp [1].data.f;
4356 result = sp [0].data.nati == GET_NATI (sp [1]);
4358 sp->data.i = result;
4368 if (sp->type == VAL_I32)
4369 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
4370 else if (sp->type == VAL_I64)
4371 result = sp [0].data.l > sp [1].data.l;
4372 else if (sp->type == VAL_DOUBLE) {
4373 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4376 result = sp [0].data.f > sp [1].data.f;
4378 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
4380 sp->data.i = result;
4390 if (sp->type == VAL_I32)
4391 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
4392 else if (sp->type == VAL_I64)
4393 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
4394 else if (sp->type == VAL_DOUBLE)
4395 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4396 sp[0].data.f > sp[1].data.f;
4398 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
4400 sp->data.i = result;
4410 if (sp->type == VAL_I32)
4411 result = (mono_i)sp [0].data.i < (mono_i)GET_NATI (sp [1]);
4412 else if (sp->type == VAL_I64)
4413 result = sp [0].data.l < sp [1].data.l;
4414 else if (sp->type == VAL_DOUBLE) {
4415 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4418 result = sp [0].data.f < sp [1].data.f;
4420 result = (mono_i)sp [0].data.nati < (mono_i)GET_NATI (sp [1]);
4422 sp->data.i = result;
4432 if (sp->type == VAL_I32)
4433 result = (mono_u)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
4434 else if (sp->type == VAL_I64)
4435 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
4436 else if (sp->type == VAL_DOUBLE)
4437 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4438 sp[0].data.f < sp[1].data.f;
4440 result = (mono_u)sp [0].data.nati < (mono_u)GET_NATI (sp [1]);
4442 sp->data.i = result;
4448 case CEE_LDVIRTFTN: {
4449 int virtual = *ip == CEE_LDVIRTFTN;
4453 token = read32 (ip);
4456 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
4457 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
4459 m = mono_get_method (image, token, NULL);
4462 THROW_EX (mono_get_exception_missing_method (), ip - 5);
4466 THROW_EX (mono_get_exception_null_reference (), ip - 5);
4468 m = get_virtual_method (domain, m, sp);
4472 * This prevents infinite cycles since the wrapper contains
4475 if (frame->method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
4476 if (m && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4477 m = mono_marshal_get_synchronized_wrapper (m);
4479 sp->type = VAL_NATI;
4480 sp->data.p = mono_create_method_pointer (m);
4484 case CEE_UNUSED56: ves_abort(); break;
4488 arg_pos = read16 (ip);
4490 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
4491 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4500 sp->data.vt = ARG_POS (anum);
4508 arg_pos = read16 (ip);
4511 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4518 loc_pos = read16 (ip);
4520 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4521 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4530 loc_pos = read16 (ip);
4532 t = LOCAL_TYPE (header, loc_pos);
4533 sp->data.vt = LOCAL_POS (loc_pos);
4543 loc_pos = read16 (ip);
4546 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4552 if (sp != frame->stack)
4553 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4555 sp->data.p = alloca (sp->data.i);
4559 case CEE_UNUSED57: ves_abort(); break;
4560 case CEE_ENDFILTER: ves_abort(); break;
4561 case CEE_UNALIGNED_:
4563 unaligned_address = 1;
4567 volatile_address = 1;
4578 token = read32 (ip);
4581 class = mono_class_get (image, token);
4584 g_assert (sp->type == VAL_TP || sp->type == VAL_MP);
4585 memset (sp->data.vt, 0, mono_class_value_size (class, NULL));
4588 case CEE_CONSTRAINED_: {
4590 /* FIXME: implement */
4592 token = read32 (ip);
4598 if (!sp [0].data.p || !sp [1].data.p)
4599 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4601 /* FIXME: value and size may be int64... */
4602 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4607 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4609 /* FIXME: value and size may be int64... */
4610 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4613 /* FIXME: implement */
4618 * need to clarify what this should actually do:
4619 * start the search from the last found handler in
4620 * this method or continue in the caller or what.
4621 * Also, do we need to run finally/fault handlers after a retrow?
4622 * Well, this implementation will follow the usual search
4623 * for an handler, considering the current ip as throw spot.
4624 * We need to NULL frame->ex_handler for the later code to
4625 * actually run the new found handler.
4627 frame->ex_handler = NULL;
4628 THROW_EX (frame->ex, ip - 1);
4630 case CEE_UNUSED: ves_abort(); break;
4635 token = read32 (ip);
4637 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4638 MonoType *type = mono_type_create_from_typespec (image, token);
4639 sp->data.i = mono_type_size (type, &align);
4641 MonoClass *szclass = mono_class_get (image, token);
4642 mono_class_init (szclass);
4643 if (!szclass->valuetype)
4644 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4645 sp->data.i = mono_class_value_size (szclass, &align);
4651 case CEE_REFANYTYPE: ves_abort(); break;
4653 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4660 g_assert_not_reached ();
4662 * Exception handling code.
4663 * The exception object is stored in frame->ex.
4670 MonoInvocation *inv;
4671 MonoMethodHeader *hd;
4672 MonoExceptionClause *clause;
4678 g_print ("* Handling exception '%s' at IL_%04x\n", frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, frame->ip - header->code);
4680 if (die_on_exception)
4683 if (frame->ex == quit_exception)
4684 goto handle_finally;
4686 for (inv = frame; inv; inv = inv->parent) {
4687 if (inv->method == NULL)
4689 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4691 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4693 hd = ((MonoMethodNormal*)inv->method)->header;
4694 ip_offset = inv->ip - hd->code;
4695 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4696 for (i = 0; i < hd->num_clauses; ++i) {
4697 clause = &hd->clauses [i];
4698 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4699 if (!clause->flags) {
4700 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4702 * OK, we found an handler, now we need to execute the finally
4703 * and fault blocks before branching to the handler code.
4705 inv->ex_handler = clause;
4708 g_print ("* Found handler at '%s'\n", inv->method->name);
4710 goto handle_finally;
4713 /* FIXME: handle filter clauses */
4720 * If we get here, no handler was found: print a stack trace.
4722 for (inv = frame; inv; inv = inv->parent) {
4723 if (inv->invoke_trap)
4724 goto handle_finally;
4727 ex_obj = (MonoObject*)frame->ex;
4728 mono_unhandled_exception (ex_obj);
4735 MonoExceptionClause *clause;
4736 GSList *old_list = finally_ips;
4740 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - header->code);
4742 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4743 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4746 ip_offset = frame->ip - header->code;
4748 if (endfinally_ip != NULL)
4749 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4750 for (i = 0; i < header->num_clauses; ++i)
4751 if (frame->ex_handler == &header->clauses [i])
4755 clause = &header->clauses [i];
4756 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code)))) {
4757 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4758 ip = header->code + clause->handler_offset;
4759 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4762 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4768 endfinally_ip = NULL;
4770 if (old_list != finally_ips && finally_ips) {
4771 ip = finally_ips->data;
4772 finally_ips = g_slist_remove (finally_ips, ip);
4773 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4778 * If an exception is set, we need to execute the fault handler, too,
4779 * otherwise, we continue normally.
4789 MonoExceptionClause *clause;
4793 g_print ("* Handle fault\n");
4795 ip_offset = frame->ip - header->code;
4796 for (i = 0; i < header->num_clauses; ++i) {
4797 clause = &header->clauses [i];
4798 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4799 ip = header->code + clause->handler_offset;
4802 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4808 * If the handler for the exception was found in this method, we jump
4809 * to it right away, otherwise we return and let the caller run
4810 * the finally, fault and catch blocks.
4811 * This same code should be present in the endfault opcode, but it
4812 * is corrently not assigned in the ECMA specs: LAMESPEC.
4814 if (frame->ex_handler) {
4817 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4819 ip = header->code + frame->ex_handler->handler_offset;
4822 sp->data.p = frame->ex;
4833 ves_exec_method (MonoInvocation *frame)
4835 ThreadContext *context = TlsGetValue (thread_context_id);
4836 ThreadContext context_struct;
4837 if (context == NULL) {
4838 context = &context_struct;
4839 context_struct.base_frame = frame;
4840 context_struct.current_frame = NULL;
4841 context_struct.current_env = NULL;
4842 context_struct.search_for_handler = 0;
4843 TlsSetValue (thread_context_id, context);
4846 frame->parent = context->current_frame;
4847 ves_exec_method_with_context(frame, context);
4849 if (context->current_env) {
4850 context->env_frame->ex = frame->ex;
4851 longjmp (*context->current_env, 1);
4854 mono_unhandled_exception ((MonoObject*)frame->ex);
4856 if (context->base_frame == frame)
4857 TlsSetValue (thread_context_id, NULL);
4859 context->current_frame = frame->parent;
4863 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4865 MonoImage *image = assembly->image;
4866 MonoCLIImageInfo *iinfo;
4868 MonoObject *exc = NULL;
4871 iinfo = image->image_info;
4872 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4874 g_error ("No entry point method found in %s", image->name);
4876 rval = mono_runtime_run_main (method, argc, argv, &exc);
4878 mono_unhandled_exception (exc);
4887 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4888 "Usage is: mint [options] executable args...\n\n", VERSION);
4890 "Runtime Debugging:\n"
4895 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4898 " --traceclassinit\n"
4901 " --debug method_name\n"
4907 " --config filename load the specified config file instead of the default\n"
4908 " --workers n maximum number of worker threads\n"
4915 test_load_class (MonoImage* image)
4917 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4921 for (i = 1; i <= t->rows; ++i) {
4922 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4923 mono_class_init (klass);
4928 static MonoException * segv_exception = NULL;
4931 segv_handler (int signum)
4933 signal (signum, segv_handler);
4934 mono_raise_exception (segv_exception);
4939 quit_handler (int signum)
4941 signal (signum, quit_handler);
4942 mono_raise_exception (quit_exception);
4946 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4947 MonoReflectionMethod **method,
4948 gint32 *iloffset, gint32 *native_offset,
4949 MonoString **file, gint32 *line, gint32 *column)
4962 *file = mono_string_new (mono_domain_get (), "unknown");
4968 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4976 int enable_debugging;
4982 static void main_thread_handler (gpointer user_data)
4984 MainThreadArgs *main_args=(MainThreadArgs *)user_data;
4985 MonoAssembly *assembly;
4988 if (main_args->enable_debugging)
4989 mono_debug_init (main_args->domain, MONO_DEBUG_FORMAT_MONO);
4991 assembly = mono_domain_assembly_open (main_args->domain,
4995 fprintf (stderr, "Can not open image %s\n", main_args->file);
4999 if (main_args->enable_debugging)
5000 mono_debug_init_2 (assembly);
5003 test_load_class (assembly->image);
5005 error = mono_verify_corlib ();
5007 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5010 segv_exception = mono_get_exception_null_reference ();
5011 segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
5012 signal (SIGSEGV, segv_handler);
5013 /* perhaps we should use a different class for this exception... */
5014 quit_exception = mono_get_exception_null_reference ();
5015 quit_exception->message = mono_string_new (main_args->domain, "Quit");
5016 signal (SIGINT, quit_handler);
5018 ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
5023 mono_runtime_install_handlers (void)
5025 /* FIXME: anything to do here? */
5029 quit_function (MonoDomain *domain, gpointer user_data)
5031 mono_profiler_shutdown ();
5033 mono_runtime_cleanup (domain);
5034 mono_domain_free (domain, TRUE);
5039 mono_interp_cleanup(MonoDomain *domain)
5041 quit_function (domain, NULL);
5045 mono_interp_exec(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
5047 return ves_exec (domain, assembly, argc, argv);
5051 mono_interp_init(const char *file)
5055 g_set_prgname (file);
5056 mono_set_rootdir ();
5058 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
5059 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
5061 g_thread_init (NULL);
5063 thread_context_id = TlsAlloc ();
5064 TlsSetValue (thread_context_id, NULL);
5065 InitializeCriticalSection(&calc_section);
5066 InitializeCriticalSection(&create_method_pointer_mutex);
5068 mono_install_compile_method (mono_create_method_pointer);
5069 mono_install_runtime_invoke (interp_mono_runtime_invoke);
5070 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
5072 mono_install_handler (interp_ex_handler);
5073 mono_install_stack_walk (interp_walk_stack);
5074 mono_runtime_install_cleanup (quit_function);
5076 domain = mono_init (file);
5077 #ifdef __hpux /* generates very big stack frames */
5078 mono_threads_set_default_stacksize(32*1024*1024);
5081 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
5082 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
5083 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
5085 mono_runtime_init (domain, NULL, NULL);
5091 mono_main (int argc, char *argv [])
5094 int retval = 0, i, ocount = 0;
5095 char *file, *config_file = NULL;
5096 int enable_debugging = FALSE;
5097 MainThreadArgs main_args;
5100 setlocale (LC_ALL, "");
5104 for (i = 1; i < argc && argv [i][0] == '-'; i++){
5105 if (strcmp (argv [i], "--trace") == 0)
5107 if (strcmp (argv [i], "--noptr") == 0)
5108 global_no_pointers = 1;
5109 if (strcmp (argv [i], "--traceops") == 0)
5111 if (strcmp (argv [i], "--dieonex") == 0) {
5112 die_on_exception = 1;
5113 enable_debugging = 1;
5115 if (strcmp (argv [i], "--print-vtable") == 0)
5116 mono_print_vtable = TRUE;
5117 if (strcmp (argv [i], "--profile") == 0)
5118 mono_profiler_load (NULL);
5119 if (strcmp (argv [i], "--opcode-count") == 0)
5121 if (strcmp (argv [i], "--config") == 0)
5122 config_file = argv [++i];
5123 if (strcmp (argv [i], "--workers") == 0) {
5124 mono_max_worker_threads = atoi (argv [++i]);
5125 if (mono_max_worker_threads < 1)
5126 mono_max_worker_threads = 1;
5128 if (strcmp (argv [i], "--help") == 0)
5131 if (strcmp (argv [i], "--debug") == 0) {
5132 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
5134 g_error ("Invalid method name '%s'", argv [i]);
5135 db_methods = g_list_append (db_methods, desc);
5145 domain = mono_interp_init(file);
5146 mono_config_parse (config_file);
5148 error = mono_verify_corlib ();
5150 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5154 error = mono_check_corlib_version ();
5156 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5157 fprintf (stderr, "Download a newer corlib at http://go-mono/daily.\n");
5161 main_args.domain=domain;
5162 main_args.file=file;
5163 main_args.argc=argc-i;
5164 main_args.argv=argv+i;
5165 main_args.enable_debugging=enable_debugging;
5167 mono_runtime_exec_managed_code (domain, main_thread_handler,
5170 quit_function (domain, NULL);
5172 /* Get the return value from System.Environment.ExitCode */
5173 retval=mono_environment_exitcode_get ();
5177 fprintf (stderr, "opcode count: %ld\n", opcode_count);
5178 fprintf (stderr, "fcall count: %ld\n", fcall_count);