2 * PLEASE NOTE: This is a research prototype.
5 * interp.c: Interpreter for CIL byte codes
8 * Paolo Molaro (lupus@ximian.com)
9 * Miguel de Icaza (miguel@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2001, 2002 Ximian, Inc.
26 #include <mono/os/gc_wrapper.h>
32 # define alloca __builtin_alloca
36 /* trim excessive headers */
37 #include <mono/metadata/image.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/cil-coff.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/blob.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/io-layer/io-layer.h>
55 #include <mono/metadata/socket-io.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/os/util.h>
62 /*#include <mono/cli/types.h>*/
66 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
69 #define finite _finite
73 #define finite isfinite
77 /* If true, then we output the opcodes as we interpret them */
78 static int global_tracing = 0;
79 static int global_no_pointers = 0;
81 static int debug_indent_level = 0;
84 * Pull the list of opcodes
86 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
90 #include "mono/cil/opcode.def"
95 #if SIZEOF_VOID_P == 8
96 #define GET_NATI(sp) ((sp).type == VAL_I32 ? (sp).data.i : (sp).data.nati)
98 #define GET_NATI(sp) (sp).data.i
100 #define CSIZE(x) (sizeof (x) / 4)
102 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
104 (frame)->parent = (parent_frame); \
105 (frame)->obj = (obj_this); \
106 (frame)->stack_args = (method_args); \
107 (frame)->retval = (method_retval); \
108 (frame)->method = (mono_method); \
109 (frame)->ex_handler = NULL; \
110 (frame)->ex = NULL; \
111 (frame)->child = NULL; \
112 (frame)->ip = NULL; \
113 (frame)->invoke_trap = 0; \
117 MonoInvocation *base_frame;
118 MonoInvocation *current_frame;
119 MonoInvocation *env_frame;
120 jmp_buf *current_env;
121 int search_for_handler;
124 static MonoException * quit_exception = NULL;
126 void ves_exec_method (MonoInvocation *frame);
128 static char* dump_stack (stackval *stack, stackval *sp);
129 static char* dump_frame (MonoInvocation *inv);
130 static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
132 typedef void (*ICallMethod) (MonoInvocation *frame);
134 static guint32 die_on_exception = 0;
135 static guint32 thread_context_id = 0;
137 #define DEBUG_INTERP 1
140 static unsigned long opcode_count = 0;
141 static unsigned long fcall_count = 0;
142 static int break_on_method = 0;
143 static GList *db_methods = NULL;
150 for (h = 0; h < debug_indent_level; h++)
155 db_match_method (gpointer data, gpointer user_data)
157 MonoMethod *m = (MonoMethod*)user_data;
158 MonoMethodDesc *desc = data;
160 if (mono_method_desc_full_match (desc, m))
164 #define DEBUG_ENTER() \
166 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
167 if (break_on_method) tracing=2; \
168 break_on_method = 0; \
170 char *mn, *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
171 debug_indent_level++; \
173 mn = mono_method_full_name (frame->method, FALSE); \
174 g_print ("(%u) Entering %s (", GetCurrentThreadId(), mn); \
176 if (signature->hasthis) { \
177 if (global_no_pointers) { \
178 g_print ("this%s ", frame->obj ? "" : "=null"); \
180 g_print ("%p ", frame->obj); } \
182 g_print ("%s)\n", args); \
185 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
186 mono_profiler_method_enter (frame->method);
188 #define DEBUG_LEAVE() \
191 if (signature->ret->type != MONO_TYPE_VOID) \
192 args = dump_stack (frame->retval, frame->retval + 1); \
194 args = g_strdup (""); \
196 mn = mono_method_full_name (frame->method, FALSE); \
197 g_print ("(%u) Leaving %s", GetCurrentThreadId(), mn); \
199 g_print (" => %s\n", args); \
201 debug_indent_level--; \
203 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
204 mono_profiler_method_leave (frame->method);
208 #define DEBUG_ENTER()
209 #define DEBUG_LEAVE()
214 interp_ex_handler (MonoException *ex) {
215 ThreadContext *context = TlsGetValue (thread_context_id);
217 stack_trace = dump_frame (context->current_frame);
218 ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
219 g_free (stack_trace);
220 if (context == NULL || context->current_env == NULL) {
221 char *strace = mono_string_to_utf8 (ex->stack_trace);
222 fprintf(stderr, "Nothing can catch this exception: ");
223 fprintf(stderr, "%s", ex->object.vtable->klass->name);
224 if (ex->message != NULL) {
225 char *m = mono_string_to_utf8 (ex->message);
226 fprintf(stderr, ": %s", m);
229 fprintf(stderr, "\n");
230 fprintf(stderr, "%s\n", strace);
232 if (ex->inner_ex != NULL) {
233 ex = (MonoException *)ex->inner_ex;
234 fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name);
235 if (ex->message != NULL) {
236 char *m = mono_string_to_utf8 (ex->message);
237 fprintf(stderr, ": %s", m);
240 strace = mono_string_to_utf8 (ex->stack_trace);
241 fprintf(stderr, "\n");
242 fprintf(stderr, "%s\n", strace);
247 context->env_frame->ex = ex;
248 context->search_for_handler = 1;
249 longjmp (*context->current_env, 1);
253 ves_real_abort (int line, MonoMethod *mh,
254 const unsigned char *ip, stackval *stack, stackval *sp)
256 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
257 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
258 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
259 ip-mm->header->code);
260 g_print ("0x%04x %02x\n",
261 ip-mm->header->code, *ip);
263 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
265 #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);
268 interp_create_remoting_trampoline (MonoMethod *method)
270 return mono_marshal_get_remoting_invoke (method);
274 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
279 gboolean is_proxy = FALSE;
282 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
286 if ((klass = obj->vtable->klass) == mono_defaults.transparent_proxy_class) {
287 klass = ((MonoTransparentProxy *)obj)->klass;
290 vtable = (MonoMethod **)klass->vtable;
292 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
293 res = ((MonoMethod **)obj->vtable->interface_offsets [m->klass->interface_id]) [m->slot];
295 res = vtable [m->slot];
300 return mono_marshal_get_remoting_invoke (res);
306 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
309 switch (type->type) {
310 case MONO_TYPE_OBJECT:
311 case MONO_TYPE_CLASS:
312 case MONO_TYPE_STRING:
313 case MONO_TYPE_ARRAY:
314 case MONO_TYPE_SZARRAY:
315 result->type = VAL_OBJ;
318 result->type = VAL_MP;
321 result->data.p = *(gpointer*)data;
324 switch (type->type) {
328 result->type = VAL_I32;
329 result->data.i = *(gint8*)data;
332 case MONO_TYPE_BOOLEAN:
333 result->type = VAL_I32;
334 result->data.i = *(guint8*)data;
337 result->type = VAL_I32;
338 result->data.i = *(gint16*)data;
342 result->type = VAL_I32;
343 result->data.i = *(guint16*)data;
346 result->type = VAL_I32;
347 result->data.i = *(gint32*)data;
351 result->type = VAL_NATI;
352 result->data.nati = *(mono_i*)data;
355 result->type = VAL_TP;
356 result->data.p = *(gpointer*)data;
359 result->type = VAL_I32;
360 result->data.i = *(guint32*)data;
363 result->type = VAL_DOUBLE;
364 result->data.f = *(float*)data;
368 result->type = VAL_I64;
369 result->data.l = *(gint64*)data;
372 result->type = VAL_DOUBLE;
373 result->data.f = *(double*)data;
375 case MONO_TYPE_STRING:
376 case MONO_TYPE_SZARRAY:
377 case MONO_TYPE_CLASS:
378 case MONO_TYPE_OBJECT:
379 case MONO_TYPE_ARRAY:
380 result->type = VAL_OBJ;
381 result->data.p = *(gpointer*)data;
383 case MONO_TYPE_VALUETYPE:
384 if (type->data.klass->enumtype) {
385 stackval_from_data (type->data.klass->enum_basetype, result, data, pinvoke);
389 result->type = VAL_VALUET;
392 size = mono_class_native_size (type->data.klass, NULL);
394 size = mono_class_value_size (type->data.klass, NULL);
395 memcpy (result->data.vt, data, size);
399 g_warning ("got type 0x%02x", type->type);
400 g_assert_not_reached ();
405 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
408 gpointer *p = (gpointer*)data;
412 //printf ("TODAT0 %p\n", data);
413 switch (type->type) {
416 guint8 *p = (guint8*)data;
420 case MONO_TYPE_BOOLEAN: {
421 guint8 *p = (guint8*)data;
422 *p = (val->data.i != 0);
427 case MONO_TYPE_CHAR: {
428 guint16 *p = (guint16*)data;
433 mono_i *p = (mono_i*)data;
434 /* In theory the value used by stloc should match the local var type
435 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
436 a native int - both by csc and mcs). Not sure what to do about sign extension
437 as it is outside the spec... doing the obvious */
438 *p = val->type == VAL_I32 ? val->data.i : val->data.nati;
442 mono_u *p = (mono_u*)data;
444 *p = val->type == VAL_I32 ? (guint32)val->data.i : val->data.nati;
449 gint32 *p = (gint32*)data;
455 gint64 *p = (gint64*)data;
460 float *p = (float*)data;
465 double *p = (double*)data;
469 case MONO_TYPE_STRING:
470 case MONO_TYPE_SZARRAY:
471 case MONO_TYPE_CLASS:
472 case MONO_TYPE_OBJECT:
473 case MONO_TYPE_ARRAY:
474 case MONO_TYPE_PTR: {
475 gpointer *p = (gpointer*)data;
479 case MONO_TYPE_VALUETYPE:
480 if (type->data.klass->enumtype) {
481 stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
487 size = mono_class_native_size (type->data.klass, NULL);
489 size = mono_class_value_size (type->data.klass, NULL);
491 memcpy (data, val->data.vt, size);
495 g_warning ("got type %x", type->type);
496 g_assert_not_reached ();
500 #define FILL_IN_TRACE(exception, frame) \
503 stack_trace = dump_frame (frame); \
504 (exception)->stack_trace = mono_string_new (mono_domain_get(), stack_trace); \
505 g_free (stack_trace); \
508 #define THROW_EX(exception,ex_ip) \
510 frame->ip = (ex_ip); \
511 frame->ex = (MonoException*)(exception); \
512 FILL_IN_TRACE(frame->ex, frame); \
513 goto handle_exception; \
517 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
520 guint32 *lower_bounds;
523 lengths = alloca (sizeof (guint32) * klass->rank * 2);
524 for (i = 0; i < sig->param_count; ++i) {
525 lengths [i] = values->data.i;
528 if (klass->rank == sig->param_count) {
529 /* Only lengths provided. */
532 /* lower bounds are first. */
533 lower_bounds = lengths;
534 lengths += klass->rank;
536 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
540 ves_array_set (MonoInvocation *frame)
542 stackval *sp = frame->stack_args;
546 gint32 i, t, pos, esize;
552 ac = o->vtable->klass;
554 g_assert (ac->rank >= 1);
557 if (ao->bounds != NULL) {
558 pos -= ao->bounds [0].lower_bound;
559 for (i = 1; i < ac->rank; i++) {
560 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
561 ao->bounds [i].length) {
562 frame->ex = mono_get_exception_index_out_of_range ();
563 FILL_IN_TRACE(frame->ex, frame);
566 pos = pos*ao->bounds [i].length + sp [i].data.i -
567 ao->bounds [i].lower_bound;
569 } else if (pos >= ao->max_length) {
570 frame->ex = mono_get_exception_index_out_of_range ();
571 FILL_IN_TRACE(frame->ex, frame);
575 esize = mono_array_element_size (ac);
576 ea = mono_array_addr_with_size (ao, esize, pos);
578 mt = frame->method->signature->params [ac->rank];
579 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
583 ves_array_get (MonoInvocation *frame)
585 stackval *sp = frame->stack_args;
589 gint32 i, t, pos, esize;
595 ac = o->vtable->klass;
597 g_assert (ac->rank >= 1);
600 if (ao->bounds != NULL) {
601 pos -= ao->bounds [0].lower_bound;
602 for (i = 1; i < ac->rank; i++) {
603 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
604 ao->bounds [i].length) {
605 frame->ex = mono_get_exception_index_out_of_range ();
606 FILL_IN_TRACE(frame->ex, frame);
610 pos = pos*ao->bounds [i].length + sp [i].data.i -
611 ao->bounds [i].lower_bound;
613 } else if (pos >= ao->max_length) {
614 frame->ex = mono_get_exception_index_out_of_range ();
615 FILL_IN_TRACE(frame->ex, frame);
619 esize = mono_array_element_size (ac);
620 ea = mono_array_addr_with_size (ao, esize, pos);
622 mt = frame->method->signature->ret;
623 stackval_from_data (mt, frame->retval, ea, FALSE);
627 ves_array_element_address (MonoInvocation *frame)
629 stackval *sp = frame->stack_args;
633 gint32 i, t, pos, esize;
638 ac = o->vtable->klass;
640 g_assert (ac->rank >= 1);
643 if (ao->bounds != NULL) {
644 pos -= ao->bounds [0].lower_bound;
645 for (i = 1; i < ac->rank; i++) {
646 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
647 ao->bounds [i].length) {
648 frame->ex = mono_get_exception_index_out_of_range ();
649 FILL_IN_TRACE(frame->ex, frame);
652 pos = pos*ao->bounds [i].length + sp [i].data.i -
653 ao->bounds [i].lower_bound;
655 } else if (pos >= ao->max_length) {
656 frame->ex = mono_get_exception_index_out_of_range ();
657 FILL_IN_TRACE(frame->ex, frame);
661 esize = mono_array_element_size (ac);
662 ea = mono_array_addr_with_size (ao, esize, pos);
664 frame->retval->type = VAL_MP;
665 frame->retval->data.p = ea;
669 interp_walk_stack (MonoStackWalk func, gpointer user_data)
671 ThreadContext *context = TlsGetValue (thread_context_id);
672 MonoInvocation *frame = context->current_frame;
674 MonoMethodHeader *hd;
677 gboolean managed = FALSE;
678 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
679 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
682 hd = ((MonoMethodNormal*)frame->method)->header;
683 il_offset = frame->ip - hd->code;
684 if (!frame->method->wrapper_type)
687 if (func (frame->method, -1, il_offset, managed, user_data))
689 frame = frame->parent;
694 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor, ThreadContext *context)
698 MonoInvocation *old_frame = context->current_frame;
699 MonoInvocation *old_env_frame = context->env_frame;
700 jmp_buf *old_env = context->current_env;
703 context->current_frame = old_frame;
704 context->env_frame = old_env_frame;
705 context->current_env = old_env;
706 context->search_for_handler = 0;
710 context->env_frame = frame;
711 context->current_env = &env;
714 if (!frame->method->info) {
715 func = frame->method->info = mono_create_trampoline (sig, string_ctor);
717 func = (MonoPIFunc)frame->method->info;
720 func = mono_create_trampoline (sig, string_ctor);
723 context->current_frame = frame;
725 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
728 stackval_from_data (&mono_defaults.string_class->byval_arg,
729 frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
730 } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
731 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
733 context->current_frame = old_frame;
734 context->env_frame = old_env_frame;
735 context->current_env = old_env;
740 * runtime specifies that the implementation of the method is automatically
741 * provided by the runtime and is primarily used for the methods of delegates.
744 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
746 const char *name = frame->method->name;
747 MonoObject *obj = (MonoObject*)frame->obj;
752 mono_class_init (frame->method->klass);
754 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
755 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
756 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
759 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
760 nm = mono_marshal_get_delegate_invoke (frame->method);
761 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
762 ves_exec_method_with_context (&call, context);
766 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
767 nm = mono_marshal_get_delegate_begin_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 == 'E' && (strcmp (name, "EndInvoke") == 0)) {
774 nm = mono_marshal_get_delegate_end_invoke (frame->method);
775 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
776 ves_exec_method_with_context (&call, context);
782 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
783 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
784 ves_array_set (frame);
787 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
788 ves_array_get (frame);
791 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
792 ves_array_element_address (frame);
797 g_error ("Don't know how to exec runtime method %s.%s::%s",
798 frame->method->klass->name_space, frame->method->klass->name,
799 frame->method->name);
803 dump_stack (stackval *stack, stackval *sp)
806 GString *str = g_string_new ("");
809 return g_string_free (str, FALSE);
813 #if SIZEOF_VOID_P == 4
814 case VAL_NATI: g_string_sprintfa (str, "[%d/0x%0x] ", s->data.nati, s->data.nati); break;
816 case VAL_NATI: g_string_sprintfa (str, "[%lld/0x%0llx] ", s->data.nati, s->data.nati); break;
818 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
819 case VAL_I64: g_string_sprintfa (str, "[%lldL] ", s->data.l); break;
820 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
822 if (!global_no_pointers)
823 g_string_sprintfa (str, "[vt: %p] ", s->data.vt);
825 g_string_sprintfa (str, "[vt%s] ", s->data.vt ? "" : "=null");
828 MonoObject *obj = s->data.p;
829 if (global_no_pointers && obj && obj->vtable) {
830 MonoClass *klass = mono_object_class (obj);
831 if (klass == mono_defaults.string_class) {
832 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
833 g_string_sprintfa (str, "[str:%s] ", utf8);
836 } else if (klass == mono_defaults.sbyte_class) {
837 g_string_sprintfa (str, "[b:%d] ",
838 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
840 } else if (klass == mono_defaults.int16_class) {
841 g_string_sprintfa (str, "[b:%d] ",
842 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
844 } else if (klass == mono_defaults.int32_class) {
845 g_string_sprintfa (str, "[b:%d] ",
846 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
848 } else if (klass == mono_defaults.byte_class) {
849 g_string_sprintfa (str, "[b:%u] ",
850 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
852 } else if (klass == mono_defaults.char_class
853 || klass == mono_defaults.uint16_class) {
854 g_string_sprintfa (str, "[b:%u] ",
855 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
857 } else if (klass == mono_defaults.uint32_class) {
858 g_string_sprintfa (str, "[b:%u] ",
859 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
861 } else if (klass == mono_defaults.int64_class) {
862 g_string_sprintfa (str, "[b:%lld] ",
863 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
865 } else if (klass == mono_defaults.uint64_class) {
866 g_string_sprintfa (str, "[b:%llu] ",
867 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
869 } else if (klass == mono_defaults.double_class) {
870 g_string_sprintfa (str, "[b:%0.5f] ",
871 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
873 } else if (klass == mono_defaults.single_class) {
874 g_string_sprintfa (str, "[b:%0.5f] ",
875 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
877 } else if (klass == mono_defaults.boolean_class) {
878 g_string_sprintfa (str, "[b:%s] ",
879 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
887 if (!global_no_pointers)
888 g_string_sprintfa (str, "[%c:%p] ", s->type == VAL_OBJ ? 'O' : s->type == VAL_MP ? 'M' : '?', s->data.p);
890 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
895 return g_string_free (str, FALSE);
899 dump_frame (MonoInvocation *inv)
901 GString *str = g_string_new ("");
904 for (i = 0; inv; inv = inv->parent, ++i) {
905 if (inv->method != NULL) {
909 const char * opname = "";
910 gchar *source = NULL;
917 k = inv->method->klass;
919 if ((inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
920 (inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
921 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
925 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
928 opname = mono_opcode_names [codep];
929 codep = inv->ip - hd->code;
931 source = mono_debug_source_location_from_il_offset (inv->method, codep, NULL);
934 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
936 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s) at %s\n", i, codep, opname,
937 k->name_space, k->name, inv->method->name, args, source);
939 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
940 k->name_space, k->name, inv->method->name, args);
945 return g_string_free (str, FALSE);
949 INLINE_STRING_LENGTH = 1,
950 INLINE_STRING_GET_CHARS,
953 INLINE_TYPE_ELEMENT_TYPE
958 MonoClassField *field;
959 } MonoRuntimeFieldInfo;
965 MonoRuntimeFieldInfo *field_info;
970 write32(unsigned char *p, guint32 v)
973 p[1] = (v >> 8) & 0xff;
974 p[2] = (v >> 16) & 0xff;
975 p[3] = (v >> 24) & 0xff;
978 static CRITICAL_SECTION calc_section;
981 calc_offsets (MonoImage *image, MonoMethod *method)
983 int i, align, size, offset = 0;
984 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
985 MonoMethodSignature *signature = method->signature;
986 register const unsigned char *ip, *end;
987 const MonoOpcode *opcode;
991 MonoDomain *domain = mono_domain_get ();
992 MethodRuntimeData *rtd;
995 mono_profiler_method_jit (method); /* sort of... */
996 /* intern the strings in the method. */
998 end = ip + header->code_size;
1005 opcode = &mono_opcodes [i];
1006 switch (opcode->argument) {
1007 case MonoInlineNone:
1010 case MonoInlineString:
1011 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
1014 case MonoInlineType:
1015 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1016 class = mono_class_get (image, read32 (ip + 1));
1017 mono_class_init (class);
1018 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
1019 mono_class_vtable (domain, class);
1023 case MonoInlineField:
1027 case MonoInlineMethod:
1028 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1029 m = mono_get_method (image, read32 (ip + 1), NULL);
1030 mono_class_init (m->klass);
1031 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
1032 mono_class_vtable (domain, m->klass);
1038 case MonoShortInlineR:
1040 case MonoInlineBrTarget:
1046 case MonoShortInlineVar:
1047 case MonoShortInlineI:
1048 case MonoShortInlineBrTarget:
1051 case MonoInlineSwitch: {
1064 g_assert_not_reached ();
1069 /* the rest needs to be locked so it is only done once */
1070 EnterCriticalSection(&calc_section);
1071 if (method->info != NULL) {
1072 LeaveCriticalSection(&calc_section);
1073 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1076 rtd = (MethodRuntimeData *)g_malloc0 (sizeof(MethodRuntimeData) + (header->num_locals - 1 + signature->hasthis + signature->param_count) * sizeof(guint32));
1077 for (i = 0; i < header->num_locals; ++i) {
1078 size = mono_type_size (header->locals [i], &align);
1079 offset += align - 1;
1080 offset &= ~(align - 1);
1081 rtd->offsets [i] = offset;
1084 rtd->locals_size = offset;
1086 if (signature->hasthis) {
1087 offset += sizeof (gpointer) - 1;
1088 offset &= ~(sizeof (gpointer) - 1);
1089 rtd->offsets [header->num_locals] = offset;
1090 offset += sizeof (gpointer);
1092 for (i = 0; i < signature->param_count; ++i) {
1093 if (signature->pinvoke) {
1094 size = mono_type_native_stack_size (signature->params [i], &align);
1098 size = mono_type_stack_size (signature->params [i], &align);
1099 offset += align - 1;
1100 offset &= ~(align - 1);
1101 rtd->offsets [signature->hasthis + header->num_locals + i] = offset;
1104 rtd->args_size = offset;
1105 rtd->field_info = g_malloc(n_fields * sizeof(MonoRuntimeFieldInfo));
1107 header->code = g_memdup(header->code, header->code_size);
1110 end = ip + header->code_size;
1117 opcode = &mono_opcodes [i];
1118 switch (opcode->argument) {
1119 case MonoInlineNone:
1122 case MonoInlineString:
1125 case MonoInlineType:
1128 case MonoInlineField:
1129 token = read32 (ip + 1);
1130 rtd->field_info[n_fields].field = mono_field_from_token (image, token, &class);
1131 mono_class_vtable (domain, class);
1132 g_assert(rtd->field_info[n_fields].field->parent == class);
1133 write32 ((unsigned char *)ip + 1, n_fields);
1137 case MonoInlineMethod:
1142 case MonoShortInlineR:
1144 case MonoInlineBrTarget:
1150 case MonoShortInlineVar:
1151 case MonoShortInlineI:
1152 case MonoShortInlineBrTarget:
1155 case MonoInlineSwitch: {
1168 g_assert_not_reached ();
1174 * We store the inline info in addr, since it's unused for IL methods.
1176 if (method->klass == mono_defaults.string_class) {
1177 if (strcmp (method->name, "get_Length") == 0)
1178 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
1179 else if (strcmp (method->name, "get_Chars") == 0)
1180 method->addr = GUINT_TO_POINTER (INLINE_STRING_GET_CHARS);
1181 } else if (method->klass == mono_defaults.array_class) {
1182 if (strcmp (method->name, "get_Length") == 0)
1183 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
1184 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
1185 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
1186 } else if (method->klass == mono_defaults.monotype_class) {
1187 if (strcmp (method->name, "GetElementType") == 0)
1188 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
1190 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1192 LeaveCriticalSection(&calc_section);
1195 #define LOCAL_POS(n) (frame->locals + rtd->offsets [n])
1196 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1198 #define ARG_POS(n) (args_pointers [(n)])
1199 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1200 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1202 typedef struct _vtallocation vtallocation;
1204 struct _vtallocation {
1209 char data [MONO_ZERO_LEN_ARRAY];
1210 double force_alignment;
1214 #define vt_allocmem(sz, var) \
1216 vtallocation *tmp, *prev; \
1219 while (tmp && (tmp->max_size < (sz))) { \
1224 tmp = alloca (sizeof (vtallocation) + (sz)); \
1225 tmp->max_size = (sz); \
1226 g_assert ((sz) < 10000); \
1230 prev->next = tmp->next; \
1232 vtalloc = tmp->next; \
1234 var = tmp->u.data; \
1237 #define vt_alloc(vtype,sp,native) \
1238 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1239 if (!(vtype)->byref) { \
1241 if (native) vtsize = mono_class_native_size ((vtype)->data.klass, NULL); \
1242 else vtsize = mono_class_value_size ((vtype)->data.klass, NULL); \
1243 vt_allocmem(vtsize, (sp)->data.vt); \
1247 #define vt_free(sp) \
1249 if ((sp)->type == VAL_VALUET) { \
1250 vtallocation *tmp = (vtallocation*)(((char*)(sp)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1251 tmp->next = vtalloc; \
1256 #define stackvalpush(val, sp) \
1258 (sp)->type = (val)->type; \
1259 (sp)->data = (val)->data; \
1260 if ((val)->type == VAL_VALUET) { \
1261 vtallocation *vala = (vtallocation*)(((char*)(val)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1262 vt_allocmem(vala->size, (sp)->data.vt); \
1263 memcpy((sp)->data.vt, (val)->data.vt, vala->size); \
1268 #define stackvalcpy(src, dest) \
1270 (dest)->type = (src)->type; \
1271 (dest)->data = (src)->data; \
1272 if ((dest)->type == VAL_VALUET) { \
1273 vtallocation *tmp = (vtallocation*)(((char*)(src)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1274 memcpy((dest)->data.vt, (src)->data.vt, tmp->size); \
1280 verify_method (MonoMethod *m)
1282 GSList *errors, *tmp;
1283 MonoVerifyInfo *info;
1285 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1287 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1288 for (tmp = errors; tmp; tmp = tmp->next) {
1290 g_print ("%s\n", info->message);
1294 mono_free_verify_list (errors);
1298 #define MYGUINT64_MAX 18446744073709551615ULL
1299 #define MYGINT64_MAX 9223372036854775807LL
1300 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1302 #define MYGUINT32_MAX 4294967295U
1303 #define MYGINT32_MAX 2147483647
1304 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1306 #define CHECK_ADD_OVERFLOW(a,b) \
1307 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1308 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1310 #define CHECK_SUB_OVERFLOW(a,b) \
1311 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1312 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1314 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1315 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1317 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1318 (guint32)(a) < (guint32)(b) ? -1 : 0
1320 #define CHECK_ADD_OVERFLOW64(a,b) \
1321 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1322 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1324 #define CHECK_SUB_OVERFLOW64(a,b) \
1325 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1326 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1328 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1329 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1331 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1332 (guint64)(a) < (guint64)(b) ? -1 : 0
1334 #if SIZEOF_VOID_P == 4
1335 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1336 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1338 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1339 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1342 /* Resolves to TRUE if the operands would overflow */
1343 #define CHECK_MUL_OVERFLOW(a,b) \
1344 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1345 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1346 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1347 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1348 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1349 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1350 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1352 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1353 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1354 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1356 #define CHECK_MUL_OVERFLOW64(a,b) \
1357 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1358 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1359 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1360 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1361 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1362 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1363 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1365 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1366 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1367 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1369 #if SIZEOF_VOID_P == 4
1370 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1371 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1373 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1374 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1378 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1380 MonoInvocation frame;
1381 ThreadContext *context = TlsGetValue (thread_context_id);
1382 MonoObject *retval = NULL;
1383 MonoMethodSignature *sig = method->signature;
1384 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1385 int i, type, isobject = 0;
1388 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1389 ThreadContext context_struct;
1390 MonoInvocation *old_frame;
1392 if (context == NULL) {
1393 context = &context_struct;
1394 context_struct.base_frame = &frame;
1395 context_struct.current_frame = NULL;
1396 context_struct.env_frame = NULL;
1397 context_struct.current_env = NULL;
1398 context_struct.search_for_handler = 0;
1399 TlsSetValue (thread_context_id, context);
1402 old_frame = context->current_frame;
1405 /* FIXME: Set frame for execption handling. */
1407 switch (sig->ret->type) {
1408 case MONO_TYPE_VOID:
1410 case MONO_TYPE_STRING:
1411 case MONO_TYPE_OBJECT:
1412 case MONO_TYPE_CLASS:
1413 case MONO_TYPE_ARRAY:
1414 case MONO_TYPE_SZARRAY:
1417 case MONO_TYPE_VALUETYPE:
1418 retval = mono_object_new (mono_domain_get (), klass);
1419 ret = ((char*)retval) + sizeof (MonoObject);
1420 if (!sig->ret->data.klass->enumtype)
1421 result.data.vt = ret;
1424 retval = mono_object_new (mono_domain_get (), klass);
1425 ret = ((char*)retval) + sizeof (MonoObject);
1429 for (i = 0; i < sig->param_count; ++i) {
1430 if (sig->params [i]->byref) {
1431 args [i].type = VAL_POINTER;
1432 args [i].data.p = params [i];
1435 type = sig->params [i]->type;
1440 case MONO_TYPE_BOOLEAN:
1441 args [i].type = VAL_I32;
1442 args [i].data.i = *(MonoBoolean*)params [i];
1446 case MONO_TYPE_CHAR:
1447 args [i].type = VAL_I32;
1448 args [i].data.i = *(gint16*)params [i];
1450 #if SIZEOF_VOID_P == 4
1451 case MONO_TYPE_U: /* use VAL_POINTER? */
1456 args [i].type = VAL_I32;
1457 args [i].data.i = *(gint32*)params [i];
1459 #if SIZEOF_VOID_P == 8
1465 args [i].type = VAL_I64;
1466 args [i].data.l = *(gint64*)params [i];
1468 case MONO_TYPE_VALUETYPE:
1469 if (sig->params [i]->data.klass->enumtype) {
1470 type = sig->params [i]->data.klass->enum_basetype->type;
1473 args [i].type = VAL_POINTER;
1474 args [i].data.p = params [i];
1477 case MONO_TYPE_STRING:
1478 case MONO_TYPE_CLASS:
1479 case MONO_TYPE_ARRAY:
1480 case MONO_TYPE_SZARRAY:
1481 case MONO_TYPE_OBJECT:
1482 args [i].type = VAL_OBJ;
1483 args [i].data.p = params [i];
1486 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1490 if (method->klass->valuetype)
1491 /* Unbox the instance, since valuetype methods expect an interior pointer. */
1492 obj = mono_object_unbox (obj);
1494 INIT_FRAME(&frame,context->current_frame,obj,args,&result,method);
1496 frame.invoke_trap = 1;
1497 ves_exec_method_with_context (&frame, context);
1498 if (context == &context_struct)
1499 TlsSetValue (thread_context_id, NULL);
1501 context->current_frame = old_frame;
1502 if (frame.ex != NULL) {
1504 *exc = (MonoObject*) frame.ex;
1505 if (*exc == (MonoObject *)quit_exception)
1506 mono_print_unhandled_exception(*exc);
1509 if (context->current_env != NULL) {
1510 context->env_frame->ex = frame.ex;
1511 longjmp(*context->current_env, 1);
1514 printf("dropped exception...\n");
1516 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1518 if (isobject || method->string_ctor)
1519 return result.data.p;
1520 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1525 get_native_wrapper(MonoMethod *method, ThreadContext *context)
1529 MonoMethod *wrapper;
1530 old_env = context->current_env;
1531 if (setjmp(env) != 0) {
1532 context->current_env = old_env;
1533 context->search_for_handler = 1;
1536 context->current_env = &env;
1537 wrapper = mono_marshal_get_native_wrapper (method);
1538 context->current_env = old_env;
1543 * Need to optimize ALU ops when natural int == int32
1545 * IDEA: if we maintain a stack of ip, sp to be checked
1546 * in the return opcode, we could inline simple methods that don't
1547 * use the stack or local variables....
1549 * The {,.S} versions of many opcodes can/should be merged to reduce code
1554 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
1556 MonoDomain *domain = mono_domain_get ();
1557 MonoInvocation child_frame;
1558 MonoMethodHeader *header;
1559 MonoMethodSignature *signature;
1561 GSList *finally_ips = NULL;
1562 const unsigned char *endfinally_ip = NULL;
1563 register const unsigned char *ip;
1564 register stackval *sp = NULL;
1565 MethodRuntimeData *rtd;
1566 void **args_pointers;
1567 gint tracing = global_tracing;
1568 unsigned char tail_recursion = 0;
1569 unsigned char unaligned_address = 0;
1570 unsigned char volatile_address = 0;
1571 vtallocation *vtalloc = NULL;
1572 MonoVTable *method_class_vt;
1576 frame->ip = ip = NULL;
1577 context->current_frame = frame;
1579 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1580 frame->method = get_native_wrapper (frame->method, context);
1581 if (frame->method == NULL)
1585 method_class_vt = mono_class_vtable (domain, frame->method->klass);
1586 if (!method_class_vt->initialized)
1587 mono_runtime_class_init (method_class_vt);
1588 signature = frame->method->signature;
1592 header = ((MonoMethodNormal *)frame->method)->header;
1594 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1595 if (!frame->method->addr) {
1596 /* ugly, but needed by the iflags setting in loader.c */
1597 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1598 ves_runtime_method (frame, context);
1600 goto handle_exception;
1603 if (frame->method->addr) {
1604 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1605 goto handle_exception;
1608 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1609 frame->method->string_ctor, context);
1611 goto handle_exception;
1615 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1616 ves_runtime_method (frame, context);
1618 goto handle_exception;
1622 /*verify_method (frame->method);*/
1624 image = frame->method->klass->image;
1626 if (!frame->method->info)
1627 calc_offsets (image, frame->method);
1628 rtd = frame->method->info;
1631 * with alloca we get the expected huge performance gain
1632 * stackval *stack = g_new0(stackval, header->max_stack);
1634 g_assert (header->max_stack < 10000);
1635 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1637 if (header->num_locals) {
1638 g_assert (rtd->locals_size < 65536);
1639 frame->locals = alloca (rtd->locals_size);
1641 * yes, we do it unconditionally, because it needs to be done for
1642 * some cases anyway and checking for that would be even slower.
1644 memset (frame->locals, 0, rtd->locals_size);
1648 * Copy args from stack_args to args.
1650 if (signature->param_count || signature->hasthis) {
1652 int has_this = signature->hasthis;
1654 g_assert (rtd->args_size < 10000);
1655 frame->args = alloca (rtd->args_size);
1656 g_assert ((signature->param_count + has_this) < 1000);
1657 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1660 this_arg = args_pointers [0] = frame->args;
1661 *this_arg = frame->obj;
1663 for (i = 0; i < signature->param_count; ++i) {
1664 args_pointers [i + has_this] = frame->args + rtd->offsets [header->num_locals + has_this + i];
1665 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1669 child_frame.parent = frame;
1670 frame->child = &child_frame;
1677 * using while (ip < end) may result in a 15% performance drop,
1678 * but it may be useful for debug
1682 /*g_assert (sp >= stack);*/
1686 char *ins, *discode;
1687 if (sp > frame->stack) {
1688 ins = dump_stack (frame->stack, sp);
1690 ins = g_strdup ("");
1693 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1694 discode [strlen (discode) - 1] = 0; /* no \n */
1695 g_print ("(%u) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1707 G_BREAKPOINT (); /* this is not portable... */
1712 CASE (CEE_LDARG_3) {
1713 int n = (*ip)-CEE_LDARG_0;
1715 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1716 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1723 CASE (CEE_LDLOC_3) {
1724 int n = (*ip)-CEE_LDLOC_0;
1725 MonoType *vartype = LOCAL_TYPE (header, n);
1727 if (vartype->type == MONO_TYPE_I4) {
1729 sp->data.i = *(gint32*) LOCAL_POS (n);
1733 vt_alloc (vartype, sp, FALSE);
1734 stackval_from_data (vartype, sp, LOCAL_POS (n), FALSE);
1742 CASE (CEE_STLOC_3) {
1743 int n = (*ip)-CEE_STLOC_0;
1746 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1747 gint32 *p = (gint32*)LOCAL_POS (n);
1751 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1758 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1759 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1763 CASE (CEE_LDARGA_S) {
1765 sp->data.vt = ARG_POS (*ip);
1774 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1780 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1781 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1785 CASE (CEE_LDLOCA_S) {
1787 sp->data.p = LOCAL_POS (*ip);
1796 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1806 CASE (CEE_LDC_I4_M1)
1822 sp->data.i = (*ip) - CEE_LDC_I4_0;
1829 sp->data.i = *(const gint8 *)ip;
1836 sp->data.i = read32 (ip);
1843 sp->data.l = read64 (ip);
1850 sp->type = VAL_DOUBLE;
1859 sp->type = VAL_DOUBLE;
1860 readr8(ip, &sp->data.f);
1864 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1866 stackvalpush(sp - 1, sp);
1874 CASE (CEE_JMP) ves_abort(); BREAK;
1875 CASE (CEE_CALLVIRT) /* Fall through */
1876 CASE (CEE_CALLI) /* Fall through */
1878 MonoMethodSignature *csignature;
1880 stackval *endsp = sp;
1882 int virtual = *ip == CEE_CALLVIRT;
1883 int calli = *ip == CEE_CALLI;
1884 unsigned char *code = NULL;
1887 * We ignore tail recursion for now.
1894 token = read32 (ip);
1900 if (frame->method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE &&
1901 (ji = mono_jit_info_table_find (mono_root_domain, code)) != NULL) {
1902 child_frame.method = ji->method;
1903 csignature = ji->method->signature;
1905 else if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1906 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1907 child_frame.method = NULL;
1909 g_assert_not_reached ();
1913 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
1914 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
1916 child_frame.method = mono_get_method (image, token, NULL);
1917 if (!child_frame.method)
1918 THROW_EX (mono_get_exception_missing_method (), ip -5);
1919 csignature = child_frame.method->signature;
1921 stackval *this_arg = &sp [-csignature->param_count-1];
1922 if (!this_arg->data.p)
1923 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1924 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1925 if (!child_frame.method)
1926 THROW_EX (mono_get_exception_missing_method (), ip -5);
1930 if (frame->method->wrapper_type == MONO_WRAPPER_NONE)
1931 if (child_frame.method && child_frame.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1932 child_frame.method = mono_marshal_get_synchronized_wrapper (child_frame.method);
1934 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
1935 /* decrement by the actual number of args */
1936 if (csignature->param_count) {
1937 sp -= csignature->param_count;
1938 child_frame.stack_args = sp;
1940 child_frame.stack_args = NULL;
1942 if (csignature->hasthis) {
1943 g_assert (sp >= frame->stack);
1946 * It may also be a TP from LD(S)FLDA
1947 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_MP);
1949 if (sp->type == VAL_OBJ && child_frame.method &&
1950 child_frame.method->klass->valuetype) /* unbox it */
1951 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1953 child_frame.obj = sp->data.p;
1955 child_frame.obj = NULL;
1957 if (csignature->ret->type != MONO_TYPE_VOID) {
1958 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
1959 child_frame.retval = &retval;
1961 child_frame.retval = NULL;
1964 child_frame.ip = NULL;
1965 child_frame.ex = NULL;
1966 child_frame.ex_handler = NULL;
1968 if (!child_frame.method) {
1970 ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE, context);
1971 if (child_frame.ex) {
1972 frame->ex = child_frame.ex;
1973 goto handle_exception;
1975 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
1976 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
1977 g_assert (child_frame.method);
1978 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
1979 ves_exec_method_with_context (&child_frame, context);
1981 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1982 case INLINE_STRING_LENGTH:
1983 retval.type = VAL_I32;
1984 retval.data.i = ((MonoString*)sp->data.p)->length;
1985 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
1987 case INLINE_STRING_GET_CHARS: {
1988 int idx = GET_NATI(sp [1]);
1989 if ((idx < 0) || (idx >= mono_string_length ((MonoString*)sp->data.p))) {
1990 child_frame.ex = mono_get_exception_index_out_of_range ();
1991 FILL_IN_TRACE(child_frame.ex, &child_frame);
1994 retval.type = VAL_I32;
1995 retval.data.i = mono_string_chars((MonoString*)sp->data.p)[idx];
1999 case INLINE_ARRAY_LENGTH:
2000 retval.type = VAL_I32;
2001 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
2003 case INLINE_ARRAY_RANK:
2004 retval.type = VAL_I32;
2005 retval.data.i = mono_object_class (sp->data.p)->rank;
2007 case INLINE_TYPE_ELEMENT_TYPE:
2008 retval.type = VAL_OBJ;
2010 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
2011 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
2012 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
2013 else if (c->element_class)
2014 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
2016 retval.data.p = NULL;
2020 ves_exec_method_with_context (&child_frame, context);
2024 context->current_frame = frame;
2026 while (endsp > sp) {
2031 if (child_frame.ex) {
2033 * An exception occurred, need to run finally, fault and catch handlers..
2035 frame->ex = child_frame.ex;
2036 if (context->search_for_handler) {
2037 context->search_for_handler = 0;
2038 goto handle_exception;
2040 goto handle_finally;
2043 /* need to handle typedbyref ... */
2044 if (csignature->ret->type != MONO_TYPE_VOID) {
2051 if (signature->ret->type != MONO_TYPE_VOID) {
2053 if (sp->type == VAL_VALUET) {
2054 /* the caller has already allocated the memory */
2055 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
2058 *frame->retval = *sp;
2061 if (sp > frame->stack)
2062 g_warning ("more values on stack: %d", sp-frame->stack);
2065 CASE (CEE_BR_S) /* Fall through */
2067 if (*ip == CEE_BR) {
2069 ip += (gint32) read32(ip);
2073 ip += (signed char) *ip;
2077 CASE (CEE_BRFALSE) /* Fall through */
2078 CASE (CEE_BRFALSE_S) {
2081 if (*ip == CEE_BRFALSE_S) {
2082 broffset = (signed char)ip [1];
2085 broffset = (gint32) read32 (ip + 1);
2090 case VAL_I32: result = sp->data.i == 0; break;
2091 case VAL_I64: result = sp->data.l == 0; break;
2092 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
2093 default: result = sp->data.p == NULL; break;
2099 CASE (CEE_BRTRUE) /* Fall through */
2100 CASE (CEE_BRTRUE_S) {
2103 if (*ip == CEE_BRTRUE_S) {
2104 broffset = (signed char)ip [1];
2107 broffset = (gint32) read32 (ip + 1);
2112 case VAL_I32: result = sp->data.i != 0; break;
2113 case VAL_I64: result = sp->data.l != 0; break;
2114 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
2115 default: result = sp->data.p != NULL; break;
2121 CASE (CEE_BEQ) /* Fall through */
2125 if (*ip == CEE_BEQ_S) {
2126 broffset = (signed char)ip [1];
2129 broffset = (gint32) read32 (ip + 1);
2133 if (sp->type == VAL_I32)
2134 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
2135 else if (sp->type == VAL_I64)
2136 result = sp [0].data.l == sp [1].data.l;
2137 else if (sp->type == VAL_DOUBLE)
2138 result = sp [0].data.f == sp [1].data.f;
2140 result = sp [0].data.nati == (mono_i)GET_NATI (sp [1]);
2145 CASE (CEE_BGE) /* Fall through */
2149 if (*ip == CEE_BGE_S) {
2150 broffset = (signed char)ip [1];
2153 broffset = (gint32) read32 (ip + 1);
2157 if (sp->type == VAL_I32)
2158 result = (mono_i)sp [0].data.i >= (mono_i)GET_NATI (sp [1]);
2159 else if (sp->type == VAL_I64)
2160 result = sp [0].data.l >= sp [1].data.l;
2161 else if (sp->type == VAL_DOUBLE)
2162 result = sp [0].data.f >= sp [1].data.f;
2164 result = (mono_i)sp [0].data.nati >= (mono_i)GET_NATI (sp [1]);
2169 CASE (CEE_BGT) /* Fall through */
2173 if (*ip == CEE_BGT_S) {
2174 broffset = (signed char)ip [1];
2177 broffset = (gint32) read32 (ip + 1);
2181 if (sp->type == VAL_I32)
2182 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
2183 else if (sp->type == VAL_I64)
2184 result = sp [0].data.l > sp [1].data.l;
2185 else if (sp->type == VAL_DOUBLE)
2186 result = sp [0].data.f > sp [1].data.f;
2188 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
2193 CASE (CEE_BLT) /* Fall through */
2197 if (*ip == CEE_BLT_S) {
2198 broffset = (signed char)ip [1];
2201 broffset = (gint32) read32 (ip + 1);
2205 if (sp->type == VAL_I32)
2206 result = (mono_i)sp[0].data.i < (mono_i)GET_NATI(sp[1]);
2207 else if (sp->type == VAL_I64)
2208 result = sp[0].data.l < sp[1].data.l;
2209 else if (sp->type == VAL_DOUBLE)
2210 result = sp[0].data.f < sp[1].data.f;
2212 result = (mono_i)sp[0].data.nati < (mono_i)GET_NATI(sp[1]);
2217 CASE (CEE_BLE) /* fall through */
2221 if (*ip == CEE_BLE_S) {
2222 broffset = (signed char)ip [1];
2225 broffset = (gint32) read32 (ip + 1);
2230 if (sp->type == VAL_I32)
2231 result = (mono_i)sp [0].data.i <= (mono_i)GET_NATI (sp [1]);
2232 else if (sp->type == VAL_I64)
2233 result = sp [0].data.l <= sp [1].data.l;
2234 else if (sp->type == VAL_DOUBLE)
2235 result = sp [0].data.f <= sp [1].data.f;
2237 result = (mono_i)sp [0].data.nati <= (mono_i)GET_NATI (sp [1]);
2243 CASE (CEE_BNE_UN) /* Fall through */
2244 CASE (CEE_BNE_UN_S) {
2247 if (*ip == CEE_BNE_UN_S) {
2248 broffset = (signed char)ip [1];
2251 broffset = (gint32) read32 (ip + 1);
2255 if (sp->type == VAL_I32)
2256 result = (mono_u)sp [0].data.i != (mono_u)GET_NATI (sp [1]);
2257 else if (sp->type == VAL_I64)
2258 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
2259 else if (sp->type == VAL_DOUBLE)
2260 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2261 (sp [0].data.f != sp [1].data.f);
2263 result = (mono_u)sp [0].data.nati != (mono_u)GET_NATI (sp [1]);
2268 CASE (CEE_BGE_UN) /* Fall through */
2269 CASE (CEE_BGE_UN_S) {
2272 if (*ip == CEE_BGE_UN_S) {
2273 broffset = (signed char)ip [1];
2276 broffset = (gint32) read32 (ip + 1);
2280 if (sp->type == VAL_I32)
2281 result = (mono_u)sp [0].data.i >= (mono_u)GET_NATI (sp [1]);
2282 else if (sp->type == VAL_I64)
2283 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
2284 else if (sp->type == VAL_DOUBLE)
2285 result = !isless (sp [0].data.f,sp [1].data.f);
2287 result = (mono_u)sp [0].data.nati >= (mono_u)GET_NATI (sp [1]);
2292 CASE (CEE_BGT_UN) /* Fall through */
2293 CASE (CEE_BGT_UN_S) {
2296 if (*ip == CEE_BGT_UN_S) {
2297 broffset = (signed char)ip [1];
2300 broffset = (gint32) read32 (ip + 1);
2304 if (sp->type == VAL_I32)
2305 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2306 else if (sp->type == VAL_I64)
2307 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2308 else if (sp->type == VAL_DOUBLE)
2309 result = isgreater (sp [0].data.f, sp [1].data.f);
2311 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
2316 CASE (CEE_BLE_UN) /* Fall through */
2317 CASE (CEE_BLE_UN_S) {
2320 if (*ip == CEE_BLE_UN_S) {
2321 broffset = (signed char)ip [1];
2324 broffset = (gint32) read32 (ip + 1);
2328 if (sp->type == VAL_I32)
2329 result = (mono_u)sp [0].data.i <= (mono_u)GET_NATI (sp [1]);
2330 else if (sp->type == VAL_I64)
2331 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2332 else if (sp->type == VAL_DOUBLE)
2333 result = islessequal (sp [0].data.f, sp [1].data.f);
2335 result = (mono_u)sp [0].data.nati <= (mono_u)GET_NATI (sp [1]);
2340 CASE (CEE_BLT_UN) /* Fall through */
2341 CASE (CEE_BLT_UN_S) {
2344 if (*ip == CEE_BLT_UN_S) {
2345 broffset = (signed char)ip [1];
2348 broffset = (gint32) read32 (ip + 1);
2352 if (sp->type == VAL_I32)
2353 result = (mono_u)sp[0].data.i < (mono_u)GET_NATI(sp[1]);
2354 else if (sp->type == VAL_I64)
2355 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2356 else if (sp->type == VAL_DOUBLE)
2357 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2358 (sp [0].data.f < sp [1].data.f);
2360 result = (mono_u)sp[0].data.nati < (mono_u)GET_NATI(sp[1]);
2367 const unsigned char *st;
2371 st = ip + sizeof (gint32) * n;
2373 if ((guint32)sp->data.i < n) {
2375 ip += sizeof (gint32) * (guint32)sp->data.i;
2376 offset = read32 (ip);
2385 sp[-1].type = VAL_I32;
2386 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2390 sp[-1].type = VAL_I32;
2391 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2395 sp[-1].type = VAL_I32;
2396 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2400 sp[-1].type = VAL_I32;
2401 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2403 CASE (CEE_LDIND_I4) /* Fall through */
2406 sp[-1].type = VAL_I32;
2407 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2411 sp[-1].type = VAL_I64;
2412 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2416 sp[-1].type = VAL_NATI;
2417 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2421 sp[-1].type = VAL_DOUBLE;
2422 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2426 sp[-1].type = VAL_DOUBLE;
2427 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2429 CASE (CEE_LDIND_REF)
2431 sp[-1].type = VAL_OBJ;
2432 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2434 CASE (CEE_STIND_REF) {
2442 CASE (CEE_STIND_I1) {
2447 *p = (gint8)sp[1].data.i;
2450 CASE (CEE_STIND_I2) {
2455 *p = (gint16)sp[1].data.i;
2458 CASE (CEE_STIND_I4) {
2466 CASE (CEE_STIND_I) {
2471 *p = (mono_i)sp[1].data.p;
2474 CASE (CEE_STIND_I8) {
2482 CASE (CEE_STIND_R4) {
2487 *p = (gfloat)sp[1].data.f;
2490 CASE (CEE_STIND_R8) {
2501 /* should probably consider the pointers as unsigned */
2502 if (sp->type == VAL_I32) {
2503 if (sp [-1].type == VAL_I32)
2504 sp [-1].data.i += sp [0].data.i;
2506 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.i;
2507 } else if (sp->type == VAL_I64)
2508 sp [-1].data.l += sp [0].data.l;
2509 else if (sp->type == VAL_DOUBLE)
2510 sp [-1].data.f += sp [0].data.f;
2512 if (sp [-1].type == VAL_I32) {
2513 sp [-1].data.nati = sp [-1].data.i + sp [0].data.nati;
2514 sp [-1].type = sp [0].type;
2516 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.nati;
2522 /* should probably consider the pointers as unsigned */
2523 if (sp->type == VAL_I32) {
2524 if (sp [-1].type == VAL_I32)
2525 sp [-1].data.i -= sp [0].data.i;
2527 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
2528 sp [-1].type = VAL_NATI;
2530 } else if (sp->type == VAL_I64)
2531 sp [-1].data.l -= sp [0].data.l;
2532 else if (sp->type == VAL_DOUBLE)
2533 sp [-1].data.f -= sp [0].data.f;
2535 if (sp [-1].type == VAL_I32) {
2536 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
2537 sp [-1].type = sp [0].type;
2539 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
2545 if (sp->type == VAL_I32) {
2546 if (sp [-1].type == VAL_I32)
2547 sp [-1].data.i *= sp [0].data.i;
2549 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
2550 } else if (sp->type == VAL_I64)
2551 sp [-1].data.l *= sp [0].data.l;
2552 else if (sp->type == VAL_DOUBLE)
2553 sp [-1].data.f *= sp [0].data.f;
2555 if (sp [-1].type == VAL_NATI)
2556 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.nati;
2558 sp [-1].data.nati = sp [-1].data.i * sp [0].data.nati;
2559 sp [-1].type = VAL_NATI;
2566 if (sp->type == VAL_I32) {
2567 if (sp [0].data.i == 0)
2568 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2569 if (sp [-1].type == VAL_I32)
2570 sp [-1].data.i /= sp [0].data.i;
2572 sp [-1].data.nati /= sp [0].data.i;
2573 } else if (sp->type == VAL_I64) {
2574 if (sp [0].data.l == 0)
2575 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2576 sp [-1].data.l /= sp [0].data.l;
2577 } else if (sp->type == VAL_DOUBLE) {
2578 /* set NaN is divisor is 0.0 */
2579 sp [-1].data.f /= sp [0].data.f;
2581 if (sp [-1].type == VAL_NATI)
2582 sp [-1].data.nati = sp [-1].data.nati / sp [0].data.nati;
2584 sp [-1].data.nati = sp [-1].data.i / sp [0].data.nati;
2585 sp [-1].type = VAL_NATI;
2592 if (sp->type == VAL_I32) {
2593 if (sp [0].data.i == 0)
2594 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2595 if (sp [-1].type == VAL_NATI)
2596 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.i;
2598 sp [-1].data.i = (guint32)sp [-1].data.i / (guint32)sp [0].data.i;
2599 } else if (sp->type == VAL_I64) {
2601 if (sp [0].data.l == 0)
2602 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2603 val = sp [-1].data.l;
2604 val /= (guint64)sp [0].data.l;
2605 sp [-1].data.l = val;
2607 if (sp [0].data.nati == 0)
2608 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2609 if (sp [-1].type == VAL_NATI)
2610 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.nati;
2612 sp [-1].data.nati = (mono_u)sp [-1].data.i / (mono_u)sp [0].data.nati;
2613 sp [-1].type = VAL_NATI;
2620 if (sp->type == VAL_I32) {
2621 if (sp [0].data.i == 0)
2622 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2623 if (sp [-1].type == VAL_NATI)
2624 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.i;
2626 sp [-1].data.i = sp [-1].data.i % sp [0].data.i;
2627 } else if (sp->type == VAL_I64) {
2628 if (sp [0].data.l == 0)
2629 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2630 sp [-1].data.l %= sp [0].data.l;
2631 } else if (sp->type == VAL_DOUBLE) {
2632 /* FIXME: what do we actually do here? */
2633 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2635 if (sp [0].data.nati == 0)
2636 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2637 if (sp [-1].type == VAL_NATI)
2638 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.nati;
2640 sp [-1].data.nati = (mono_i)sp [-1].data.i % (mono_i)sp [0].data.nati;
2641 sp [-1].type = VAL_NATI;
2648 if (sp->type == VAL_I32) {
2649 if (sp [0].data.i == 0)
2650 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2651 if (sp [-1].type == VAL_NATI)
2652 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.i;
2654 sp [-1].data.i = (guint32)sp [-1].data.i % (guint32)sp [0].data.i;
2655 } else if (sp->type == VAL_I64) {
2656 if (sp [0].data.l == 0)
2657 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2658 sp [-1].data.l = (guint64)sp [-1].data.l % (guint64)sp [0].data.l;
2659 } else if (sp->type == VAL_DOUBLE) {
2660 /* unspecified behaviour according to the spec */
2662 if (sp [0].data.nati == 0)
2663 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2664 if (sp [-1].type == VAL_NATI)
2665 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.nati;
2667 sp [-1].data.nati = (mono_u)sp [-1].data.i % (mono_u)sp [0].data.nati;
2668 sp [-1].type = VAL_NATI;
2675 if (sp->type == VAL_I32) {
2676 if (sp [-1].type == VAL_NATI)
2677 sp [-1].data.nati &= sp [0].data.i;
2679 sp [-1].data.i &= sp [0].data.i;
2681 else if (sp->type == VAL_I64)
2682 sp [-1].data.l &= sp [0].data.l;
2684 if (sp [-1].type == VAL_NATI)
2685 sp [-1].data.nati = (mono_i)sp [-1].data.nati & (mono_i)sp [0].data.nati;
2687 sp [-1].data.nati = (mono_i)sp [-1].data.i & (mono_i)sp [0].data.nati;
2688 sp [-1].type = VAL_NATI;
2695 if (sp->type == VAL_I32) {
2696 if (sp [-1].type == VAL_NATI)
2697 sp [-1].data.nati |= sp [0].data.i;
2699 sp [-1].data.i |= sp [0].data.i;
2701 else if (sp->type == VAL_I64)
2702 sp [-1].data.l |= sp [0].data.l;
2704 if (sp [-1].type == VAL_NATI)
2705 sp [-1].data.nati = (mono_i)sp [-1].data.nati | (mono_i)sp [0].data.nati;
2707 sp [-1].data.nati = (mono_i)sp [-1].data.i | (mono_i)sp [0].data.nati;
2708 sp [-1].type = VAL_NATI;
2715 if (sp->type == VAL_I32) {
2716 if (sp [-1].type == VAL_NATI)
2717 sp [-1].data.nati ^= sp [0].data.i;
2719 sp [-1].data.i ^= sp [0].data.i;
2721 else if (sp->type == VAL_I64)
2722 sp [-1].data.l ^= sp [0].data.l;
2724 if (sp [-1].type == VAL_NATI)
2725 sp [-1].data.nati = (mono_i)sp [-1].data.nati ^ (mono_i)sp [0].data.nati;
2727 sp [-1].data.nati = (mono_i)sp [-1].data.i ^ (mono_i)sp [0].data.nati;
2728 sp [-1].type = VAL_NATI;
2735 if (sp [-1].type == VAL_I32)
2736 sp [-1].data.i <<= GET_NATI (sp [0]);
2737 else if (sp [-1].type == VAL_I64)
2738 sp [-1].data.l <<= GET_NATI (sp [0]);
2740 sp [-1].data.nati <<= GET_NATI (sp [0]);
2745 if (sp [-1].type == VAL_I32)
2746 sp [-1].data.i >>= GET_NATI (sp [0]);
2747 else if (sp [-1].type == VAL_I64)
2748 sp [-1].data.l >>= GET_NATI (sp [0]);
2750 sp [-1].data.nati = ((mono_i)sp [-1].data.nati) >> GET_NATI (sp [0]);
2755 if (sp [-1].type == VAL_I32)
2756 sp [-1].data.i = (guint)sp [-1].data.i >> GET_NATI (sp [0]);
2757 else if (sp [-1].type == VAL_I64)
2758 sp [-1].data.l = (guint64)sp [-1].data.l >> GET_NATI (sp [0]);
2760 sp [-1].data.nati = ((mono_u)sp[-1].data.nati) >> GET_NATI (sp [0]);
2765 if (sp->type == VAL_I32)
2766 sp->data.i = - sp->data.i;
2767 else if (sp->type == VAL_I64)
2768 sp->data.l = - sp->data.l;
2769 else if (sp->type == VAL_DOUBLE)
2770 sp->data.f = - sp->data.f;
2771 else if (sp->type == VAL_NATI)
2772 sp->data.nati = - (mono_i)sp->data.nati;
2778 if (sp->type == VAL_I32)
2779 sp->data.i = ~ sp->data.i;
2780 else if (sp->type == VAL_I64)
2781 sp->data.l = ~ sp->data.l;
2782 else if (sp->type == VAL_NATI)
2783 sp->data.nati = ~ (mono_i)sp->data.p;
2786 CASE (CEE_CONV_U1) {
2788 switch (sp [-1].type) {
2790 sp [-1].data.i = (guint8)sp [-1].data.f;
2793 sp [-1].data.i = (guint8)sp [-1].data.l;
2798 sp [-1].data.i = (guint8)sp [-1].data.i;
2801 sp [-1].data.i = (guint8)sp [-1].data.nati;
2804 sp [-1].type = VAL_I32;
2807 CASE (CEE_CONV_I1) {
2809 switch (sp [-1].type) {
2811 sp [-1].data.i = (gint8)sp [-1].data.f;
2814 sp [-1].data.i = (gint8)sp [-1].data.l;
2819 sp [-1].data.i = (gint8)sp [-1].data.i;
2822 sp [-1].data.i = (gint8)sp [-1].data.nati;
2825 sp [-1].type = VAL_I32;
2828 CASE (CEE_CONV_U2) {
2830 switch (sp [-1].type) {
2832 sp [-1].data.i = (guint16)sp [-1].data.f;
2835 sp [-1].data.i = (guint16)sp [-1].data.l;
2840 sp [-1].data.i = (guint16)sp [-1].data.i;
2843 sp [-1].data.i = (guint16)sp [-1].data.nati;
2846 sp [-1].type = VAL_I32;
2849 CASE (CEE_CONV_I2) {
2851 switch (sp [-1].type) {
2853 sp [-1].data.i = (gint16)sp [-1].data.f;
2856 sp [-1].data.i = (gint16)sp [-1].data.l;
2861 sp [-1].data.i = (gint16)sp [-1].data.i;
2864 sp [-1].data.i = (gint16)sp [-1].data.nati;
2867 sp [-1].type = VAL_I32;
2870 CASE (CEE_CONV_U4) /* Fall through */
2871 #if SIZEOF_VOID_P == 4
2872 CASE (CEE_CONV_I) /* Fall through */
2873 CASE (CEE_CONV_U) /* Fall through */
2875 CASE (CEE_CONV_I4) {
2877 switch (sp [-1].type) {
2879 sp [-1].data.i = (gint32)sp [-1].data.f;
2882 sp [-1].data.i = (gint32)sp [-1].data.l;
2889 sp [-1].data.i = (gint32)sp [-1].data.p;
2892 sp [-1].type = VAL_I32;
2895 #if SIZEOF_VOID_P == 8
2896 CASE (CEE_CONV_I) /* Fall through */
2900 switch (sp [-1].type) {
2902 sp [-1].data.l = (gint64)sp [-1].data.f;
2909 sp [-1].data.l = (gint64)sp [-1].data.i;
2912 sp [-1].data.l = (gint64)sp [-1].data.nati;
2915 sp [-1].type = ip[-1] == CEE_CONV_I ? VAL_NATI : VAL_I64;
2917 CASE (CEE_CONV_R4) {
2919 switch (sp [-1].type) {
2921 sp [-1].data.f = (float)sp [-1].data.f;
2924 sp [-1].data.f = (float)sp [-1].data.l;
2929 sp [-1].data.f = (float)sp [-1].data.i;
2932 sp [-1].data.f = (float)sp [-1].data.nati;
2935 sp [-1].type = VAL_DOUBLE;
2938 CASE (CEE_CONV_R8) {
2940 switch (sp [-1].type) {
2942 sp [-1].data.f = (double)sp [-1].data.f;
2945 sp [-1].data.f = (double)sp [-1].data.l;
2950 sp [-1].data.f = (double)sp [-1].data.i;
2953 sp [-1].data.f = (double)sp [-1].data.nati;
2956 sp [-1].type = VAL_DOUBLE;
2959 #if SIZEOF_VOID_P == 8
2960 CASE (CEE_CONV_U) /* Fall through */
2965 switch (sp [-1].type){
2967 sp [-1].data.l = (guint64)sp [-1].data.f;
2974 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
2977 sp [-1].data.l = (guint64) sp [-1].data.nati;
2980 sp [-1].type = ip[-1] == CEE_CONV_U ? VAL_NATI : VAL_I64;
2985 vtklass = mono_class_get (image, read32 (ip));
2988 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2997 token = read32 (ip);
3000 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3001 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3003 c = mono_class_get (image, token);
3005 addr = sp [-1].data.vt;
3006 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
3007 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
3015 str_index = mono_metadata_token_index (read32 (ip));
3018 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
3019 o = (MonoObject *)mono_string_new_wrapper(
3020 mono_method_get_wrapper_data (frame->method, str_index));
3023 o = (MonoObject*)mono_ldstr (domain, image, str_index);
3032 MonoClass *newobj_class;
3033 MonoMethodSignature *csig;
3034 stackval valuetype_this;
3035 stackval *endsp = sp;
3042 token = read32 (ip);
3045 if (!(child_frame.method = mono_get_method (image, token, NULL)))
3046 THROW_EX (mono_get_exception_missing_method (), ip -5);
3048 csig = child_frame.method->signature;
3049 newobj_class = child_frame.method->klass;
3050 /*if (profiling_classes) {
3051 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3053 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3057 if (newobj_class->parent == mono_defaults.array_class) {
3058 sp -= csig->param_count;
3059 o = ves_array_create (domain, newobj_class, csig, sp);
3060 goto array_constructed;
3064 * First arg is the object.
3066 if (newobj_class->valuetype) {
3068 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
3069 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
3070 zero = valuetype_this.data.vt;
3071 child_frame.obj = valuetype_this.data.vt;
3073 memset (&valuetype_this, 0, sizeof (stackval));
3074 zero = &valuetype_this;
3075 child_frame.obj = &valuetype_this;
3077 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
3079 if (newobj_class != mono_defaults.string_class) {
3080 o = mono_object_new (domain, newobj_class);
3081 child_frame.obj = o;
3083 child_frame.retval = &retval;
3087 if (csig->param_count) {
3088 sp -= csig->param_count;
3089 child_frame.stack_args = sp;
3091 child_frame.stack_args = NULL;
3094 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3096 child_frame.ip = NULL;
3097 child_frame.ex = NULL;
3098 child_frame.ex_handler = NULL;
3100 ves_exec_method_with_context (&child_frame, context);
3102 context->current_frame = frame;
3104 while (endsp > sp) {
3109 if (child_frame.ex) {
3111 * An exception occurred, need to run finally, fault and catch handlers..
3113 frame->ex = child_frame.ex;
3114 goto handle_finally;
3117 * a constructor returns void, but we need to return the object we created
3120 if (newobj_class->valuetype && !newobj_class->enumtype) {
3121 *sp = valuetype_this;
3122 } else if (newobj_class == mono_defaults.string_class) {
3131 CASE (CEE_CASTCLASS) /* Fall through */
3136 int do_isinst = *ip == CEE_ISINST;
3139 token = read32 (ip);
3140 c = mono_class_get (image, token);
3142 g_assert (sp [-1].type == VAL_OBJ);
3144 if ((o = sp [-1].data.p)) {
3145 if (!mono_object_isinst (o, c)) {
3147 sp [-1].data.p = NULL;
3149 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3155 CASE (CEE_CONV_R_UN)
3157 switch (sp [-1].type) {
3161 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3166 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3169 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
3172 sp [-1].type = VAL_DOUBLE;
3175 CASE (CEE_UNUSED1) ves_abort(); BREAK;
3182 token = read32 (ip);
3184 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3185 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3187 c = mono_class_get (image, token);
3191 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3193 if (!(mono_object_isinst (o, c) ||
3194 ((o->vtable->klass->rank == 0) &&
3195 (o->vtable->klass->element_class == c->element_class))))
3196 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3198 sp [-1].type = VAL_MP;
3199 sp [-1].data.p = (char *)o + sizeof (MonoObject);
3206 frame->ex_handler = NULL;
3208 sp->data.p = mono_get_exception_null_reference ();
3209 THROW_EX ((MonoException *)sp->data.p, ip);
3211 CASE (CEE_LDFLDA) /* Fall through */
3214 MonoClassField *field;
3216 int load_addr = *ip == CEE_LDFLDA;
3219 if (!sp [-1].data.p)
3220 THROW_EX (mono_get_exception_null_reference (), ip);
3223 token = read32 (ip);
3224 field = rtd->field_info[token].field;
3227 if (sp [-1].type == VAL_OBJ) {
3228 obj = sp [-1].data.p;
3229 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3230 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3231 addr = mono_load_remote_field (obj, klass, field, NULL);
3233 addr = (char*)obj + field->offset;
3236 obj = sp [-1].data.vt;
3237 addr = (char*)obj + field->offset - sizeof (MonoObject);
3241 sp [-1].type = VAL_MP;
3242 sp [-1].data.p = addr;
3244 vt_alloc (field->type, &sp [-1], FALSE);
3245 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3251 MonoClassField *field;
3252 guint32 token, offset;
3257 THROW_EX (mono_get_exception_null_reference (), ip);
3260 token = read32 (ip);
3261 field = rtd->field_info[token].field;
3264 if (sp [0].type == VAL_OBJ) {
3265 obj = sp [0].data.p;
3267 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3268 MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
3269 mono_store_remote_field (obj, klass, field, &sp [1].data);
3271 offset = field->offset;
3272 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3276 obj = sp [0].data.vt;
3277 offset = field->offset - sizeof (MonoObject);
3278 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3284 CASE (CEE_LDSFLD) /* Fall through */
3285 CASE (CEE_LDSFLDA) {
3287 MonoClassField *field;
3289 int load_addr = *ip == CEE_LDSFLDA;
3293 token = read32 (ip);
3294 field = rtd->field_info[token].field;
3297 vt = mono_class_vtable (domain, field->parent);
3298 if (!vt->initialized)
3299 mono_runtime_class_init (vt);
3300 if (!domain->thread_static_fields || !(addr = g_hash_table_lookup (domain->thread_static_fields, field)))
3301 addr = (char*)(vt->data) + field->offset;
3303 addr = mono_threads_get_static_data (GPOINTER_TO_UINT (addr));
3309 vt_alloc (field->type, sp, FALSE);
3310 stackval_from_data (field->type, sp, addr, FALSE);
3317 MonoClassField *field;
3322 token = read32 (ip);
3323 field = rtd->field_info[token].field;
3327 vt = mono_class_vtable (domain, field->parent);
3328 if (!vt->initialized)
3329 mono_runtime_class_init (vt);
3330 if (!domain->thread_static_fields || !(addr = g_hash_table_lookup (domain->thread_static_fields, field)))
3331 addr = (char*)(vt->data) + field->offset;
3333 addr = mono_threads_get_static_data (GPOINTER_TO_UINT (addr));
3335 stackval_to_data (field->type, sp, addr, FALSE);
3342 vtklass = mono_class_get (image, read32 (ip));
3347 * LAMESPEC: According to the spec, the stack should contain a
3348 * pointer to a value type. In reality, it can contain anything.
3350 if (sp [1].type == VAL_VALUET)
3351 memcpy (sp [0].data.p, sp [1].data.vt, mono_class_value_size (vtklass, NULL));
3353 memcpy (sp [0].data.p, &sp [1].data, mono_class_value_size (vtklass, NULL));
3356 #if SIZEOF_VOID_P == 8
3357 CASE (CEE_CONV_OVF_I_UN)
3359 CASE (CEE_CONV_OVF_I8_UN) {
3360 switch (sp [-1].type) {
3362 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
3363 THROW_EX (mono_get_exception_overflow (), ip);
3364 sp [-1].data.l = (guint64)sp [-1].data.f;
3371 /* Can't overflow */
3372 sp [-1].data.l = (guint64)sp [-1].data.i;
3375 sp [-1].data.l = (guint64)sp [-1].data.nati;
3378 sp [-1].type = VAL_I64;
3382 #if SIZEOF_VOID_P == 8
3383 CASE (CEE_CONV_OVF_U_UN)
3385 CASE (CEE_CONV_OVF_U8_UN) {
3386 switch (sp [-1].type) {
3388 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
3389 THROW_EX (mono_get_exception_overflow (), ip);
3390 sp [-1].data.l = (guint64)sp [-1].data.f;
3398 /* Can't overflow */
3399 sp [-1].data.l = (guint64)sp [-1].data.i;
3402 /* Can't overflow */
3403 sp [-1].data.l = (guint64)sp [-1].data.nati;
3406 sp [-1].type = VAL_I64;
3410 #if SIZEOF_VOID_P == 4
3411 CASE (CEE_CONV_OVF_I_UN)
3412 CASE (CEE_CONV_OVF_U_UN)
3414 CASE (CEE_CONV_OVF_I1_UN)
3415 CASE (CEE_CONV_OVF_I2_UN)
3416 CASE (CEE_CONV_OVF_I4_UN)
3417 CASE (CEE_CONV_OVF_U1_UN)
3418 CASE (CEE_CONV_OVF_U2_UN)
3419 CASE (CEE_CONV_OVF_U4_UN) {
3421 switch (sp [-1].type) {
3423 if (sp [-1].data.f <= -1.0)
3424 THROW_EX (mono_get_exception_overflow (), ip);
3425 value = (guint64)sp [-1].data.f;
3428 value = (guint64)sp [-1].data.l;
3433 value = (guint64)sp [-1].data.i;
3436 value = (guint64)sp [-1].data.nati;
3440 case CEE_CONV_OVF_I1_UN:
3442 THROW_EX (mono_get_exception_overflow (), ip);
3443 sp [-1].data.i = value;
3444 sp [-1].type = VAL_I32;
3446 case CEE_CONV_OVF_I2_UN:
3448 THROW_EX (mono_get_exception_overflow (), ip);
3449 sp [-1].data.i = value;
3450 sp [-1].type = VAL_I32;
3452 #if SIZEOF_VOID_P == 4
3453 case CEE_CONV_OVF_I_UN: /* Fall through */
3455 case CEE_CONV_OVF_I4_UN:
3456 if (value > MYGUINT32_MAX)
3457 THROW_EX (mono_get_exception_overflow (), ip);
3458 sp [-1].data.i = value;
3459 sp [-1].type = VAL_I32;
3461 case CEE_CONV_OVF_U1_UN:
3463 THROW_EX (mono_get_exception_overflow (), ip);
3464 sp [-1].data.i = value;
3465 sp [-1].type = VAL_I32;
3467 case CEE_CONV_OVF_U2_UN:
3469 THROW_EX (mono_get_exception_overflow (), ip);
3470 sp [-1].data.i = value;
3471 sp [-1].type = VAL_I32;
3473 #if SIZEOF_VOID_P == 4
3474 case CEE_CONV_OVF_U_UN: /* Fall through */
3476 case CEE_CONV_OVF_U4_UN:
3477 if (value > 4294967295U)
3478 THROW_EX (mono_get_exception_overflow (), ip);
3479 sp [-1].data.i = value;
3480 sp [-1].type = VAL_I32;
3483 g_assert_not_reached ();
3493 token = read32 (ip);
3495 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3496 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3498 class = mono_class_get (image, token);
3499 g_assert (class != NULL);
3501 sp [-1].type = VAL_OBJ;
3502 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3503 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3505 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3506 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3508 /* need to vt_free (sp); */
3520 token = read32 (ip);
3522 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3523 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3525 class = mono_class_get (image, token);
3527 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3530 sp [-1].type = VAL_OBJ;
3532 /*if (profiling_classes) {
3533 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3535 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3545 g_assert (sp [-1].type == VAL_OBJ);
3549 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3551 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3553 sp [-1].type = VAL_I32;
3554 sp [-1].data.i = mono_array_length (o);
3558 CASE (CEE_LDELEMA) {
3560 guint32 esize, token;
3564 token = read32 (ip);
3568 g_assert (sp [0].type == VAL_OBJ);
3571 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3573 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3574 if (aindex >= mono_array_length (o))
3575 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3577 /* check the array element corresponds to token */
3578 esize = mono_array_element_size (o->obj.vtable->klass);
3581 sp->data.p = mono_array_addr_with_size (o, esize, aindex);
3586 CASE (CEE_LDELEM_I1) /* fall through */
3587 CASE (CEE_LDELEM_U1) /* fall through */
3588 CASE (CEE_LDELEM_I2) /* fall through */
3589 CASE (CEE_LDELEM_U2) /* fall through */
3590 CASE (CEE_LDELEM_I4) /* fall through */
3591 CASE (CEE_LDELEM_U4) /* fall through */
3592 CASE (CEE_LDELEM_I8) /* fall through */
3593 CASE (CEE_LDELEM_I) /* fall through */
3594 CASE (CEE_LDELEM_R4) /* fall through */
3595 CASE (CEE_LDELEM_R8) /* fall through */
3596 CASE (CEE_LDELEM_REF) {
3602 g_assert (sp [0].type == VAL_OBJ);
3605 THROW_EX (mono_get_exception_null_reference (), ip);
3607 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3609 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3610 if (aindex >= mono_array_length (o))
3611 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3614 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3618 sp [0].data.i = mono_array_get (o, gint8, aindex);
3619 sp [0].type = VAL_I32;
3622 sp [0].data.i = mono_array_get (o, guint8, aindex);
3623 sp [0].type = VAL_I32;
3626 sp [0].data.i = mono_array_get (o, gint16, aindex);
3627 sp [0].type = VAL_I32;
3630 sp [0].data.i = mono_array_get (o, guint16, aindex);
3631 sp [0].type = VAL_I32;
3634 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3635 sp [0].type = VAL_NATI;
3638 sp [0].data.i = mono_array_get (o, gint32, aindex);
3639 sp [0].type = VAL_I32;
3642 sp [0].data.i = mono_array_get (o, guint32, aindex);
3643 sp [0].type = VAL_I32;
3646 sp [0].data.l = mono_array_get (o, guint64, aindex);
3647 sp [0].type = VAL_I64;
3650 sp [0].data.f = mono_array_get (o, float, aindex);
3651 sp [0].type = VAL_DOUBLE;
3654 sp [0].data.f = mono_array_get (o, double, aindex);
3655 sp [0].type = VAL_DOUBLE;
3657 case CEE_LDELEM_REF:
3658 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3659 sp [0].type = VAL_OBJ;
3669 CASE (CEE_STELEM_I) /* fall through */
3670 CASE (CEE_STELEM_I1) /* fall through */
3671 CASE (CEE_STELEM_I2) /* fall through */
3672 CASE (CEE_STELEM_I4) /* fall through */
3673 CASE (CEE_STELEM_I8) /* fall through */
3674 CASE (CEE_STELEM_R4) /* fall through */
3675 CASE (CEE_STELEM_R8) /* fall through */
3676 CASE (CEE_STELEM_REF) {
3683 g_assert (sp [0].type == VAL_OBJ);
3686 THROW_EX (mono_get_exception_null_reference (), ip);
3688 ac = o->obj.vtable->klass;
3689 g_assert (MONO_CLASS_IS_ARRAY (ac));
3691 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3692 if (aindex >= mono_array_length (o))
3693 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3696 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3700 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3703 mono_array_set (o, gint8, aindex, sp [2].data.i);
3706 mono_array_set (o, gint16, aindex, sp [2].data.i);
3709 mono_array_set (o, gint32, aindex, sp [2].data.i);
3712 mono_array_set (o, gint64, aindex, sp [2].data.l);
3715 mono_array_set (o, float, aindex, sp [2].data.f);
3718 mono_array_set (o, double, aindex, sp [2].data.f);
3720 case CEE_STELEM_REF:
3721 g_assert (sp [2].type == VAL_OBJ);
3722 if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
3723 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3724 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3735 CASE (CEE_UNBOX_ANY)
3748 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3750 #if SIZEOF_VOID_P == 4
3751 CASE (CEE_CONV_OVF_I)
3752 CASE (CEE_CONV_OVF_U)
3754 CASE (CEE_CONV_OVF_I1)
3755 CASE (CEE_CONV_OVF_I2)
3756 CASE (CEE_CONV_OVF_I4)
3757 CASE (CEE_CONV_OVF_U1)
3758 CASE (CEE_CONV_OVF_U2)
3759 CASE (CEE_CONV_OVF_U4) {
3761 switch (sp [-1].type) {
3763 value = (gint64)sp [-1].data.f;
3766 value = (gint64)sp [-1].data.l;
3771 value = (gint64)sp [-1].data.i;
3774 value = (gint64)sp [-1].data.nati;
3778 case CEE_CONV_OVF_I1:
3779 if (value < -128 || value > 127)
3780 THROW_EX (mono_get_exception_overflow (), ip);
3781 sp [-1].data.i = value;
3782 sp [-1].type = VAL_I32;
3784 case CEE_CONV_OVF_I2:
3785 if (value < -32768 || value > 32767)
3786 THROW_EX (mono_get_exception_overflow (), ip);
3787 sp [-1].data.i = value;
3788 sp [-1].type = VAL_I32;
3790 #if SIZEOF_VOID_P == 4
3791 case CEE_CONV_OVF_I: /* Fall through */
3793 case CEE_CONV_OVF_I4:
3794 if (value < MYGINT32_MIN || value > MYGINT32_MAX)
3795 THROW_EX (mono_get_exception_overflow (), ip);
3796 sp [-1].data.i = value;
3797 sp [-1].type = VAL_I32;
3799 case CEE_CONV_OVF_U1:
3800 if (value < 0 || value > 255)
3801 THROW_EX (mono_get_exception_overflow (), ip);
3802 sp [-1].data.i = value;
3803 sp [-1].type = VAL_I32;
3805 case CEE_CONV_OVF_U2:
3806 if (value < 0 || value > 65535)
3807 THROW_EX (mono_get_exception_overflow (), ip);
3808 sp [-1].data.i = value;
3809 sp [-1].type = VAL_I32;
3811 #if SIZEOF_VOID_P == 4
3812 case CEE_CONV_OVF_U: /* Fall through */
3814 case CEE_CONV_OVF_U4:
3815 if (value < 0 || value > MYGUINT32_MAX)
3816 THROW_EX (mono_get_exception_overflow (), ip);
3817 sp [-1].data.i = value;
3818 sp [-1].type = VAL_I32;
3821 g_assert_not_reached ();
3827 #if SIZEOF_VOID_P == 8
3828 CASE (CEE_CONV_OVF_I)
3830 CASE (CEE_CONV_OVF_I8)
3831 /* FIXME: handle other cases */
3832 if (sp [-1].type == VAL_I32) {
3833 sp [-1].data.l = (guint64)sp [-1].data.i;
3834 sp [-1].type = VAL_I64;
3835 } else if(sp [-1].type == VAL_I64) {
3836 /* defined as NOP */
3843 #if SIZEOF_VOID_P == 8
3844 CASE (CEE_CONV_OVF_U)
3846 CASE (CEE_CONV_OVF_U8)
3847 /* FIXME: handle other cases */
3848 if (sp [-1].type == VAL_I32) {
3849 sp [-1].data.l = (guint64) sp [-1].data.i;
3850 sp [-1].type = VAL_I64;
3851 } else if(sp [-1].type == VAL_I64) {
3852 /* defined as NOP */
3864 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3865 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3867 if (!finite(sp [-1].data.f))
3868 THROW_EX (mono_get_exception_arithmetic (), ip);
3871 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3872 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3873 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3882 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3883 CASE (CEE_LDTOKEN) {
3885 MonoClass *handle_class;
3887 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3889 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3890 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3896 /* FIXME: check overflow */
3897 if (sp->type == VAL_I32) {
3898 if (sp [-1].type == VAL_I32) {
3899 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3900 THROW_EX (mono_get_exception_overflow (), ip);
3901 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)sp [0].data.i;
3903 if (CHECK_ADD_OVERFLOW_NAT (sp [-1].data.nati, (mono_i)sp [0].data.i))
3904 THROW_EX (mono_get_exception_overflow (), ip);
3905 sp [-1].data.nati = sp [-1].data.nati + (mono_i)sp [0].data.i;
3907 } else if (sp->type == VAL_I64) {
3908 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3909 THROW_EX (mono_get_exception_overflow (), ip);
3910 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3911 } else if (sp->type == VAL_DOUBLE)
3912 sp [-1].data.f += sp [0].data.f;
3914 char *p = sp [-1].data.p;
3915 p += GET_NATI (sp [0]);
3920 CASE (CEE_ADD_OVF_UN)
3922 /* FIXME: check overflow, make unsigned */
3923 if (sp->type == VAL_I32) {
3924 if (sp [-1].type == VAL_I32) {
3925 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
3926 THROW_EX (mono_get_exception_overflow (), ip);
3927 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)sp [0].data.i;
3929 if (CHECK_ADD_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
3930 THROW_EX (mono_get_exception_overflow (), ip);
3931 sp [-1].data.nati = (mono_u)sp [-1].data.nati + (mono_u)sp [0].data.i;
3933 } else if (sp->type == VAL_I64) {
3934 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3935 THROW_EX (mono_get_exception_overflow (), ip);
3936 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3937 } else if (sp->type == VAL_DOUBLE)
3938 sp [-1].data.f += sp [0].data.f;
3940 char *p = sp [-1].data.p;
3941 p += GET_NATI (sp [0]);
3948 /* FIXME: check overflow */
3949 if (sp->type == VAL_I32) {
3950 if (sp [-1].type == VAL_NATI) {
3951 if (CHECK_MUL_OVERFLOW_NAT (sp [-1].data.nati, sp [0].data.i))
3952 THROW_EX (mono_get_exception_overflow (), ip);
3953 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
3954 sp [-1].type = VAL_NATI;
3956 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3957 THROW_EX (mono_get_exception_overflow (), ip);
3958 sp [-1].data.i *= sp [0].data.i;
3961 else if (sp->type == VAL_I64) {
3962 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3963 THROW_EX (mono_get_exception_overflow (), ip);
3964 sp [-1].data.l *= sp [0].data.l;
3966 else if (sp->type == VAL_DOUBLE)
3967 sp [-1].data.f *= sp [0].data.f;
3972 CASE (CEE_MUL_OVF_UN)
3974 /* FIXME: check overflow, make unsigned */
3975 if (sp->type == VAL_I32) {
3976 if (sp [-1].type == VAL_NATI) {
3977 if (CHECK_MUL_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
3978 THROW_EX (mono_get_exception_overflow (), ip);
3979 sp [-1].data.nati = (mono_u)sp [-1].data.nati * (mono_u)sp [0].data.i;
3980 sp [-1].type = VAL_NATI;
3982 if (CHECK_MUL_OVERFLOW_UN ((guint32)sp [-1].data.i, (guint32)sp [0].data.i))
3983 THROW_EX (mono_get_exception_overflow (), ip);
3984 sp [-1].data.i *= sp [0].data.i;
3987 else if (sp->type == VAL_I64) {
3988 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3989 THROW_EX (mono_get_exception_overflow (), ip);
3990 sp [-1].data.l *= sp [0].data.l;
3992 else if (sp->type == VAL_DOUBLE)
3993 sp [-1].data.f *= sp [0].data.f;
4000 /* FIXME: handle undeflow/unsigned */
4001 /* should probably consider the pointers as unsigned */
4002 if (sp->type == VAL_I32) {
4003 if (sp [-1].type == VAL_I32) {
4004 if (CHECK_SUB_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4005 THROW_EX (mono_get_exception_overflow (), ip);
4006 sp [-1].data.i -= sp [0].data.i;
4008 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4009 sp [-1].type = VAL_NATI;
4012 else if (sp->type == VAL_I64) {
4013 if (CHECK_SUB_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4014 THROW_EX (mono_get_exception_overflow (), ip);
4015 sp [-1].data.l -= sp [0].data.l;
4017 else if (sp->type == VAL_DOUBLE)
4018 sp [-1].data.f -= sp [0].data.f;
4020 if (sp [-1].type == VAL_I32) {
4021 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4022 sp [-1].type = sp [0].type;
4024 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4028 CASE (CEE_SUB_OVF_UN)
4030 /* FIXME: handle undeflow/unsigned */
4031 /* should probably consider the pointers as unsigned */
4032 if (sp->type == VAL_I32) {
4033 if (sp [-1].type == VAL_I32) {
4034 if (CHECK_SUB_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
4035 THROW_EX (mono_get_exception_overflow (), ip);
4036 sp [-1].data.i -= sp [0].data.i;
4038 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4039 sp [-1].type = VAL_NATI;
4042 else if (sp->type == VAL_I64) {
4043 if (CHECK_SUB_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4044 THROW_EX (mono_get_exception_overflow (), ip);
4045 sp [-1].data.l -= sp [0].data.l;
4047 else if (sp->type == VAL_DOUBLE)
4048 sp [-1].data.f -= sp [0].data.f;
4050 if (sp [-1].type == VAL_I32) {
4051 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4052 sp [-1].type = sp [0].type;
4054 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4058 CASE (CEE_ENDFINALLY)
4060 ip = finally_ips->data;
4061 finally_ips = g_slist_remove (finally_ips, ip);
4068 CASE (CEE_LEAVE) /* Fall through */
4070 while (sp > frame->stack) {
4075 if (*ip == CEE_LEAVE_S) {
4077 ip += (signed char) *ip;
4081 ip += (gint32) read32 (ip);
4085 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - header->code)) {
4086 frame->ex_handler = NULL;
4089 goto handle_finally;
4094 case CEE_MONO_FUNC1: {
4095 MonoMarshalConv conv;
4104 sp->type = VAL_NATI;
4107 case MONO_MARSHAL_CONV_STR_LPWSTR:
4108 sp->data.p = mono_string_to_utf16 (sp->data.p);
4110 case MONO_MARSHAL_CONV_LPSTR_STR:
4111 sp->data.p = mono_string_new_wrapper (sp->data.p);
4113 case MONO_MARSHAL_CONV_STR_LPTSTR:
4114 case MONO_MARSHAL_CONV_STR_LPSTR:
4115 sp->data.p = mono_string_to_utf8 (sp->data.p);
4117 case MONO_MARSHAL_CONV_STR_BSTR:
4118 sp->data.p = mono_string_to_bstr (sp->data.p);
4120 case MONO_MARSHAL_CONV_STR_TBSTR:
4121 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4122 sp->data.p = mono_string_to_ansibstr (sp->data.p);
4124 case MONO_MARSHAL_CONV_SB_LPSTR:
4125 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
4127 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4128 sp->data.p = mono_array_to_savearray (sp->data.p);
4130 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4131 sp->data.p = mono_array_to_lparray (sp->data.p);
4133 case MONO_MARSHAL_CONV_DEL_FTN:
4134 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
4136 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4137 sp->data.p = mono_marshal_string_array (sp->data.p);
4139 case MONO_MARSHAL_CONV_LPWSTR_STR:
4140 sp->data.p = mono_string_from_utf16 (sp->data.p);
4143 fprintf(stderr, "MONO_FUNC1 %d", conv);
4144 g_assert_not_reached ();
4149 case CEE_MONO_PROC2: {
4150 MonoMarshalConv conv;
4158 case MONO_MARSHAL_CONV_LPSTR_SB:
4159 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
4161 case MONO_MARSHAL_FREE_ARRAY:
4162 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
4165 g_assert_not_reached ();
4169 case CEE_MONO_PROC3: {
4170 MonoMarshalConv conv;
4178 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4179 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4181 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4182 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4185 g_assert_not_reached ();
4189 case CEE_MONO_VTADDR: {
4192 sp [-1].type = VAL_MP;
4196 case CEE_MONO_LDPTR: {
4200 token = read32 (ip);
4203 sp->type = VAL_NATI;
4204 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
4208 case CEE_MONO_FREE: {
4212 g_free (sp->data.p);
4215 case CEE_MONO_OBJADDR: {
4222 case CEE_MONO_NEWOBJ: {
4227 token = read32 (ip);
4230 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4231 sp->data.p = mono_object_new (domain, class);
4235 case CEE_MONO_RETOBJ: {
4240 token = read32 (ip);
4245 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4247 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
4249 if (sp > frame->stack)
4250 g_warning ("more values on stack: %d", sp-frame->stack);
4253 case CEE_MONO_LDNATIVEOBJ: {
4258 token = read32 (ip);
4261 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4262 g_assert(class->valuetype);
4264 sp [-1].type = VAL_MP;
4269 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
4300 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
4302 * Note: Exceptions thrown when executing a prefixed opcode need
4303 * to take into account the number of prefix bytes (usually the
4304 * throw point is just (ip - n_prefix_bytes).
4309 case CEE_ARGLIST: ves_abort(); break;
4315 if (sp->type == VAL_I32)
4316 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
4317 else if (sp->type == VAL_I64)
4318 result = sp [0].data.l == sp [1].data.l;
4319 else if (sp->type == VAL_DOUBLE) {
4320 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4323 result = sp [0].data.f == sp [1].data.f;
4325 result = sp [0].data.nati == GET_NATI (sp [1]);
4327 sp->data.i = result;
4337 if (sp->type == VAL_I32)
4338 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
4339 else if (sp->type == VAL_I64)
4340 result = sp [0].data.l > sp [1].data.l;
4341 else if (sp->type == VAL_DOUBLE) {
4342 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4345 result = sp [0].data.f > sp [1].data.f;
4347 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
4349 sp->data.i = result;
4359 if (sp->type == VAL_I32)
4360 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
4361 else if (sp->type == VAL_I64)
4362 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
4363 else if (sp->type == VAL_DOUBLE)
4364 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4365 sp[0].data.f > sp[1].data.f;
4367 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
4369 sp->data.i = result;
4379 if (sp->type == VAL_I32)
4380 result = (mono_i)sp [0].data.i < (mono_i)GET_NATI (sp [1]);
4381 else if (sp->type == VAL_I64)
4382 result = sp [0].data.l < sp [1].data.l;
4383 else if (sp->type == VAL_DOUBLE) {
4384 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4387 result = sp [0].data.f < sp [1].data.f;
4389 result = (mono_i)sp [0].data.nati < (mono_i)GET_NATI (sp [1]);
4391 sp->data.i = result;
4401 if (sp->type == VAL_I32)
4402 result = (mono_u)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
4403 else if (sp->type == VAL_I64)
4404 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
4405 else if (sp->type == VAL_DOUBLE)
4406 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4407 sp[0].data.f < sp[1].data.f;
4409 result = (mono_u)sp [0].data.nati < (mono_u)GET_NATI (sp [1]);
4411 sp->data.i = result;
4417 case CEE_LDVIRTFTN: {
4418 int virtual = *ip == CEE_LDVIRTFTN;
4422 token = read32 (ip);
4425 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
4426 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
4428 m = mono_get_method (image, token, NULL);
4431 THROW_EX (mono_get_exception_missing_method (), ip - 5);
4435 THROW_EX (mono_get_exception_null_reference (), ip - 5);
4437 m = get_virtual_method (domain, m, sp);
4441 * This prevents infinite cycles since the wrapper contains
4444 if (frame->method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
4445 if (m && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4446 m = mono_marshal_get_synchronized_wrapper (m);
4448 sp->type = VAL_NATI;
4449 sp->data.p = mono_create_method_pointer (m);
4453 case CEE_UNUSED56: ves_abort(); break;
4457 arg_pos = read16 (ip);
4459 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
4460 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4469 sp->data.vt = ARG_POS (anum);
4477 arg_pos = read16 (ip);
4480 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4487 loc_pos = read16 (ip);
4489 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4490 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4499 loc_pos = read16 (ip);
4501 t = LOCAL_TYPE (header, loc_pos);
4502 sp->data.vt = LOCAL_POS (loc_pos);
4512 loc_pos = read16 (ip);
4515 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4521 if (sp != frame->stack)
4522 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4524 sp->data.p = alloca (sp->data.i);
4528 case CEE_UNUSED57: ves_abort(); break;
4529 case CEE_ENDFILTER: ves_abort(); break;
4530 case CEE_UNALIGNED_:
4532 unaligned_address = 1;
4536 volatile_address = 1;
4547 token = read32 (ip);
4550 class = mono_class_get (image, token);
4553 g_assert (sp->type == VAL_TP || sp->type == VAL_MP);
4554 memset (sp->data.vt, 0, mono_class_value_size (class, NULL));
4557 case CEE_CONSTRAINED_: {
4559 /* FIXME: implement */
4561 token = read32 (ip);
4567 if (!sp [0].data.p || !sp [1].data.p)
4568 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4570 /* FIXME: value and size may be int64... */
4571 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4576 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4578 /* FIXME: value and size may be int64... */
4579 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4582 /* FIXME: implement */
4587 * need to clarify what this should actually do:
4588 * start the search from the last found handler in
4589 * this method or continue in the caller or what.
4590 * Also, do we need to run finally/fault handlers after a retrow?
4591 * Well, this implementation will follow the usual search
4592 * for an handler, considering the current ip as throw spot.
4593 * We need to NULL frame->ex_handler for the later code to
4594 * actually run the new found handler.
4596 frame->ex_handler = NULL;
4597 THROW_EX (frame->ex, ip - 1);
4599 case CEE_UNUSED: ves_abort(); break;
4604 token = read32 (ip);
4606 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4607 MonoType *type = mono_type_create_from_typespec (image, token);
4608 sp->data.i = mono_type_size (type, &align);
4609 mono_metadata_free_type (type);
4611 MonoClass *szclass = mono_class_get (image, token);
4612 mono_class_init (szclass);
4613 if (!szclass->valuetype)
4614 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4615 sp->data.i = mono_class_value_size (szclass, &align);
4621 case CEE_REFANYTYPE: ves_abort(); break;
4623 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4630 g_assert_not_reached ();
4632 * Exception handling code.
4633 * The exception object is stored in frame->ex.
4640 MonoInvocation *inv;
4641 MonoMethodHeader *hd;
4642 MonoExceptionClause *clause;
4648 g_print ("* Handling exception '%s' at IL_%04x\n", frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, frame->ip - header->code);
4650 if (die_on_exception)
4653 if (frame->ex == quit_exception)
4654 goto handle_finally;
4656 for (inv = frame; inv; inv = inv->parent) {
4657 if (inv->method == NULL)
4659 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4661 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4663 hd = ((MonoMethodNormal*)inv->method)->header;
4664 ip_offset = inv->ip - hd->code;
4665 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4666 for (i = 0; i < hd->num_clauses; ++i) {
4667 clause = &hd->clauses [i];
4668 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4669 if (!clause->flags) {
4670 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4672 * OK, we found an handler, now we need to execute the finally
4673 * and fault blocks before branching to the handler code.
4675 inv->ex_handler = clause;
4678 g_print ("* Found handler at '%s'\n", inv->method->name);
4680 goto handle_finally;
4683 /* FIXME: handle filter clauses */
4690 * If we get here, no handler was found: print a stack trace.
4692 for (inv = frame; inv; inv = inv->parent) {
4693 if (inv->invoke_trap)
4694 goto handle_finally;
4697 ex_obj = (MonoObject*)frame->ex;
4698 mono_unhandled_exception (ex_obj);
4705 MonoExceptionClause *clause;
4706 GSList *old_list = finally_ips;
4710 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - header->code);
4712 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4713 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4716 ip_offset = frame->ip - header->code;
4718 if (endfinally_ip != NULL)
4719 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4720 for (i = 0; i < header->num_clauses; ++i)
4721 if (frame->ex_handler == &header->clauses [i])
4725 clause = &header->clauses [i];
4726 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code)))) {
4727 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4728 ip = header->code + clause->handler_offset;
4729 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4732 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4738 endfinally_ip = NULL;
4740 if (old_list != finally_ips && finally_ips) {
4741 ip = finally_ips->data;
4742 finally_ips = g_slist_remove (finally_ips, ip);
4743 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4748 * If an exception is set, we need to execute the fault handler, too,
4749 * otherwise, we continue normally.
4759 MonoExceptionClause *clause;
4763 g_print ("* Handle fault\n");
4765 ip_offset = frame->ip - header->code;
4766 for (i = 0; i < header->num_clauses; ++i) {
4767 clause = &header->clauses [i];
4768 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4769 ip = header->code + clause->handler_offset;
4772 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4778 * If the handler for the exception was found in this method, we jump
4779 * to it right away, otherwise we return and let the caller run
4780 * the finally, fault and catch blocks.
4781 * This same code should be present in the endfault opcode, but it
4782 * is corrently not assigned in the ECMA specs: LAMESPEC.
4784 if (frame->ex_handler) {
4787 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4789 ip = header->code + frame->ex_handler->handler_offset;
4792 sp->data.p = frame->ex;
4803 ves_exec_method (MonoInvocation *frame)
4805 ThreadContext *context = TlsGetValue (thread_context_id);
4806 ThreadContext context_struct;
4807 if (context == NULL) {
4808 context = &context_struct;
4809 context_struct.base_frame = frame;
4810 context_struct.current_frame = NULL;
4811 context_struct.current_env = NULL;
4812 context_struct.search_for_handler = 0;
4813 TlsSetValue (thread_context_id, context);
4816 frame->parent = context->current_frame;
4817 ves_exec_method_with_context(frame, context);
4819 if (context->current_env) {
4820 context->env_frame->ex = frame->ex;
4821 longjmp (*context->current_env, 1);
4824 mono_unhandled_exception ((MonoObject*)frame->ex);
4826 if (context->base_frame == frame)
4827 TlsSetValue (thread_context_id, NULL);
4829 context->current_frame = frame->parent;
4833 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4835 MonoImage *image = assembly->image;
4836 MonoCLIImageInfo *iinfo;
4838 MonoObject *exc = NULL;
4841 iinfo = image->image_info;
4842 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4844 g_error ("No entry point method found in %s", image->name);
4846 rval = mono_runtime_run_main (method, argc, argv, &exc);
4848 mono_unhandled_exception (exc);
4857 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4858 "Usage is: mint [options] executable args...\n\n", VERSION);
4860 "Runtime Debugging:\n"
4865 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4868 " --traceclassinit\n"
4871 " --debug method_name\n"
4877 " --config filename load the specified config file instead of the default\n"
4878 " --workers n maximum number of worker threads\n"
4885 test_load_class (MonoImage* image)
4887 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4891 for (i = 1; i <= t->rows; ++i) {
4892 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4893 mono_class_init (klass);
4898 static MonoException * segv_exception = NULL;
4901 segv_handler (int signum)
4903 signal (signum, segv_handler);
4904 mono_raise_exception (segv_exception);
4909 quit_handler (int signum)
4911 signal (signum, quit_handler);
4912 mono_raise_exception (quit_exception);
4916 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4917 MonoReflectionMethod **method,
4918 gint32 *iloffset, gint32 *native_offset,
4919 MonoString **file, gint32 *line, gint32 *column)
4932 *file = mono_string_new (mono_domain_get (), "unknown");
4938 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4946 int enable_debugging;
4952 static void main_thread_handler (gpointer user_data)
4954 MainThreadArgs *main_args=(MainThreadArgs *)user_data;
4955 MonoAssembly *assembly;
4958 if (main_args->enable_debugging)
4959 mono_debug_init (main_args->domain, MONO_DEBUG_FORMAT_MONO);
4961 assembly = mono_domain_assembly_open (main_args->domain,
4965 fprintf (stderr, "Can not open image %s\n", main_args->file);
4969 if (main_args->enable_debugging)
4970 mono_debug_init_2 (assembly);
4973 test_load_class (assembly->image);
4975 error = mono_verify_corlib ();
4977 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
4980 segv_exception = mono_get_exception_null_reference ();
4981 segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
4982 signal (SIGSEGV, segv_handler);
4983 /* perhaps we should use a different class for this exception... */
4984 quit_exception = mono_get_exception_null_reference ();
4985 quit_exception->message = mono_string_new (main_args->domain, "Quit");
4986 signal (SIGINT, quit_handler);
4988 ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
4993 mono_runtime_install_handlers (void)
4995 /* FIXME: anything to do here? */
4999 quit_function (MonoDomain *domain, gpointer user_data)
5001 mono_profiler_shutdown ();
5003 mono_runtime_cleanup (domain);
5004 mono_domain_unload (domain, TRUE);
5009 main (int argc, char *argv [])
5012 int retval = 0, i, ocount = 0;
5013 char *file, *config_file = NULL;
5014 int enable_debugging = FALSE;
5015 MainThreadArgs main_args;
5020 for (i = 1; i < argc && argv [i][0] == '-'; i++){
5021 if (strcmp (argv [i], "--trace") == 0)
5023 if (strcmp (argv [i], "--noptr") == 0)
5024 global_no_pointers = 1;
5025 if (strcmp (argv [i], "--traceops") == 0)
5027 if (strcmp (argv [i], "--dieonex") == 0) {
5028 die_on_exception = 1;
5029 enable_debugging = 1;
5031 if (strcmp (argv [i], "--print-vtable") == 0)
5032 mono_print_vtable = TRUE;
5033 if (strcmp (argv [i], "--profile") == 0)
5034 mono_profiler_load (NULL);
5035 if (strcmp (argv [i], "--opcode-count") == 0)
5037 if (strcmp (argv [i], "--config") == 0)
5038 config_file = argv [++i];
5039 if (strcmp (argv [i], "--workers") == 0) {
5040 mono_max_worker_threads = atoi (argv [++i]);
5041 if (mono_max_worker_threads < 1)
5042 mono_max_worker_threads = 1;
5044 if (strcmp (argv [i], "--help") == 0)
5047 if (strcmp (argv [i], "--debug") == 0) {
5048 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
5050 g_error ("Invalid method name '%s'", argv [i]);
5051 db_methods = g_list_append (db_methods, desc);
5061 g_set_prgname (file);
5062 mono_set_rootdir ();
5064 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
5065 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
5067 g_thread_init (NULL);
5069 thread_context_id = TlsAlloc ();
5070 TlsSetValue (thread_context_id, NULL);
5071 InitializeCriticalSection(&calc_section);
5073 mono_install_compile_method (mono_create_method_pointer);
5074 mono_install_runtime_invoke (interp_mono_runtime_invoke);
5075 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
5077 mono_install_handler (interp_ex_handler);
5078 mono_install_stack_walk (interp_walk_stack);
5079 mono_runtime_install_cleanup (quit_function);
5081 domain = mono_init (file);
5082 #ifdef __hpux /* generates very big stack frames */
5083 mono_threads_set_default_stacksize(32*1024*1024);
5085 mono_config_parse (config_file);
5087 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
5088 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
5089 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
5091 mono_runtime_init (domain, NULL, NULL);
5093 main_args.domain=domain;
5094 main_args.file=file;
5095 main_args.argc=argc-i;
5096 main_args.argv=argv+i;
5097 main_args.enable_debugging=enable_debugging;
5099 mono_runtime_exec_managed_code (domain, main_thread_handler,
5102 quit_function (domain, NULL);
5104 /* Get the return value from System.Environment.ExitCode */
5105 retval=mono_environment_exitcode_get ();
5109 fprintf (stderr, "opcode count: %ld\n", opcode_count);
5110 fprintf (stderr, "fcall count: %ld\n", fcall_count);