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 get_native_wrapper(MonoMethod *method, ThreadContext *context)
1579 MonoMethod *wrapper;
1580 old_env = context->current_env;
1581 if (setjmp(env) != 0) {
1582 context->current_env = old_env;
1583 context->search_for_handler = 1;
1586 context->current_env = &env;
1587 wrapper = mono_marshal_get_native_wrapper (method);
1588 context->current_env = old_env;
1593 * Need to optimize ALU ops when natural int == int32
1595 * IDEA: if we maintain a stack of ip, sp to be checked
1596 * in the return opcode, we could inline simple methods that don't
1597 * use the stack or local variables....
1599 * The {,.S} versions of many opcodes can/should be merged to reduce code
1604 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
1606 MonoDomain *domain = mono_domain_get ();
1607 MonoInvocation child_frame;
1608 MonoMethodHeader *header;
1609 MonoMethodSignature *signature;
1611 GSList *finally_ips = NULL;
1612 const unsigned char *endfinally_ip = NULL;
1613 register const unsigned char *ip;
1614 register stackval *sp = NULL;
1615 MethodRuntimeData *rtd;
1616 void **args_pointers;
1617 gint tracing = global_tracing;
1618 unsigned char tail_recursion = 0;
1619 unsigned char unaligned_address = 0;
1620 unsigned char volatile_address = 0;
1621 vtallocation *vtalloc = NULL;
1622 MonoVTable *method_class_vt;
1626 frame->ip = ip = NULL;
1627 context->current_frame = frame;
1629 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1630 frame->method = get_native_wrapper (frame->method, context);
1631 if (frame->method == NULL)
1635 method_class_vt = mono_class_vtable (domain, frame->method->klass);
1636 if (!method_class_vt->initialized)
1637 mono_runtime_class_init (method_class_vt);
1638 signature = frame->method->signature;
1642 header = ((MonoMethodNormal *)frame->method)->header;
1644 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1645 if (!frame->method->addr) {
1646 /* assumes all internal calls with an array this are built in... */
1647 if (signature->hasthis && frame->method->klass->rank) {
1648 ves_runtime_method (frame, context);
1650 goto handle_exception;
1653 frame->method->addr = mono_lookup_internal_call (frame->method);
1655 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1656 frame->method->string_ctor, context);
1658 goto handle_exception;
1661 else if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1662 ves_runtime_method (frame, context);
1664 goto handle_exception;
1668 /*verify_method (frame->method);*/
1670 image = frame->method->klass->image;
1672 if (!frame->method->info)
1673 calc_offsets (image, frame->method);
1674 rtd = frame->method->info;
1677 * with alloca we get the expected huge performance gain
1678 * stackval *stack = g_new0(stackval, header->max_stack);
1680 g_assert (header->max_stack < 10000);
1681 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1683 if (header->num_locals) {
1684 g_assert (rtd->locals_size < 65536);
1685 frame->locals = alloca (rtd->locals_size);
1687 * yes, we do it unconditionally, because it needs to be done for
1688 * some cases anyway and checking for that would be even slower.
1690 memset (frame->locals, 0, rtd->locals_size);
1694 * Copy args from stack_args to args.
1696 if (signature->param_count || signature->hasthis) {
1698 int has_this = signature->hasthis;
1700 g_assert (rtd->args_size < 10000);
1701 frame->args = alloca (rtd->args_size);
1702 g_assert ((signature->param_count + has_this) < 1000);
1703 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1706 this_arg = args_pointers [0] = frame->args;
1707 *this_arg = frame->obj;
1709 for (i = 0; i < signature->param_count; ++i) {
1710 args_pointers [i + has_this] = frame->args + rtd->offsets [header->num_locals + has_this + i];
1711 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1715 child_frame.parent = frame;
1716 frame->child = &child_frame;
1723 * using while (ip < end) may result in a 15% performance drop,
1724 * but it may be useful for debug
1728 /*g_assert (sp >= stack);*/
1732 char *ins, *discode;
1733 if (sp > frame->stack) {
1734 ins = dump_stack (frame->stack, sp);
1736 ins = g_strdup ("");
1739 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1740 discode [strlen (discode) - 1] = 0; /* no \n */
1741 g_print ("(%u) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1753 G_BREAKPOINT (); /* this is not portable... */
1758 CASE (CEE_LDARG_3) {
1759 int n = (*ip)-CEE_LDARG_0;
1761 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1762 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1769 CASE (CEE_LDLOC_3) {
1770 int n = (*ip)-CEE_LDLOC_0;
1771 MonoType *vartype = LOCAL_TYPE (header, n);
1773 if (vartype->type == MONO_TYPE_I4) {
1775 sp->data.i = *(gint32*) LOCAL_POS (n);
1779 vt_alloc (vartype, sp, FALSE);
1780 stackval_from_data (vartype, sp, LOCAL_POS (n), FALSE);
1788 CASE (CEE_STLOC_3) {
1789 int n = (*ip)-CEE_STLOC_0;
1792 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1793 gint32 *p = (gint32*)LOCAL_POS (n);
1797 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1804 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1805 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1809 CASE (CEE_LDARGA_S) {
1811 sp->data.vt = ARG_POS (*ip);
1820 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1826 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1827 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1831 CASE (CEE_LDLOCA_S) {
1833 sp->data.p = LOCAL_POS (*ip);
1842 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1852 CASE (CEE_LDC_I4_M1)
1868 sp->data.i = (*ip) - CEE_LDC_I4_0;
1875 sp->data.i = *(const gint8 *)ip;
1882 sp->data.i = read32 (ip);
1889 sp->data.l = read64 (ip);
1896 sp->type = VAL_DOUBLE;
1905 sp->type = VAL_DOUBLE;
1906 readr8(ip, &sp->data.f);
1910 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1912 stackvalpush(sp - 1, sp);
1920 CASE (CEE_JMP) ves_abort(); BREAK;
1921 CASE (CEE_CALLVIRT) /* Fall through */
1922 CASE (CEE_CALLI) /* Fall through */
1924 MonoMethodSignature *csignature;
1926 stackval *endsp = sp;
1928 int virtual = *ip == CEE_CALLVIRT;
1929 int calli = *ip == CEE_CALLI;
1930 unsigned char *code = NULL;
1933 * We ignore tail recursion for now.
1940 token = read32 (ip);
1946 if (frame->method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE &&
1947 (ji = mono_jit_info_table_find (mono_root_domain, code)) != NULL) {
1948 child_frame.method = ji->method;
1949 csignature = ji->method->signature;
1951 else if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1952 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1953 child_frame.method = NULL;
1955 g_assert_not_reached ();
1959 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
1960 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
1962 child_frame.method = mono_get_method (image, token, NULL);
1963 if (!child_frame.method)
1964 THROW_EX (mono_get_exception_missing_method (), ip -5);
1965 csignature = child_frame.method->signature;
1967 stackval *this_arg = &sp [-csignature->param_count-1];
1968 if (!this_arg->data.p)
1969 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1970 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1971 if (!child_frame.method)
1972 THROW_EX (mono_get_exception_missing_method (), ip -5);
1976 if (frame->method->wrapper_type == MONO_WRAPPER_NONE)
1977 if (child_frame.method && child_frame.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1978 child_frame.method = mono_marshal_get_synchronized_wrapper (child_frame.method);
1980 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
1981 /* decrement by the actual number of args */
1982 if (csignature->param_count) {
1983 sp -= csignature->param_count;
1984 child_frame.stack_args = sp;
1986 child_frame.stack_args = NULL;
1988 if (csignature->hasthis) {
1989 g_assert (sp >= frame->stack);
1992 * It may also be a TP from LD(S)FLDA
1993 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_MP);
1995 if (sp->type == VAL_OBJ && child_frame.method &&
1996 child_frame.method->klass->valuetype) /* unbox it */
1997 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1999 child_frame.obj = sp->data.p;
2001 child_frame.obj = NULL;
2003 if (csignature->ret->type != MONO_TYPE_VOID) {
2004 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
2005 child_frame.retval = &retval;
2007 child_frame.retval = NULL;
2010 child_frame.ip = NULL;
2011 child_frame.ex = NULL;
2012 child_frame.ex_handler = NULL;
2014 if (!child_frame.method) {
2016 ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE, context);
2017 if (child_frame.ex) {
2018 frame->ex = child_frame.ex;
2019 goto handle_exception;
2021 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
2022 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
2023 g_assert (child_frame.method);
2024 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
2025 ves_exec_method_with_context (&child_frame, context);
2027 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
2028 case INLINE_STRING_LENGTH:
2029 retval.type = VAL_I32;
2030 retval.data.i = ((MonoString*)sp->data.p)->length;
2031 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
2033 case INLINE_STRING_GET_CHARS: {
2034 int idx = GET_NATI(sp [1]);
2035 if ((idx < 0) || (idx >= mono_string_length ((MonoString*)sp->data.p))) {
2036 child_frame.ex = mono_get_exception_index_out_of_range ();
2037 FILL_IN_TRACE(child_frame.ex, &child_frame);
2040 retval.type = VAL_I32;
2041 retval.data.i = mono_string_chars((MonoString*)sp->data.p)[idx];
2045 case INLINE_ARRAY_LENGTH:
2046 retval.type = VAL_I32;
2047 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
2049 case INLINE_ARRAY_RANK:
2050 retval.type = VAL_I32;
2051 retval.data.i = mono_object_class (sp->data.p)->rank;
2053 case INLINE_TYPE_ELEMENT_TYPE:
2054 retval.type = VAL_OBJ;
2056 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
2057 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
2058 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
2059 else if (c->element_class)
2060 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
2062 retval.data.p = NULL;
2066 ves_exec_method_with_context (&child_frame, context);
2070 context->current_frame = frame;
2072 while (endsp > sp) {
2077 if (child_frame.ex) {
2079 * An exception occurred, need to run finally, fault and catch handlers..
2081 frame->ex = child_frame.ex;
2082 if (context->search_for_handler) {
2083 context->search_for_handler = 0;
2084 goto handle_exception;
2086 goto handle_finally;
2089 /* need to handle typedbyref ... */
2090 if (csignature->ret->type != MONO_TYPE_VOID) {
2097 if (signature->ret->type != MONO_TYPE_VOID) {
2099 if (sp->type == VAL_VALUET) {
2100 /* the caller has already allocated the memory */
2101 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
2104 *frame->retval = *sp;
2107 if (sp > frame->stack)
2108 g_warning ("more values on stack: %d", sp-frame->stack);
2111 CASE (CEE_BR_S) /* Fall through */
2113 if (*ip == CEE_BR) {
2115 ip += (gint32) read32(ip);
2119 ip += (signed char) *ip;
2123 CASE (CEE_BRFALSE) /* Fall through */
2124 CASE (CEE_BRFALSE_S) {
2127 if (*ip == CEE_BRFALSE_S) {
2128 broffset = (signed char)ip [1];
2131 broffset = (gint32) read32 (ip + 1);
2136 case VAL_I32: result = sp->data.i == 0; break;
2137 case VAL_I64: result = sp->data.l == 0; break;
2138 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
2139 default: result = sp->data.p == NULL; break;
2145 CASE (CEE_BRTRUE) /* Fall through */
2146 CASE (CEE_BRTRUE_S) {
2149 if (*ip == CEE_BRTRUE_S) {
2150 broffset = (signed char)ip [1];
2153 broffset = (gint32) read32 (ip + 1);
2158 case VAL_I32: result = sp->data.i != 0; break;
2159 case VAL_I64: result = sp->data.l != 0; break;
2160 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
2161 default: result = sp->data.p != NULL; break;
2167 CASE (CEE_BEQ) /* Fall through */
2171 if (*ip == CEE_BEQ_S) {
2172 broffset = (signed char)ip [1];
2175 broffset = (gint32) read32 (ip + 1);
2179 if (sp->type == VAL_I32)
2180 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
2181 else if (sp->type == VAL_I64)
2182 result = sp [0].data.l == sp [1].data.l;
2183 else if (sp->type == VAL_DOUBLE)
2184 result = sp [0].data.f == sp [1].data.f;
2186 result = sp [0].data.nati == (mono_i)GET_NATI (sp [1]);
2191 CASE (CEE_BGE) /* Fall through */
2195 if (*ip == CEE_BGE_S) {
2196 broffset = (signed char)ip [1];
2199 broffset = (gint32) read32 (ip + 1);
2203 if (sp->type == VAL_I32)
2204 result = (mono_i)sp [0].data.i >= (mono_i)GET_NATI (sp [1]);
2205 else if (sp->type == VAL_I64)
2206 result = sp [0].data.l >= sp [1].data.l;
2207 else if (sp->type == VAL_DOUBLE)
2208 result = sp [0].data.f >= sp [1].data.f;
2210 result = (mono_i)sp [0].data.nati >= (mono_i)GET_NATI (sp [1]);
2215 CASE (CEE_BGT) /* Fall through */
2219 if (*ip == CEE_BGT_S) {
2220 broffset = (signed char)ip [1];
2223 broffset = (gint32) read32 (ip + 1);
2227 if (sp->type == VAL_I32)
2228 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
2229 else if (sp->type == VAL_I64)
2230 result = sp [0].data.l > sp [1].data.l;
2231 else if (sp->type == VAL_DOUBLE)
2232 result = sp [0].data.f > sp [1].data.f;
2234 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
2239 CASE (CEE_BLT) /* Fall through */
2243 if (*ip == CEE_BLT_S) {
2244 broffset = (signed char)ip [1];
2247 broffset = (gint32) read32 (ip + 1);
2251 if (sp->type == VAL_I32)
2252 result = (mono_i)sp[0].data.i < (mono_i)GET_NATI(sp[1]);
2253 else if (sp->type == VAL_I64)
2254 result = sp[0].data.l < sp[1].data.l;
2255 else if (sp->type == VAL_DOUBLE)
2256 result = sp[0].data.f < sp[1].data.f;
2258 result = (mono_i)sp[0].data.nati < (mono_i)GET_NATI(sp[1]);
2263 CASE (CEE_BLE) /* fall through */
2267 if (*ip == CEE_BLE_S) {
2268 broffset = (signed char)ip [1];
2271 broffset = (gint32) read32 (ip + 1);
2276 if (sp->type == VAL_I32)
2277 result = (mono_i)sp [0].data.i <= (mono_i)GET_NATI (sp [1]);
2278 else if (sp->type == VAL_I64)
2279 result = sp [0].data.l <= sp [1].data.l;
2280 else if (sp->type == VAL_DOUBLE)
2281 result = sp [0].data.f <= sp [1].data.f;
2283 result = (mono_i)sp [0].data.nati <= (mono_i)GET_NATI (sp [1]);
2289 CASE (CEE_BNE_UN) /* Fall through */
2290 CASE (CEE_BNE_UN_S) {
2293 if (*ip == CEE_BNE_UN_S) {
2294 broffset = (signed char)ip [1];
2297 broffset = (gint32) read32 (ip + 1);
2301 if (sp->type == VAL_I32)
2302 result = (mono_u)sp [0].data.i != (mono_u)GET_NATI (sp [1]);
2303 else if (sp->type == VAL_I64)
2304 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
2305 else if (sp->type == VAL_DOUBLE)
2306 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2307 (sp [0].data.f != sp [1].data.f);
2309 result = (mono_u)sp [0].data.nati != (mono_u)GET_NATI (sp [1]);
2314 CASE (CEE_BGE_UN) /* Fall through */
2315 CASE (CEE_BGE_UN_S) {
2318 if (*ip == CEE_BGE_UN_S) {
2319 broffset = (signed char)ip [1];
2322 broffset = (gint32) read32 (ip + 1);
2326 if (sp->type == VAL_I32)
2327 result = (mono_u)sp [0].data.i >= (mono_u)GET_NATI (sp [1]);
2328 else if (sp->type == VAL_I64)
2329 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
2330 else if (sp->type == VAL_DOUBLE)
2331 result = !isless (sp [0].data.f,sp [1].data.f);
2333 result = (mono_u)sp [0].data.nati >= (mono_u)GET_NATI (sp [1]);
2338 CASE (CEE_BGT_UN) /* Fall through */
2339 CASE (CEE_BGT_UN_S) {
2342 if (*ip == CEE_BGT_UN_S) {
2343 broffset = (signed char)ip [1];
2346 broffset = (gint32) read32 (ip + 1);
2350 if (sp->type == VAL_I32)
2351 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2352 else if (sp->type == VAL_I64)
2353 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2354 else if (sp->type == VAL_DOUBLE)
2355 result = isgreater (sp [0].data.f, sp [1].data.f);
2357 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
2362 CASE (CEE_BLE_UN) /* Fall through */
2363 CASE (CEE_BLE_UN_S) {
2366 if (*ip == CEE_BLE_UN_S) {
2367 broffset = (signed char)ip [1];
2370 broffset = (gint32) read32 (ip + 1);
2374 if (sp->type == VAL_I32)
2375 result = (mono_u)sp [0].data.i <= (mono_u)GET_NATI (sp [1]);
2376 else if (sp->type == VAL_I64)
2377 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2378 else if (sp->type == VAL_DOUBLE)
2379 result = islessequal (sp [0].data.f, sp [1].data.f);
2381 result = (mono_u)sp [0].data.nati <= (mono_u)GET_NATI (sp [1]);
2386 CASE (CEE_BLT_UN) /* Fall through */
2387 CASE (CEE_BLT_UN_S) {
2390 if (*ip == CEE_BLT_UN_S) {
2391 broffset = (signed char)ip [1];
2394 broffset = (gint32) read32 (ip + 1);
2398 if (sp->type == VAL_I32)
2399 result = (mono_u)sp[0].data.i < (mono_u)GET_NATI(sp[1]);
2400 else if (sp->type == VAL_I64)
2401 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2402 else if (sp->type == VAL_DOUBLE)
2403 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2404 (sp [0].data.f < sp [1].data.f);
2406 result = (mono_u)sp[0].data.nati < (mono_u)GET_NATI(sp[1]);
2413 const unsigned char *st;
2417 st = ip + sizeof (gint32) * n;
2419 if ((guint32)sp->data.i < n) {
2421 ip += sizeof (gint32) * (guint32)sp->data.i;
2422 offset = read32 (ip);
2431 sp[-1].type = VAL_I32;
2432 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2436 sp[-1].type = VAL_I32;
2437 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2441 sp[-1].type = VAL_I32;
2442 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2446 sp[-1].type = VAL_I32;
2447 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2449 CASE (CEE_LDIND_I4) /* Fall through */
2452 sp[-1].type = VAL_I32;
2453 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2457 sp[-1].type = VAL_I64;
2458 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2462 sp[-1].type = VAL_NATI;
2463 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2467 sp[-1].type = VAL_DOUBLE;
2468 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2472 sp[-1].type = VAL_DOUBLE;
2473 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2475 CASE (CEE_LDIND_REF)
2477 sp[-1].type = VAL_OBJ;
2478 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2480 CASE (CEE_STIND_REF) {
2488 CASE (CEE_STIND_I1) {
2493 *p = (gint8)sp[1].data.i;
2496 CASE (CEE_STIND_I2) {
2501 *p = (gint16)sp[1].data.i;
2504 CASE (CEE_STIND_I4) {
2512 CASE (CEE_STIND_I) {
2517 *p = (mono_i)sp[1].data.p;
2520 CASE (CEE_STIND_I8) {
2528 CASE (CEE_STIND_R4) {
2533 *p = (gfloat)sp[1].data.f;
2536 CASE (CEE_STIND_R8) {
2547 /* should probably consider the pointers as unsigned */
2548 if (sp->type == VAL_I32) {
2549 if (sp [-1].type == VAL_I32)
2550 sp [-1].data.i += sp [0].data.i;
2552 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.i;
2553 } else if (sp->type == VAL_I64)
2554 sp [-1].data.l += sp [0].data.l;
2555 else if (sp->type == VAL_DOUBLE)
2556 sp [-1].data.f += sp [0].data.f;
2558 if (sp [-1].type == VAL_I32) {
2559 sp [-1].data.nati = sp [-1].data.i + sp [0].data.nati;
2560 sp [-1].type = sp [0].type;
2562 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.nati;
2568 /* should probably consider the pointers as unsigned */
2569 if (sp->type == VAL_I32) {
2570 if (sp [-1].type == VAL_I32)
2571 sp [-1].data.i -= sp [0].data.i;
2573 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
2574 sp [-1].type = VAL_NATI;
2576 } else if (sp->type == VAL_I64)
2577 sp [-1].data.l -= sp [0].data.l;
2578 else if (sp->type == VAL_DOUBLE)
2579 sp [-1].data.f -= sp [0].data.f;
2581 if (sp [-1].type == VAL_I32) {
2582 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
2583 sp [-1].type = sp [0].type;
2585 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
2591 if (sp->type == VAL_I32) {
2592 if (sp [-1].type == VAL_I32)
2593 sp [-1].data.i *= sp [0].data.i;
2595 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
2596 } else if (sp->type == VAL_I64)
2597 sp [-1].data.l *= sp [0].data.l;
2598 else if (sp->type == VAL_DOUBLE)
2599 sp [-1].data.f *= sp [0].data.f;
2601 if (sp [-1].type == VAL_NATI)
2602 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.nati;
2604 sp [-1].data.nati = sp [-1].data.i * sp [0].data.nati;
2605 sp [-1].type = VAL_NATI;
2612 if (sp->type == VAL_I32) {
2613 if (sp [0].data.i == 0)
2614 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2615 if (sp [-1].type == VAL_I32)
2616 sp [-1].data.i /= sp [0].data.i;
2618 sp [-1].data.nati /= sp [0].data.i;
2619 } else if (sp->type == VAL_I64) {
2620 if (sp [0].data.l == 0)
2621 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2622 sp [-1].data.l /= sp [0].data.l;
2623 } else if (sp->type == VAL_DOUBLE) {
2624 /* set NaN is divisor is 0.0 */
2625 sp [-1].data.f /= sp [0].data.f;
2627 if (sp [-1].type == VAL_NATI)
2628 sp [-1].data.nati = sp [-1].data.nati / sp [0].data.nati;
2630 sp [-1].data.nati = sp [-1].data.i / sp [0].data.nati;
2631 sp [-1].type = VAL_NATI;
2638 if (sp->type == VAL_I32) {
2639 if (sp [0].data.i == 0)
2640 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2641 if (sp [-1].type == VAL_NATI)
2642 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.i;
2644 sp [-1].data.i = (guint32)sp [-1].data.i / (guint32)sp [0].data.i;
2645 } else if (sp->type == VAL_I64) {
2647 if (sp [0].data.l == 0)
2648 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2649 val = sp [-1].data.l;
2650 val /= (guint64)sp [0].data.l;
2651 sp [-1].data.l = val;
2653 if (sp [0].data.nati == 0)
2654 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2655 if (sp [-1].type == VAL_NATI)
2656 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.nati;
2658 sp [-1].data.nati = (mono_u)sp [-1].data.i / (mono_u)sp [0].data.nati;
2659 sp [-1].type = VAL_NATI;
2666 if (sp->type == VAL_I32) {
2667 if (sp [0].data.i == 0)
2668 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2669 if (sp [-1].type == VAL_NATI)
2670 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.i;
2672 sp [-1].data.i = sp [-1].data.i % sp [0].data.i;
2673 } else if (sp->type == VAL_I64) {
2674 if (sp [0].data.l == 0)
2675 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2676 sp [-1].data.l %= sp [0].data.l;
2677 } else if (sp->type == VAL_DOUBLE) {
2678 /* FIXME: what do we actually do here? */
2679 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2681 if (sp [0].data.nati == 0)
2682 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2683 if (sp [-1].type == VAL_NATI)
2684 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.nati;
2686 sp [-1].data.nati = (mono_i)sp [-1].data.i % (mono_i)sp [0].data.nati;
2687 sp [-1].type = VAL_NATI;
2694 if (sp->type == VAL_I32) {
2695 if (sp [0].data.i == 0)
2696 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2697 if (sp [-1].type == VAL_NATI)
2698 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.i;
2700 sp [-1].data.i = (guint32)sp [-1].data.i % (guint32)sp [0].data.i;
2701 } else if (sp->type == VAL_I64) {
2702 if (sp [0].data.l == 0)
2703 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2704 sp [-1].data.l = (guint64)sp [-1].data.l % (guint64)sp [0].data.l;
2705 } else if (sp->type == VAL_DOUBLE) {
2706 /* unspecified behaviour according to the spec */
2708 if (sp [0].data.nati == 0)
2709 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2710 if (sp [-1].type == VAL_NATI)
2711 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.nati;
2713 sp [-1].data.nati = (mono_u)sp [-1].data.i % (mono_u)sp [0].data.nati;
2714 sp [-1].type = VAL_NATI;
2721 if (sp->type == VAL_I32) {
2722 if (sp [-1].type == VAL_NATI)
2723 sp [-1].data.nati &= sp [0].data.i;
2725 sp [-1].data.i &= sp [0].data.i;
2727 else if (sp->type == VAL_I64)
2728 sp [-1].data.l &= sp [0].data.l;
2730 if (sp [-1].type == VAL_NATI)
2731 sp [-1].data.nati = (mono_i)sp [-1].data.nati & (mono_i)sp [0].data.nati;
2733 sp [-1].data.nati = (mono_i)sp [-1].data.i & (mono_i)sp [0].data.nati;
2734 sp [-1].type = VAL_NATI;
2741 if (sp->type == VAL_I32) {
2742 if (sp [-1].type == VAL_NATI)
2743 sp [-1].data.nati |= sp [0].data.i;
2745 sp [-1].data.i |= sp [0].data.i;
2747 else if (sp->type == VAL_I64)
2748 sp [-1].data.l |= sp [0].data.l;
2750 if (sp [-1].type == VAL_NATI)
2751 sp [-1].data.nati = (mono_i)sp [-1].data.nati | (mono_i)sp [0].data.nati;
2753 sp [-1].data.nati = (mono_i)sp [-1].data.i | (mono_i)sp [0].data.nati;
2754 sp [-1].type = VAL_NATI;
2761 if (sp->type == VAL_I32) {
2762 if (sp [-1].type == VAL_NATI)
2763 sp [-1].data.nati ^= sp [0].data.i;
2765 sp [-1].data.i ^= sp [0].data.i;
2767 else if (sp->type == VAL_I64)
2768 sp [-1].data.l ^= sp [0].data.l;
2770 if (sp [-1].type == VAL_NATI)
2771 sp [-1].data.nati = (mono_i)sp [-1].data.nati ^ (mono_i)sp [0].data.nati;
2773 sp [-1].data.nati = (mono_i)sp [-1].data.i ^ (mono_i)sp [0].data.nati;
2774 sp [-1].type = VAL_NATI;
2781 if (sp [-1].type == VAL_I32)
2782 sp [-1].data.i <<= GET_NATI (sp [0]);
2783 else if (sp [-1].type == VAL_I64)
2784 sp [-1].data.l <<= GET_NATI (sp [0]);
2786 sp [-1].data.nati <<= GET_NATI (sp [0]);
2791 if (sp [-1].type == VAL_I32)
2792 sp [-1].data.i >>= GET_NATI (sp [0]);
2793 else if (sp [-1].type == VAL_I64)
2794 sp [-1].data.l >>= GET_NATI (sp [0]);
2796 sp [-1].data.nati = ((mono_i)sp [-1].data.nati) >> GET_NATI (sp [0]);
2801 if (sp [-1].type == VAL_I32)
2802 sp [-1].data.i = (guint)sp [-1].data.i >> GET_NATI (sp [0]);
2803 else if (sp [-1].type == VAL_I64)
2804 sp [-1].data.l = (guint64)sp [-1].data.l >> GET_NATI (sp [0]);
2806 sp [-1].data.nati = ((mono_u)sp[-1].data.nati) >> GET_NATI (sp [0]);
2811 if (sp->type == VAL_I32)
2812 sp->data.i = - sp->data.i;
2813 else if (sp->type == VAL_I64)
2814 sp->data.l = - sp->data.l;
2815 else if (sp->type == VAL_DOUBLE)
2816 sp->data.f = - sp->data.f;
2817 else if (sp->type == VAL_NATI)
2818 sp->data.nati = - (mono_i)sp->data.nati;
2824 if (sp->type == VAL_I32)
2825 sp->data.i = ~ sp->data.i;
2826 else if (sp->type == VAL_I64)
2827 sp->data.l = ~ sp->data.l;
2828 else if (sp->type == VAL_NATI)
2829 sp->data.nati = ~ (mono_i)sp->data.p;
2832 CASE (CEE_CONV_U1) {
2834 switch (sp [-1].type) {
2836 sp [-1].data.i = (guint8)sp [-1].data.f;
2839 sp [-1].data.i = (guint8)sp [-1].data.l;
2844 sp [-1].data.i = (guint8)sp [-1].data.i;
2847 sp [-1].data.i = (guint8)sp [-1].data.nati;
2850 sp [-1].type = VAL_I32;
2853 CASE (CEE_CONV_I1) {
2855 switch (sp [-1].type) {
2857 sp [-1].data.i = (gint8)sp [-1].data.f;
2860 sp [-1].data.i = (gint8)sp [-1].data.l;
2865 sp [-1].data.i = (gint8)sp [-1].data.i;
2868 sp [-1].data.i = (gint8)sp [-1].data.nati;
2871 sp [-1].type = VAL_I32;
2874 CASE (CEE_CONV_U2) {
2876 switch (sp [-1].type) {
2878 sp [-1].data.i = (guint16)sp [-1].data.f;
2881 sp [-1].data.i = (guint16)sp [-1].data.l;
2886 sp [-1].data.i = (guint16)sp [-1].data.i;
2889 sp [-1].data.i = (guint16)sp [-1].data.nati;
2892 sp [-1].type = VAL_I32;
2895 CASE (CEE_CONV_I2) {
2897 switch (sp [-1].type) {
2899 sp [-1].data.i = (gint16)sp [-1].data.f;
2902 sp [-1].data.i = (gint16)sp [-1].data.l;
2907 sp [-1].data.i = (gint16)sp [-1].data.i;
2910 sp [-1].data.i = (gint16)sp [-1].data.nati;
2913 sp [-1].type = VAL_I32;
2916 CASE (CEE_CONV_U4) /* Fall through */
2917 #if SIZEOF_VOID_P == 4
2918 CASE (CEE_CONV_I) /* Fall through */
2919 CASE (CEE_CONV_U) /* Fall through */
2921 CASE (CEE_CONV_I4) {
2923 switch (sp [-1].type) {
2925 sp [-1].data.i = (gint32)sp [-1].data.f;
2928 sp [-1].data.i = (gint32)sp [-1].data.l;
2935 sp [-1].data.i = (gint32)sp [-1].data.p;
2938 sp [-1].type = VAL_I32;
2941 #if SIZEOF_VOID_P == 8
2942 CASE (CEE_CONV_I) /* Fall through */
2946 switch (sp [-1].type) {
2948 sp [-1].data.l = (gint64)sp [-1].data.f;
2955 sp [-1].data.l = (gint64)sp [-1].data.i;
2958 sp [-1].data.l = (gint64)sp [-1].data.nati;
2961 sp [-1].type = ip[-1] == CEE_CONV_I ? VAL_NATI : VAL_I64;
2963 CASE (CEE_CONV_R4) {
2965 switch (sp [-1].type) {
2967 sp [-1].data.f = (float)sp [-1].data.f;
2970 sp [-1].data.f = (float)sp [-1].data.l;
2975 sp [-1].data.f = (float)sp [-1].data.i;
2978 sp [-1].data.f = (float)sp [-1].data.nati;
2981 sp [-1].type = VAL_DOUBLE;
2984 CASE (CEE_CONV_R8) {
2986 switch (sp [-1].type) {
2988 sp [-1].data.f = (double)sp [-1].data.f;
2991 sp [-1].data.f = (double)sp [-1].data.l;
2996 sp [-1].data.f = (double)sp [-1].data.i;
2999 sp [-1].data.f = (double)sp [-1].data.nati;
3002 sp [-1].type = VAL_DOUBLE;
3005 #if SIZEOF_VOID_P == 8
3006 CASE (CEE_CONV_U) /* Fall through */
3011 switch (sp [-1].type){
3013 sp [-1].data.l = (guint64)sp [-1].data.f;
3020 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3023 sp [-1].data.l = (guint64) sp [-1].data.nati;
3026 sp [-1].type = ip[-1] == CEE_CONV_U ? VAL_NATI : VAL_I64;
3031 vtklass = mono_class_get (image, read32 (ip));
3034 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
3043 token = read32 (ip);
3046 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3047 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3049 c = mono_class_get (image, token);
3051 addr = sp [-1].data.vt;
3052 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
3053 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
3061 str_index = mono_metadata_token_index (read32 (ip));
3064 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
3065 o = (MonoObject *)mono_string_new_wrapper(
3066 mono_method_get_wrapper_data (frame->method, str_index));
3069 o = (MonoObject*)mono_ldstr (domain, image, str_index);
3078 MonoClass *newobj_class;
3079 MonoMethodSignature *csig;
3080 stackval valuetype_this;
3081 stackval *endsp = sp;
3088 token = read32 (ip);
3091 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3092 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
3094 child_frame.method = mono_get_method (image, token, NULL);
3095 if (!child_frame.method)
3096 THROW_EX (mono_get_exception_missing_method (), ip -5);
3098 csig = child_frame.method->signature;
3099 newobj_class = child_frame.method->klass;
3100 /*if (profiling_classes) {
3101 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3103 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3107 if (newobj_class->parent == mono_defaults.array_class) {
3108 sp -= csig->param_count;
3109 o = ves_array_create (domain, newobj_class, csig, sp);
3110 goto array_constructed;
3114 * First arg is the object.
3116 if (newobj_class->valuetype) {
3118 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
3119 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
3120 zero = valuetype_this.data.vt;
3121 child_frame.obj = valuetype_this.data.vt;
3123 memset (&valuetype_this, 0, sizeof (stackval));
3124 zero = &valuetype_this;
3125 child_frame.obj = &valuetype_this;
3127 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
3129 if (newobj_class != mono_defaults.string_class) {
3130 o = mono_object_new (domain, newobj_class);
3131 child_frame.obj = o;
3133 child_frame.retval = &retval;
3137 if (csig->param_count) {
3138 sp -= csig->param_count;
3139 child_frame.stack_args = sp;
3141 child_frame.stack_args = NULL;
3144 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3146 child_frame.ip = NULL;
3147 child_frame.ex = NULL;
3148 child_frame.ex_handler = NULL;
3150 ves_exec_method_with_context (&child_frame, context);
3152 context->current_frame = frame;
3154 while (endsp > sp) {
3159 if (child_frame.ex) {
3161 * An exception occurred, need to run finally, fault and catch handlers..
3163 frame->ex = child_frame.ex;
3164 goto handle_finally;
3167 * a constructor returns void, but we need to return the object we created
3170 if (newobj_class->valuetype && !newobj_class->enumtype) {
3171 *sp = valuetype_this;
3172 } else if (newobj_class == mono_defaults.string_class) {
3181 CASE (CEE_CASTCLASS) /* Fall through */
3186 int do_isinst = *ip == CEE_ISINST;
3189 token = read32 (ip);
3190 c = mono_class_get (image, token);
3192 g_assert (sp [-1].type == VAL_OBJ);
3194 if ((o = sp [-1].data.p)) {
3195 if (!mono_object_isinst (o, c)) {
3197 sp [-1].data.p = NULL;
3199 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3205 CASE (CEE_CONV_R_UN)
3207 switch (sp [-1].type) {
3211 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3216 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3219 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
3222 sp [-1].type = VAL_DOUBLE;
3225 CASE (CEE_UNUSED1) ves_abort(); BREAK;
3232 token = read32 (ip);
3234 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3235 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3237 c = mono_class_get (image, token);
3241 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3243 if (!(mono_object_isinst (o, c) ||
3244 ((o->vtable->klass->rank == 0) &&
3245 (o->vtable->klass->element_class == c->element_class))))
3246 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3248 sp [-1].type = VAL_MP;
3249 sp [-1].data.p = (char *)o + sizeof (MonoObject);
3256 frame->ex_handler = NULL;
3258 sp->data.p = mono_get_exception_null_reference ();
3259 THROW_EX ((MonoException *)sp->data.p, ip);
3261 CASE (CEE_LDFLDA) /* Fall through */
3264 MonoClassField *field;
3266 int load_addr = *ip == CEE_LDFLDA;
3269 if (!sp [-1].data.p)
3270 THROW_EX (mono_get_exception_null_reference (), ip);
3273 token = read32 (ip);
3274 field = rtd->field_info[token].field;
3277 if (sp [-1].type == VAL_OBJ) {
3278 obj = sp [-1].data.p;
3279 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3280 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3281 addr = mono_load_remote_field (obj, klass, field, NULL);
3283 addr = (char*)obj + field->offset;
3286 obj = sp [-1].data.vt;
3287 addr = (char*)obj + field->offset - sizeof (MonoObject);
3291 sp [-1].type = VAL_MP;
3292 sp [-1].data.p = addr;
3294 vt_alloc (field->type, &sp [-1], FALSE);
3295 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3301 MonoClassField *field;
3302 guint32 token, offset;
3307 THROW_EX (mono_get_exception_null_reference (), ip);
3310 token = read32 (ip);
3311 field = rtd->field_info[token].field;
3314 if (sp [0].type == VAL_OBJ) {
3315 obj = sp [0].data.p;
3317 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3318 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3319 mono_store_remote_field (obj, klass, field, &sp [1].data);
3321 offset = field->offset;
3322 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3326 obj = sp [0].data.vt;
3327 offset = field->offset - sizeof (MonoObject);
3328 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3334 CASE (CEE_LDSFLD) /* Fall through */
3335 CASE (CEE_LDSFLDA) {
3337 MonoClassField *field;
3339 int load_addr = *ip == CEE_LDSFLDA;
3343 token = read32 (ip);
3344 field = rtd->field_info[token].field;
3347 vt = mono_class_vtable (domain, field->parent);
3348 if (!vt->initialized)
3349 mono_runtime_class_init (vt);
3351 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3352 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3354 addr = (char*)(vt->data) + field->offset;
3360 vt_alloc (field->type, sp, FALSE);
3361 stackval_from_data (field->type, sp, addr, FALSE);
3368 MonoClassField *field;
3373 token = read32 (ip);
3374 field = rtd->field_info[token].field;
3378 vt = mono_class_vtable (domain, field->parent);
3379 if (!vt->initialized)
3380 mono_runtime_class_init (vt);
3382 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3383 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3385 addr = (char*)(vt->data) + field->offset;
3387 stackval_to_data (field->type, sp, addr, FALSE);
3394 vtklass = mono_class_get (image, read32 (ip));
3399 * LAMESPEC: According to the spec, the stack should contain a
3400 * pointer to a value type. In reality, it can contain anything.
3402 if (sp [1].type == VAL_VALUET)
3403 memcpy (sp [0].data.p, sp [1].data.vt, mono_class_value_size (vtklass, NULL));
3405 memcpy (sp [0].data.p, &sp [1].data, mono_class_value_size (vtklass, NULL));
3408 #if SIZEOF_VOID_P == 8
3409 CASE (CEE_CONV_OVF_I_UN)
3411 CASE (CEE_CONV_OVF_I8_UN) {
3412 switch (sp [-1].type) {
3414 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
3415 THROW_EX (mono_get_exception_overflow (), ip);
3416 sp [-1].data.l = (guint64)sp [-1].data.f;
3423 /* Can't overflow */
3424 sp [-1].data.l = (guint64)sp [-1].data.i;
3427 sp [-1].data.l = (guint64)sp [-1].data.nati;
3430 sp [-1].type = VAL_I64;
3434 #if SIZEOF_VOID_P == 8
3435 CASE (CEE_CONV_OVF_U_UN)
3437 CASE (CEE_CONV_OVF_U8_UN) {
3438 switch (sp [-1].type) {
3440 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
3441 THROW_EX (mono_get_exception_overflow (), ip);
3442 sp [-1].data.l = (guint64)sp [-1].data.f;
3450 /* Can't overflow */
3451 sp [-1].data.l = (guint64)sp [-1].data.i;
3454 /* Can't overflow */
3455 sp [-1].data.l = (guint64)sp [-1].data.nati;
3458 sp [-1].type = VAL_I64;
3462 #if SIZEOF_VOID_P == 4
3463 CASE (CEE_CONV_OVF_I_UN)
3464 CASE (CEE_CONV_OVF_U_UN)
3466 CASE (CEE_CONV_OVF_I1_UN)
3467 CASE (CEE_CONV_OVF_I2_UN)
3468 CASE (CEE_CONV_OVF_I4_UN)
3469 CASE (CEE_CONV_OVF_U1_UN)
3470 CASE (CEE_CONV_OVF_U2_UN)
3471 CASE (CEE_CONV_OVF_U4_UN) {
3473 switch (sp [-1].type) {
3475 if (sp [-1].data.f <= -1.0)
3476 THROW_EX (mono_get_exception_overflow (), ip);
3477 value = (guint64)sp [-1].data.f;
3480 value = (guint64)sp [-1].data.l;
3485 value = (guint64)sp [-1].data.i;
3488 value = (guint64)sp [-1].data.nati;
3492 case CEE_CONV_OVF_I1_UN:
3494 THROW_EX (mono_get_exception_overflow (), ip);
3495 sp [-1].data.i = value;
3496 sp [-1].type = VAL_I32;
3498 case CEE_CONV_OVF_I2_UN:
3500 THROW_EX (mono_get_exception_overflow (), ip);
3501 sp [-1].data.i = value;
3502 sp [-1].type = VAL_I32;
3504 #if SIZEOF_VOID_P == 4
3505 case CEE_CONV_OVF_I_UN: /* Fall through */
3507 case CEE_CONV_OVF_I4_UN:
3508 if (value > MYGUINT32_MAX)
3509 THROW_EX (mono_get_exception_overflow (), ip);
3510 sp [-1].data.i = value;
3511 sp [-1].type = VAL_I32;
3513 case CEE_CONV_OVF_U1_UN:
3515 THROW_EX (mono_get_exception_overflow (), ip);
3516 sp [-1].data.i = value;
3517 sp [-1].type = VAL_I32;
3519 case CEE_CONV_OVF_U2_UN:
3521 THROW_EX (mono_get_exception_overflow (), ip);
3522 sp [-1].data.i = value;
3523 sp [-1].type = VAL_I32;
3525 #if SIZEOF_VOID_P == 4
3526 case CEE_CONV_OVF_U_UN: /* Fall through */
3528 case CEE_CONV_OVF_U4_UN:
3529 if (value > 4294967295U)
3530 THROW_EX (mono_get_exception_overflow (), ip);
3531 sp [-1].data.i = value;
3532 sp [-1].type = VAL_I32;
3535 g_assert_not_reached ();
3545 token = read32 (ip);
3547 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3548 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3550 class = mono_class_get (image, token);
3551 g_assert (class != NULL);
3553 sp [-1].type = VAL_OBJ;
3554 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3555 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3557 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3558 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3560 /* need to vt_free (sp); */
3572 token = read32 (ip);
3574 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3575 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3577 class = mono_class_get (image, token);
3579 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3582 sp [-1].type = VAL_OBJ;
3584 /*if (profiling_classes) {
3585 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3587 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3597 g_assert (sp [-1].type == VAL_OBJ);
3601 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3603 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3605 sp [-1].type = VAL_I32;
3606 sp [-1].data.i = mono_array_length (o);
3610 CASE (CEE_LDELEMA) {
3612 guint32 esize, token;
3616 token = read32 (ip);
3620 g_assert (sp [0].type == VAL_OBJ);
3623 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3625 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3626 if (aindex >= mono_array_length (o))
3627 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3629 /* check the array element corresponds to token */
3630 esize = mono_array_element_size (o->obj.vtable->klass);
3633 sp->data.p = mono_array_addr_with_size (o, esize, aindex);
3638 CASE (CEE_LDELEM_I1) /* fall through */
3639 CASE (CEE_LDELEM_U1) /* fall through */
3640 CASE (CEE_LDELEM_I2) /* fall through */
3641 CASE (CEE_LDELEM_U2) /* fall through */
3642 CASE (CEE_LDELEM_I4) /* fall through */
3643 CASE (CEE_LDELEM_U4) /* fall through */
3644 CASE (CEE_LDELEM_I8) /* fall through */
3645 CASE (CEE_LDELEM_I) /* fall through */
3646 CASE (CEE_LDELEM_R4) /* fall through */
3647 CASE (CEE_LDELEM_R8) /* fall through */
3648 CASE (CEE_LDELEM_REF) {
3654 g_assert (sp [0].type == VAL_OBJ);
3657 THROW_EX (mono_get_exception_null_reference (), ip);
3659 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3661 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3662 if (aindex >= mono_array_length (o))
3663 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3666 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3670 sp [0].data.i = mono_array_get (o, gint8, aindex);
3671 sp [0].type = VAL_I32;
3674 sp [0].data.i = mono_array_get (o, guint8, aindex);
3675 sp [0].type = VAL_I32;
3678 sp [0].data.i = mono_array_get (o, gint16, aindex);
3679 sp [0].type = VAL_I32;
3682 sp [0].data.i = mono_array_get (o, guint16, aindex);
3683 sp [0].type = VAL_I32;
3686 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3687 sp [0].type = VAL_NATI;
3690 sp [0].data.i = mono_array_get (o, gint32, aindex);
3691 sp [0].type = VAL_I32;
3694 sp [0].data.i = mono_array_get (o, guint32, aindex);
3695 sp [0].type = VAL_I32;
3698 sp [0].data.l = mono_array_get (o, guint64, aindex);
3699 sp [0].type = VAL_I64;
3702 sp [0].data.f = mono_array_get (o, float, aindex);
3703 sp [0].type = VAL_DOUBLE;
3706 sp [0].data.f = mono_array_get (o, double, aindex);
3707 sp [0].type = VAL_DOUBLE;
3709 case CEE_LDELEM_REF:
3710 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3711 sp [0].type = VAL_OBJ;
3721 CASE (CEE_STELEM_I) /* fall through */
3722 CASE (CEE_STELEM_I1) /* fall through */
3723 CASE (CEE_STELEM_I2) /* fall through */
3724 CASE (CEE_STELEM_I4) /* fall through */
3725 CASE (CEE_STELEM_I8) /* fall through */
3726 CASE (CEE_STELEM_R4) /* fall through */
3727 CASE (CEE_STELEM_R8) /* fall through */
3728 CASE (CEE_STELEM_REF) {
3735 g_assert (sp [0].type == VAL_OBJ);
3738 THROW_EX (mono_get_exception_null_reference (), ip);
3740 ac = o->obj.vtable->klass;
3741 g_assert (MONO_CLASS_IS_ARRAY (ac));
3743 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3744 if (aindex >= mono_array_length (o))
3745 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3749 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3752 mono_array_set (o, gint8, aindex, sp [2].data.i);
3755 mono_array_set (o, gint16, aindex, sp [2].data.i);
3758 mono_array_set (o, gint32, aindex, sp [2].data.i);
3761 mono_array_set (o, gint64, aindex, sp [2].data.l);
3764 mono_array_set (o, float, aindex, sp [2].data.f);
3767 mono_array_set (o, double, aindex, sp [2].data.f);
3769 case CEE_STELEM_REF:
3770 g_assert (sp [2].type == VAL_OBJ);
3771 if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
3772 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3773 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3784 CASE (CEE_UNBOX_ANY)
3797 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3799 #if SIZEOF_VOID_P == 4
3800 CASE (CEE_CONV_OVF_I)
3801 CASE (CEE_CONV_OVF_U)
3803 CASE (CEE_CONV_OVF_I1)
3804 CASE (CEE_CONV_OVF_I2)
3805 CASE (CEE_CONV_OVF_I4)
3806 CASE (CEE_CONV_OVF_U1)
3807 CASE (CEE_CONV_OVF_U2)
3808 CASE (CEE_CONV_OVF_U4) {
3810 switch (sp [-1].type) {
3812 value = (gint64)sp [-1].data.f;
3815 value = (gint64)sp [-1].data.l;
3820 value = (gint64)sp [-1].data.i;
3823 value = (gint64)sp [-1].data.nati;
3827 case CEE_CONV_OVF_I1:
3828 if (value < -128 || value > 127)
3829 THROW_EX (mono_get_exception_overflow (), ip);
3830 sp [-1].data.i = value;
3831 sp [-1].type = VAL_I32;
3833 case CEE_CONV_OVF_I2:
3834 if (value < -32768 || value > 32767)
3835 THROW_EX (mono_get_exception_overflow (), ip);
3836 sp [-1].data.i = value;
3837 sp [-1].type = VAL_I32;
3839 #if SIZEOF_VOID_P == 4
3840 case CEE_CONV_OVF_I: /* Fall through */
3842 case CEE_CONV_OVF_I4:
3843 if (value < MYGINT32_MIN || value > MYGINT32_MAX)
3844 THROW_EX (mono_get_exception_overflow (), ip);
3845 sp [-1].data.i = value;
3846 sp [-1].type = VAL_I32;
3848 case CEE_CONV_OVF_U1:
3849 if (value < 0 || value > 255)
3850 THROW_EX (mono_get_exception_overflow (), ip);
3851 sp [-1].data.i = value;
3852 sp [-1].type = VAL_I32;
3854 case CEE_CONV_OVF_U2:
3855 if (value < 0 || value > 65535)
3856 THROW_EX (mono_get_exception_overflow (), ip);
3857 sp [-1].data.i = value;
3858 sp [-1].type = VAL_I32;
3860 #if SIZEOF_VOID_P == 4
3861 case CEE_CONV_OVF_U: /* Fall through */
3863 case CEE_CONV_OVF_U4:
3864 if (value < 0 || value > MYGUINT32_MAX)
3865 THROW_EX (mono_get_exception_overflow (), ip);
3866 sp [-1].data.i = value;
3867 sp [-1].type = VAL_I32;
3870 g_assert_not_reached ();
3876 #if SIZEOF_VOID_P == 8
3877 CASE (CEE_CONV_OVF_I)
3879 CASE (CEE_CONV_OVF_I8)
3880 /* FIXME: handle other cases */
3881 if (sp [-1].type == VAL_I32) {
3882 sp [-1].data.l = (guint64)sp [-1].data.i;
3883 sp [-1].type = VAL_I64;
3884 } else if(sp [-1].type == VAL_I64) {
3885 /* defined as NOP */
3892 #if SIZEOF_VOID_P == 8
3893 CASE (CEE_CONV_OVF_U)
3895 CASE (CEE_CONV_OVF_U8)
3896 /* FIXME: handle other cases */
3897 if (sp [-1].type == VAL_I32) {
3898 sp [-1].data.l = (guint64) sp [-1].data.i;
3899 sp [-1].type = VAL_I64;
3900 } else if(sp [-1].type == VAL_I64) {
3901 /* defined as NOP */
3913 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3914 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3916 if (!finite(sp [-1].data.f))
3917 THROW_EX (mono_get_exception_arithmetic (), ip);
3920 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3921 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3922 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3931 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3932 CASE (CEE_LDTOKEN) {
3934 MonoClass *handle_class;
3936 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3938 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3939 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3945 /* FIXME: check overflow */
3946 if (sp->type == VAL_I32) {
3947 if (sp [-1].type == VAL_I32) {
3948 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3949 THROW_EX (mono_get_exception_overflow (), ip);
3950 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)sp [0].data.i;
3952 if (CHECK_ADD_OVERFLOW_NAT (sp [-1].data.nati, (mono_i)sp [0].data.i))
3953 THROW_EX (mono_get_exception_overflow (), ip);
3954 sp [-1].data.nati = sp [-1].data.nati + (mono_i)sp [0].data.i;
3956 } else if (sp->type == VAL_I64) {
3957 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3958 THROW_EX (mono_get_exception_overflow (), ip);
3959 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3960 } else if (sp->type == VAL_DOUBLE)
3961 sp [-1].data.f += sp [0].data.f;
3963 char *p = sp [-1].data.p;
3964 p += GET_NATI (sp [0]);
3969 CASE (CEE_ADD_OVF_UN)
3971 /* FIXME: check overflow, make unsigned */
3972 if (sp->type == VAL_I32) {
3973 if (sp [-1].type == VAL_I32) {
3974 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
3975 THROW_EX (mono_get_exception_overflow (), ip);
3976 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)sp [0].data.i;
3978 if (CHECK_ADD_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
3979 THROW_EX (mono_get_exception_overflow (), ip);
3980 sp [-1].data.nati = (mono_u)sp [-1].data.nati + (mono_u)sp [0].data.i;
3982 } else if (sp->type == VAL_I64) {
3983 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3984 THROW_EX (mono_get_exception_overflow (), ip);
3985 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3986 } else if (sp->type == VAL_DOUBLE)
3987 sp [-1].data.f += sp [0].data.f;
3989 char *p = sp [-1].data.p;
3990 p += GET_NATI (sp [0]);
3997 /* FIXME: check overflow */
3998 if (sp->type == VAL_I32) {
3999 if (sp [-1].type == VAL_NATI) {
4000 if (CHECK_MUL_OVERFLOW_NAT (sp [-1].data.nati, sp [0].data.i))
4001 THROW_EX (mono_get_exception_overflow (), ip);
4002 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
4003 sp [-1].type = VAL_NATI;
4005 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4006 THROW_EX (mono_get_exception_overflow (), ip);
4007 sp [-1].data.i *= sp [0].data.i;
4010 else if (sp->type == VAL_I64) {
4011 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4012 THROW_EX (mono_get_exception_overflow (), ip);
4013 sp [-1].data.l *= sp [0].data.l;
4015 else if (sp->type == VAL_DOUBLE)
4016 sp [-1].data.f *= sp [0].data.f;
4021 CASE (CEE_MUL_OVF_UN)
4023 /* FIXME: check overflow, make unsigned */
4024 if (sp->type == VAL_I32) {
4025 if (sp [-1].type == VAL_NATI) {
4026 if (CHECK_MUL_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
4027 THROW_EX (mono_get_exception_overflow (), ip);
4028 sp [-1].data.nati = (mono_u)sp [-1].data.nati * (mono_u)sp [0].data.i;
4029 sp [-1].type = VAL_NATI;
4031 if (CHECK_MUL_OVERFLOW_UN ((guint32)sp [-1].data.i, (guint32)sp [0].data.i))
4032 THROW_EX (mono_get_exception_overflow (), ip);
4033 sp [-1].data.i *= sp [0].data.i;
4036 else if (sp->type == VAL_I64) {
4037 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4038 THROW_EX (mono_get_exception_overflow (), ip);
4039 sp [-1].data.l *= sp [0].data.l;
4041 else if (sp->type == VAL_DOUBLE)
4042 sp [-1].data.f *= sp [0].data.f;
4049 /* FIXME: handle undeflow/unsigned */
4050 /* should probably consider the pointers as unsigned */
4051 if (sp->type == VAL_I32) {
4052 if (sp [-1].type == VAL_I32) {
4053 if (CHECK_SUB_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4054 THROW_EX (mono_get_exception_overflow (), ip);
4055 sp [-1].data.i -= sp [0].data.i;
4057 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4058 sp [-1].type = VAL_NATI;
4061 else if (sp->type == VAL_I64) {
4062 if (CHECK_SUB_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4063 THROW_EX (mono_get_exception_overflow (), ip);
4064 sp [-1].data.l -= sp [0].data.l;
4066 else if (sp->type == VAL_DOUBLE)
4067 sp [-1].data.f -= sp [0].data.f;
4069 if (sp [-1].type == VAL_I32) {
4070 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4071 sp [-1].type = sp [0].type;
4073 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4077 CASE (CEE_SUB_OVF_UN)
4079 /* FIXME: handle undeflow/unsigned */
4080 /* should probably consider the pointers as unsigned */
4081 if (sp->type == VAL_I32) {
4082 if (sp [-1].type == VAL_I32) {
4083 if (CHECK_SUB_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
4084 THROW_EX (mono_get_exception_overflow (), ip);
4085 sp [-1].data.i -= sp [0].data.i;
4087 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4088 sp [-1].type = VAL_NATI;
4091 else if (sp->type == VAL_I64) {
4092 if (CHECK_SUB_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4093 THROW_EX (mono_get_exception_overflow (), ip);
4094 sp [-1].data.l -= sp [0].data.l;
4096 else if (sp->type == VAL_DOUBLE)
4097 sp [-1].data.f -= sp [0].data.f;
4099 if (sp [-1].type == VAL_I32) {
4100 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4101 sp [-1].type = sp [0].type;
4103 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4107 CASE (CEE_ENDFINALLY)
4109 ip = finally_ips->data;
4110 finally_ips = g_slist_remove (finally_ips, ip);
4117 CASE (CEE_LEAVE) /* Fall through */
4119 while (sp > frame->stack) {
4124 if (*ip == CEE_LEAVE_S) {
4126 ip += (signed char) *ip;
4130 ip += (gint32) read32 (ip);
4134 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - header->code)) {
4135 frame->ex_handler = NULL;
4138 goto handle_finally;
4143 case CEE_MONO_FUNC1: {
4144 MonoMarshalConv conv;
4153 sp->type = VAL_NATI;
4156 case MONO_MARSHAL_CONV_STR_LPWSTR:
4157 sp->data.p = mono_string_to_utf16 (sp->data.p);
4159 case MONO_MARSHAL_CONV_LPSTR_STR:
4160 sp->data.p = mono_string_new_wrapper (sp->data.p);
4162 case MONO_MARSHAL_CONV_STR_LPTSTR:
4163 case MONO_MARSHAL_CONV_STR_LPSTR:
4164 sp->data.p = mono_string_to_utf8 (sp->data.p);
4166 case MONO_MARSHAL_CONV_STR_BSTR:
4167 sp->data.p = mono_string_to_bstr (sp->data.p);
4169 case MONO_MARSHAL_CONV_STR_TBSTR:
4170 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4171 sp->data.p = mono_string_to_ansibstr (sp->data.p);
4173 case MONO_MARSHAL_CONV_SB_LPSTR:
4174 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
4176 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4177 sp->data.p = mono_array_to_savearray (sp->data.p);
4179 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4180 sp->data.p = mono_array_to_lparray (sp->data.p);
4182 case MONO_MARSHAL_CONV_DEL_FTN:
4183 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
4185 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4186 sp->data.p = mono_marshal_string_array (sp->data.p);
4188 case MONO_MARSHAL_CONV_LPWSTR_STR:
4189 sp->data.p = mono_string_from_utf16 (sp->data.p);
4192 fprintf(stderr, "MONO_FUNC1 %d", conv);
4193 g_assert_not_reached ();
4198 case CEE_MONO_PROC2: {
4199 MonoMarshalConv conv;
4207 case MONO_MARSHAL_CONV_LPSTR_SB:
4208 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
4210 case MONO_MARSHAL_FREE_ARRAY:
4211 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
4214 g_assert_not_reached ();
4218 case CEE_MONO_PROC3: {
4219 MonoMarshalConv conv;
4227 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4228 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4230 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4231 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4234 g_assert_not_reached ();
4238 case CEE_MONO_VTADDR: {
4241 sp [-1].type = VAL_MP;
4245 case CEE_MONO_LDPTR: {
4249 token = read32 (ip);
4252 sp->type = VAL_NATI;
4253 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
4257 case CEE_MONO_FREE: {
4261 g_free (sp->data.p);
4264 case CEE_MONO_OBJADDR: {
4271 case CEE_MONO_NEWOBJ: {
4276 token = read32 (ip);
4279 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4280 sp->data.p = mono_object_new (domain, class);
4284 case CEE_MONO_RETOBJ: {
4289 token = read32 (ip);
4294 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4296 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
4298 if (sp > frame->stack)
4299 g_warning ("more values on stack: %d", sp-frame->stack);
4302 case CEE_MONO_LDNATIVEOBJ: {
4307 token = read32 (ip);
4310 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4311 g_assert(class->valuetype);
4313 sp [-1].type = VAL_MP;
4318 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
4349 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
4351 * Note: Exceptions thrown when executing a prefixed opcode need
4352 * to take into account the number of prefix bytes (usually the
4353 * throw point is just (ip - n_prefix_bytes).
4358 case CEE_ARGLIST: ves_abort(); break;
4364 if (sp->type == VAL_I32)
4365 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
4366 else if (sp->type == VAL_I64)
4367 result = sp [0].data.l == sp [1].data.l;
4368 else if (sp->type == VAL_DOUBLE) {
4369 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4372 result = sp [0].data.f == sp [1].data.f;
4374 result = sp [0].data.nati == GET_NATI (sp [1]);
4376 sp->data.i = result;
4386 if (sp->type == VAL_I32)
4387 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
4388 else if (sp->type == VAL_I64)
4389 result = sp [0].data.l > sp [1].data.l;
4390 else if (sp->type == VAL_DOUBLE) {
4391 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4394 result = sp [0].data.f > sp [1].data.f;
4396 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
4398 sp->data.i = result;
4408 if (sp->type == VAL_I32)
4409 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
4410 else if (sp->type == VAL_I64)
4411 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
4412 else if (sp->type == VAL_DOUBLE)
4413 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4414 sp[0].data.f > sp[1].data.f;
4416 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
4418 sp->data.i = result;
4428 if (sp->type == VAL_I32)
4429 result = (mono_i)sp [0].data.i < (mono_i)GET_NATI (sp [1]);
4430 else if (sp->type == VAL_I64)
4431 result = sp [0].data.l < sp [1].data.l;
4432 else if (sp->type == VAL_DOUBLE) {
4433 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4436 result = sp [0].data.f < sp [1].data.f;
4438 result = (mono_i)sp [0].data.nati < (mono_i)GET_NATI (sp [1]);
4440 sp->data.i = result;
4450 if (sp->type == VAL_I32)
4451 result = (mono_u)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
4452 else if (sp->type == VAL_I64)
4453 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
4454 else if (sp->type == VAL_DOUBLE)
4455 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4456 sp[0].data.f < sp[1].data.f;
4458 result = (mono_u)sp [0].data.nati < (mono_u)GET_NATI (sp [1]);
4460 sp->data.i = result;
4466 case CEE_LDVIRTFTN: {
4467 int virtual = *ip == CEE_LDVIRTFTN;
4471 token = read32 (ip);
4474 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
4475 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
4477 m = mono_get_method (image, token, NULL);
4480 THROW_EX (mono_get_exception_missing_method (), ip - 5);
4484 THROW_EX (mono_get_exception_null_reference (), ip - 5);
4486 m = get_virtual_method (domain, m, sp);
4490 * This prevents infinite cycles since the wrapper contains
4493 if (frame->method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
4494 if (m && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4495 m = mono_marshal_get_synchronized_wrapper (m);
4497 sp->type = VAL_NATI;
4498 sp->data.p = mono_create_method_pointer (m);
4502 case CEE_UNUSED56: ves_abort(); break;
4506 arg_pos = read16 (ip);
4508 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
4509 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4518 sp->data.vt = ARG_POS (anum);
4526 arg_pos = read16 (ip);
4529 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4536 loc_pos = read16 (ip);
4538 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4539 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4548 loc_pos = read16 (ip);
4550 t = LOCAL_TYPE (header, loc_pos);
4551 sp->data.vt = LOCAL_POS (loc_pos);
4561 loc_pos = read16 (ip);
4564 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4570 if (sp != frame->stack)
4571 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4573 sp->data.p = alloca (sp->data.i);
4577 case CEE_UNUSED57: ves_abort(); break;
4578 case CEE_ENDFILTER: ves_abort(); break;
4579 case CEE_UNALIGNED_:
4581 unaligned_address = 1;
4585 volatile_address = 1;
4596 token = read32 (ip);
4599 class = mono_class_get (image, token);
4602 g_assert (sp->type == VAL_TP || sp->type == VAL_MP);
4603 memset (sp->data.vt, 0, mono_class_value_size (class, NULL));
4606 case CEE_CONSTRAINED_: {
4608 /* FIXME: implement */
4610 token = read32 (ip);
4616 if (!sp [0].data.p || !sp [1].data.p)
4617 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4619 /* FIXME: value and size may be int64... */
4620 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4625 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4627 /* FIXME: value and size may be int64... */
4628 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4631 /* FIXME: implement */
4636 * need to clarify what this should actually do:
4637 * start the search from the last found handler in
4638 * this method or continue in the caller or what.
4639 * Also, do we need to run finally/fault handlers after a retrow?
4640 * Well, this implementation will follow the usual search
4641 * for an handler, considering the current ip as throw spot.
4642 * We need to NULL frame->ex_handler for the later code to
4643 * actually run the new found handler.
4645 frame->ex_handler = NULL;
4646 THROW_EX (frame->ex, ip - 1);
4648 case CEE_UNUSED: ves_abort(); break;
4653 token = read32 (ip);
4655 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4656 MonoType *type = mono_type_create_from_typespec (image, token);
4657 sp->data.i = mono_type_size (type, &align);
4659 MonoClass *szclass = mono_class_get (image, token);
4660 mono_class_init (szclass);
4661 if (!szclass->valuetype)
4662 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4663 sp->data.i = mono_class_value_size (szclass, &align);
4669 case CEE_REFANYTYPE: ves_abort(); break;
4671 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4678 g_assert_not_reached ();
4680 * Exception handling code.
4681 * The exception object is stored in frame->ex.
4688 MonoInvocation *inv;
4689 MonoMethodHeader *hd;
4690 MonoExceptionClause *clause;
4696 g_print ("* Handling exception '%s' at IL_%04x\n", frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, frame->ip - header->code);
4698 if (die_on_exception)
4701 if (frame->ex == quit_exception)
4702 goto handle_finally;
4704 for (inv = frame; inv; inv = inv->parent) {
4705 if (inv->method == NULL)
4707 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4709 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4711 hd = ((MonoMethodNormal*)inv->method)->header;
4712 ip_offset = inv->ip - hd->code;
4713 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4714 for (i = 0; i < hd->num_clauses; ++i) {
4715 clause = &hd->clauses [i];
4716 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4717 if (!clause->flags) {
4718 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4720 * OK, we found an handler, now we need to execute the finally
4721 * and fault blocks before branching to the handler code.
4723 inv->ex_handler = clause;
4726 g_print ("* Found handler at '%s'\n", inv->method->name);
4728 goto handle_finally;
4731 /* FIXME: handle filter clauses */
4738 * If we get here, no handler was found: print a stack trace.
4740 for (inv = frame; inv; inv = inv->parent) {
4741 if (inv->invoke_trap)
4742 goto handle_finally;
4745 ex_obj = (MonoObject*)frame->ex;
4746 mono_unhandled_exception (ex_obj);
4753 MonoExceptionClause *clause;
4754 GSList *old_list = finally_ips;
4758 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - header->code);
4760 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4761 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4764 ip_offset = frame->ip - header->code;
4766 if (endfinally_ip != NULL)
4767 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4768 for (i = 0; i < header->num_clauses; ++i)
4769 if (frame->ex_handler == &header->clauses [i])
4773 clause = &header->clauses [i];
4774 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code)))) {
4775 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4776 ip = header->code + clause->handler_offset;
4777 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4780 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4786 endfinally_ip = NULL;
4788 if (old_list != finally_ips && finally_ips) {
4789 ip = finally_ips->data;
4790 finally_ips = g_slist_remove (finally_ips, ip);
4791 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4796 * If an exception is set, we need to execute the fault handler, too,
4797 * otherwise, we continue normally.
4807 MonoExceptionClause *clause;
4811 g_print ("* Handle fault\n");
4813 ip_offset = frame->ip - header->code;
4814 for (i = 0; i < header->num_clauses; ++i) {
4815 clause = &header->clauses [i];
4816 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4817 ip = header->code + clause->handler_offset;
4820 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4826 * If the handler for the exception was found in this method, we jump
4827 * to it right away, otherwise we return and let the caller run
4828 * the finally, fault and catch blocks.
4829 * This same code should be present in the endfault opcode, but it
4830 * is corrently not assigned in the ECMA specs: LAMESPEC.
4832 if (frame->ex_handler) {
4835 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4837 ip = header->code + frame->ex_handler->handler_offset;
4840 sp->data.p = frame->ex;
4851 ves_exec_method (MonoInvocation *frame)
4853 ThreadContext *context = TlsGetValue (thread_context_id);
4854 ThreadContext context_struct;
4855 if (context == NULL) {
4856 context = &context_struct;
4857 context_struct.base_frame = frame;
4858 context_struct.current_frame = NULL;
4859 context_struct.current_env = NULL;
4860 context_struct.search_for_handler = 0;
4861 TlsSetValue (thread_context_id, context);
4864 frame->parent = context->current_frame;
4865 ves_exec_method_with_context(frame, context);
4867 if (context->current_env) {
4868 context->env_frame->ex = frame->ex;
4869 longjmp (*context->current_env, 1);
4872 mono_unhandled_exception ((MonoObject*)frame->ex);
4874 if (context->base_frame == frame)
4875 TlsSetValue (thread_context_id, NULL);
4877 context->current_frame = frame->parent;
4881 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4883 MonoImage *image = assembly->image;
4884 MonoCLIImageInfo *iinfo;
4886 MonoObject *exc = NULL;
4889 iinfo = image->image_info;
4890 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4892 g_error ("No entry point method found in %s", image->name);
4894 rval = mono_runtime_run_main (method, argc, argv, &exc);
4896 mono_unhandled_exception (exc);
4905 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4906 "Usage is: mint [options] executable args...\n\n", VERSION);
4908 "Runtime Debugging:\n"
4913 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4916 " --traceclassinit\n"
4919 " --debug method_name\n"
4925 " --config filename load the specified config file instead of the default\n"
4926 " --workers n maximum number of worker threads\n"
4933 test_load_class (MonoImage* image)
4935 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4939 for (i = 1; i <= t->rows; ++i) {
4940 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4941 mono_class_init (klass);
4946 static MonoException * segv_exception = NULL;
4949 segv_handler (int signum)
4951 signal (signum, segv_handler);
4952 mono_raise_exception (segv_exception);
4957 quit_handler (int signum)
4959 signal (signum, quit_handler);
4960 mono_raise_exception (quit_exception);
4964 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4965 MonoReflectionMethod **method,
4966 gint32 *iloffset, gint32 *native_offset,
4967 MonoString **file, gint32 *line, gint32 *column)
4980 *file = mono_string_new (mono_domain_get (), "unknown");
4986 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4994 int enable_debugging;
5000 static void main_thread_handler (gpointer user_data)
5002 MainThreadArgs *main_args=(MainThreadArgs *)user_data;
5003 MonoAssembly *assembly;
5006 if (main_args->enable_debugging)
5007 mono_debug_init (main_args->domain, MONO_DEBUG_FORMAT_MONO);
5009 assembly = mono_domain_assembly_open (main_args->domain,
5013 fprintf (stderr, "Can not open image %s\n", main_args->file);
5017 if (main_args->enable_debugging)
5018 mono_debug_init_2 (assembly);
5021 test_load_class (assembly->image);
5023 error = mono_verify_corlib ();
5025 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5028 segv_exception = mono_get_exception_null_reference ();
5029 segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
5030 signal (SIGSEGV, segv_handler);
5031 /* perhaps we should use a different class for this exception... */
5032 quit_exception = mono_get_exception_null_reference ();
5033 quit_exception->message = mono_string_new (main_args->domain, "Quit");
5034 signal (SIGINT, quit_handler);
5036 ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
5041 mono_runtime_install_handlers (void)
5043 /* FIXME: anything to do here? */
5047 quit_function (MonoDomain *domain, gpointer user_data)
5049 mono_profiler_shutdown ();
5051 mono_runtime_cleanup (domain);
5052 mono_domain_free (domain, TRUE);
5057 mono_interp_cleanup(MonoDomain *domain)
5059 quit_function (domain, NULL);
5063 mono_interp_exec(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
5065 return ves_exec (domain, assembly, argc, argv);
5069 mono_interp_init(const char *file)
5073 g_set_prgname (file);
5074 mono_set_rootdir ();
5076 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
5077 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
5079 g_thread_init (NULL);
5081 thread_context_id = TlsAlloc ();
5082 TlsSetValue (thread_context_id, NULL);
5083 InitializeCriticalSection(&calc_section);
5084 InitializeCriticalSection(&create_method_pointer_mutex);
5086 mono_install_compile_method (mono_create_method_pointer);
5087 mono_install_runtime_invoke (interp_mono_runtime_invoke);
5088 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
5090 mono_install_handler (interp_ex_handler);
5091 mono_install_stack_walk (interp_walk_stack);
5092 mono_runtime_install_cleanup (quit_function);
5094 domain = mono_init (file);
5095 #ifdef __hpux /* generates very big stack frames */
5096 mono_threads_set_default_stacksize(32*1024*1024);
5099 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
5100 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
5101 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
5103 mono_runtime_init (domain, NULL, NULL);
5109 mono_main (int argc, char *argv [])
5112 int retval = 0, i, ocount = 0;
5113 char *file, *config_file = NULL;
5114 int enable_debugging = FALSE;
5115 MainThreadArgs main_args;
5118 setlocale (LC_ALL, "");
5122 for (i = 1; i < argc && argv [i][0] == '-'; i++){
5123 if (strcmp (argv [i], "--trace") == 0)
5125 if (strcmp (argv [i], "--noptr") == 0)
5126 global_no_pointers = 1;
5127 if (strcmp (argv [i], "--traceops") == 0)
5129 if (strcmp (argv [i], "--dieonex") == 0) {
5130 die_on_exception = 1;
5131 enable_debugging = 1;
5133 if (strcmp (argv [i], "--print-vtable") == 0)
5134 mono_print_vtable = TRUE;
5135 if (strcmp (argv [i], "--profile") == 0)
5136 mono_profiler_load (NULL);
5137 if (strcmp (argv [i], "--opcode-count") == 0)
5139 if (strcmp (argv [i], "--config") == 0)
5140 config_file = argv [++i];
5141 if (strcmp (argv [i], "--workers") == 0) {
5142 mono_max_worker_threads = atoi (argv [++i]);
5143 if (mono_max_worker_threads < 1)
5144 mono_max_worker_threads = 1;
5146 if (strcmp (argv [i], "--help") == 0)
5149 if (strcmp (argv [i], "--debug") == 0) {
5150 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
5152 g_error ("Invalid method name '%s'", argv [i]);
5153 db_methods = g_list_append (db_methods, desc);
5163 domain = mono_interp_init(file);
5164 mono_config_parse (config_file);
5166 error = mono_verify_corlib ();
5168 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5172 error = mono_check_corlib_version ();
5174 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5175 fprintf (stderr, "Download a newer corlib at http://go-mono/daily.\n");
5179 main_args.domain=domain;
5180 main_args.file=file;
5181 main_args.argc=argc-i;
5182 main_args.argv=argv+i;
5183 main_args.enable_debugging=enable_debugging;
5185 mono_runtime_exec_managed_code (domain, main_thread_handler,
5188 quit_function (domain, NULL);
5190 /* Get the return value from System.Environment.ExitCode */
5191 retval=mono_environment_exitcode_get ();
5195 fprintf (stderr, "opcode count: %ld\n", opcode_count);
5196 fprintf (stderr, "fcall count: %ld\n", fcall_count);