2 * PLEASE NOTE: This is a research prototype.
5 * interp.c: Interpreter for CIL byte codes
8 * Paolo Molaro (lupus@ximian.com)
9 * Miguel de Icaza (miguel@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2001, 2002 Ximian, Inc.
27 #include <mono/os/gc_wrapper.h>
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/blob.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/io-layer/io-layer.h>
56 #include <mono/metadata/socket-io.h>
57 #include <mono/metadata/mono-config.h>
58 #include <mono/metadata/marshal.h>
59 #include <mono/metadata/environment.h>
60 #include <mono/metadata/mono-debug.h>
61 #include <mono/os/util.h>
63 /*#include <mono/cli/types.h>*/
68 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
71 #define finite _finite
75 #define finite isfinite
79 /* If true, then we output the opcodes as we interpret them */
80 static int global_tracing = 0;
81 static int global_no_pointers = 0;
83 static int debug_indent_level = 0;
86 * Pull the list of opcodes
88 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
92 #include "mono/cil/opcode.def"
97 #if SIZEOF_VOID_P == 8
98 #define GET_NATI(sp) ((sp).type == VAL_I32 ? (sp).data.i : (sp).data.nati)
100 #define GET_NATI(sp) (sp).data.i
103 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
105 (frame)->parent = (parent_frame); \
106 (frame)->obj = (obj_this); \
107 (frame)->stack_args = (method_args); \
108 (frame)->retval = (method_retval); \
109 (frame)->method = (mono_method); \
110 (frame)->ex_handler = NULL; \
111 (frame)->ex = NULL; \
112 (frame)->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)->remote_class->proxy_class;
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);
398 case MONO_TYPE_GENERICINST:
399 stackval_from_data (type->data.generic_inst->generic_type, result, data, pinvoke);
402 g_warning ("got type 0x%02x", type->type);
403 g_assert_not_reached ();
408 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
411 gpointer *p = (gpointer*)data;
415 //printf ("TODAT0 %p\n", data);
416 switch (type->type) {
419 guint8 *p = (guint8*)data;
423 case MONO_TYPE_BOOLEAN: {
424 guint8 *p = (guint8*)data;
425 *p = (val->data.i != 0);
430 case MONO_TYPE_CHAR: {
431 guint16 *p = (guint16*)data;
436 mono_i *p = (mono_i*)data;
437 /* In theory the value used by stloc should match the local var type
438 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
439 a native int - both by csc and mcs). Not sure what to do about sign extension
440 as it is outside the spec... doing the obvious */
441 *p = val->type == VAL_I32 ? val->data.i : val->data.nati;
445 mono_u *p = (mono_u*)data;
447 *p = val->type == VAL_I32 ? (guint32)val->data.i : val->data.nati;
452 gint32 *p = (gint32*)data;
458 gint64 *p = (gint64*)data;
463 float *p = (float*)data;
468 double *p = (double*)data;
472 case MONO_TYPE_STRING:
473 case MONO_TYPE_SZARRAY:
474 case MONO_TYPE_CLASS:
475 case MONO_TYPE_OBJECT:
476 case MONO_TYPE_ARRAY:
477 case MONO_TYPE_PTR: {
478 gpointer *p = (gpointer*)data;
482 case MONO_TYPE_VALUETYPE:
483 if (type->data.klass->enumtype) {
484 stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
490 size = mono_class_native_size (type->data.klass, NULL);
492 size = mono_class_value_size (type->data.klass, NULL);
494 memcpy (data, val->data.vt, size);
497 case MONO_TYPE_GENERICINST:
498 stackval_to_data (type->data.generic_inst->generic_type, val, data, pinvoke);
501 g_warning ("got type %x", type->type);
502 g_assert_not_reached ();
506 #define FILL_IN_TRACE(exception, frame) \
509 stack_trace = dump_frame (frame); \
510 (exception)->stack_trace = mono_string_new (mono_domain_get(), stack_trace); \
511 g_free (stack_trace); \
514 #define THROW_EX(exception,ex_ip) \
516 frame->ip = (ex_ip); \
517 frame->ex = (MonoException*)(exception); \
518 FILL_IN_TRACE(frame->ex, frame); \
519 goto handle_exception; \
523 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
526 guint32 *lower_bounds;
529 lengths = alloca (sizeof (guint32) * klass->rank * 2);
530 for (i = 0; i < sig->param_count; ++i) {
531 lengths [i] = values->data.i;
534 if (klass->rank == sig->param_count) {
535 /* Only lengths provided. */
538 /* lower bounds are first. */
539 lower_bounds = lengths;
540 lengths += klass->rank;
542 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
546 ves_array_set (MonoInvocation *frame)
548 stackval *sp = frame->stack_args;
552 gint32 i, t, pos, esize;
558 ac = o->vtable->klass;
560 g_assert (ac->rank >= 1);
563 if (ao->bounds != NULL) {
564 pos -= ao->bounds [0].lower_bound;
565 for (i = 1; i < ac->rank; i++) {
566 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
567 ao->bounds [i].length) {
568 frame->ex = mono_get_exception_index_out_of_range ();
569 FILL_IN_TRACE(frame->ex, frame);
572 pos = pos*ao->bounds [i].length + sp [i].data.i -
573 ao->bounds [i].lower_bound;
575 } else if (pos >= ao->max_length) {
576 frame->ex = mono_get_exception_index_out_of_range ();
577 FILL_IN_TRACE(frame->ex, frame);
581 if ((sp [ac->rank].type == VAL_OBJ) && sp [ac->rank].data.p && !mono_object_isinst (sp [ac->rank].data.p, mono_object_class (o)->element_class)) {
582 frame->ex = mono_get_exception_array_type_mismatch ();
583 FILL_IN_TRACE (frame->ex, frame);
587 esize = mono_array_element_size (ac);
588 ea = mono_array_addr_with_size (ao, esize, pos);
590 mt = frame->method->signature->params [ac->rank];
591 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
595 ves_array_get (MonoInvocation *frame)
597 stackval *sp = frame->stack_args;
601 gint32 i, t, pos, esize;
607 ac = o->vtable->klass;
609 g_assert (ac->rank >= 1);
612 if (ao->bounds != NULL) {
613 pos -= ao->bounds [0].lower_bound;
614 for (i = 1; i < ac->rank; i++) {
615 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
616 ao->bounds [i].length) {
617 frame->ex = mono_get_exception_index_out_of_range ();
618 FILL_IN_TRACE(frame->ex, frame);
622 pos = pos*ao->bounds [i].length + sp [i].data.i -
623 ao->bounds [i].lower_bound;
625 } else if (pos >= ao->max_length) {
626 frame->ex = mono_get_exception_index_out_of_range ();
627 FILL_IN_TRACE(frame->ex, frame);
631 esize = mono_array_element_size (ac);
632 ea = mono_array_addr_with_size (ao, esize, pos);
634 mt = frame->method->signature->ret;
635 stackval_from_data (mt, frame->retval, ea, FALSE);
639 ves_array_element_address (MonoInvocation *frame)
641 stackval *sp = frame->stack_args;
645 gint32 i, t, pos, esize;
650 ac = o->vtable->klass;
652 g_assert (ac->rank >= 1);
655 if (ao->bounds != NULL) {
656 pos -= ao->bounds [0].lower_bound;
657 for (i = 1; i < ac->rank; i++) {
658 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
659 ao->bounds [i].length) {
660 frame->ex = mono_get_exception_index_out_of_range ();
661 FILL_IN_TRACE(frame->ex, frame);
664 pos = pos*ao->bounds [i].length + sp [i].data.i -
665 ao->bounds [i].lower_bound;
667 } else if (pos >= ao->max_length) {
668 frame->ex = mono_get_exception_index_out_of_range ();
669 FILL_IN_TRACE(frame->ex, frame);
673 esize = mono_array_element_size (ac);
674 ea = mono_array_addr_with_size (ao, esize, pos);
676 frame->retval->type = VAL_MP;
677 frame->retval->data.p = ea;
681 interp_walk_stack (MonoStackWalk func, gpointer user_data)
683 ThreadContext *context = TlsGetValue (thread_context_id);
684 MonoInvocation *frame = context->current_frame;
686 MonoMethodHeader *hd;
689 gboolean managed = FALSE;
690 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
691 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
694 hd = ((MonoMethodNormal*)frame->method)->header;
695 il_offset = frame->ip - hd->code;
696 if (!frame->method->wrapper_type)
699 if (func (frame->method, -1, il_offset, managed, user_data))
701 frame = frame->parent;
706 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor, ThreadContext *context)
710 MonoInvocation *old_frame = context->current_frame;
711 MonoInvocation *old_env_frame = context->env_frame;
712 jmp_buf *old_env = context->current_env;
715 context->current_frame = old_frame;
716 context->env_frame = old_env_frame;
717 context->current_env = old_env;
718 context->search_for_handler = 0;
722 context->env_frame = frame;
723 context->current_env = &env;
726 if (!frame->method->info) {
727 func = frame->method->info = mono_arch_create_trampoline (sig, string_ctor);
729 func = (MonoPIFunc)frame->method->info;
732 func = mono_arch_create_trampoline (sig, string_ctor);
735 context->current_frame = frame;
737 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
740 stackval_from_data (&mono_defaults.string_class->byval_arg,
741 frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
742 } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
743 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
745 context->current_frame = old_frame;
746 context->env_frame = old_env_frame;
747 context->current_env = old_env;
752 * runtime specifies that the implementation of the method is automatically
753 * provided by the runtime and is primarily used for the methods of delegates.
756 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
758 const char *name = frame->method->name;
759 MonoObject *obj = (MonoObject*)frame->obj;
764 mono_class_init (frame->method->klass);
766 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
767 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
768 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
771 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
772 nm = mono_marshal_get_delegate_invoke (frame->method);
773 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
774 ves_exec_method_with_context (&call, context);
778 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
779 nm = mono_marshal_get_delegate_begin_invoke (frame->method);
780 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
781 ves_exec_method_with_context (&call, context);
785 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
786 nm = mono_marshal_get_delegate_end_invoke (frame->method);
787 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
788 ves_exec_method_with_context (&call, context);
794 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
795 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
796 ves_array_set (frame);
799 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
800 ves_array_get (frame);
803 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
804 ves_array_element_address (frame);
809 g_error ("Don't know how to exec runtime method %s.%s::%s",
810 frame->method->klass->name_space, frame->method->klass->name,
811 frame->method->name);
815 dump_stack (stackval *stack, stackval *sp)
818 GString *str = g_string_new ("");
821 return g_string_free (str, FALSE);
825 #if SIZEOF_VOID_P == 4
826 case VAL_NATI: g_string_sprintfa (str, "[%d/0x%0x] ", s->data.nati, s->data.nati); break;
828 case VAL_NATI: g_string_sprintfa (str, "[%lld/0x%0llx] ", s->data.nati, s->data.nati); break;
830 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
831 case VAL_I64: g_string_sprintfa (str, "[%lldL] ", s->data.l); break;
832 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
834 if (!global_no_pointers)
835 g_string_sprintfa (str, "[vt: %p] ", s->data.vt);
837 g_string_sprintfa (str, "[vt%s] ", s->data.vt ? "" : "=null");
840 MonoObject *obj = s->data.p;
841 if (global_no_pointers && obj && obj->vtable) {
842 MonoClass *klass = mono_object_class (obj);
843 if (klass == mono_defaults.string_class) {
844 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
845 g_string_sprintfa (str, "[str:%s] ", utf8);
848 } else if (klass == mono_defaults.sbyte_class) {
849 g_string_sprintfa (str, "[b:%d] ",
850 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
852 } else if (klass == mono_defaults.int16_class) {
853 g_string_sprintfa (str, "[b:%d] ",
854 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
856 } else if (klass == mono_defaults.int32_class) {
857 g_string_sprintfa (str, "[b:%d] ",
858 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
860 } else if (klass == mono_defaults.byte_class) {
861 g_string_sprintfa (str, "[b:%u] ",
862 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
864 } else if (klass == mono_defaults.char_class
865 || klass == mono_defaults.uint16_class) {
866 g_string_sprintfa (str, "[b:%u] ",
867 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
869 } else if (klass == mono_defaults.uint32_class) {
870 g_string_sprintfa (str, "[b:%u] ",
871 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
873 } else if (klass == mono_defaults.int64_class) {
874 g_string_sprintfa (str, "[b:%lld] ",
875 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
877 } else if (klass == mono_defaults.uint64_class) {
878 g_string_sprintfa (str, "[b:%llu] ",
879 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
881 } else if (klass == mono_defaults.double_class) {
882 g_string_sprintfa (str, "[b:%0.5f] ",
883 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
885 } else if (klass == mono_defaults.single_class) {
886 g_string_sprintfa (str, "[b:%0.5f] ",
887 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
889 } else if (klass == mono_defaults.boolean_class) {
890 g_string_sprintfa (str, "[b:%s] ",
891 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
899 if (!global_no_pointers)
900 g_string_sprintfa (str, "[%c:%p] ", s->type == VAL_OBJ ? 'O' : s->type == VAL_MP ? 'M' : '?', s->data.p);
902 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
907 return g_string_free (str, FALSE);
911 dump_frame (MonoInvocation *inv)
913 GString *str = g_string_new ("");
916 for (i = 0; inv; inv = inv->parent, ++i) {
917 if (inv->method != NULL) {
921 const char * opname = "";
922 gchar *source = NULL;
929 k = inv->method->klass;
931 if ((inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
932 (inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
933 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
937 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
940 opname = mono_opcode_names [codep];
941 codep = inv->ip - hd->code;
943 source = mono_debug_source_location_from_il_offset (inv->method, codep, NULL);
946 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
948 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s) at %s\n", i, codep, opname,
949 k->name_space, k->name, inv->method->name, args, source);
951 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
952 k->name_space, k->name, inv->method->name, args);
957 return g_string_free (str, FALSE);
961 INLINE_STRING_LENGTH = 1,
962 INLINE_STRING_GET_CHARS,
965 INLINE_TYPE_ELEMENT_TYPE
970 MonoClassField *field;
971 } MonoRuntimeFieldInfo;
977 MonoRuntimeFieldInfo *field_info;
982 write32(unsigned char *p, guint32 v)
985 p[1] = (v >> 8) & 0xff;
986 p[2] = (v >> 16) & 0xff;
987 p[3] = (v >> 24) & 0xff;
990 static CRITICAL_SECTION calc_section;
993 calc_offsets (MonoImage *image, MonoMethod *method)
995 int i, align, size, offset = 0;
996 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
997 MonoMethodSignature *signature = method->signature;
998 MonoGenericContext *generic_context = NULL;
999 register const unsigned char *ip, *end;
1000 const MonoOpcode *opcode;
1004 MonoDomain *domain = mono_domain_get ();
1005 MethodRuntimeData *rtd;
1008 if (method->signature->is_inflated)
1009 generic_context = ((MonoMethodInflated *) method)->context;
1011 mono_profiler_method_jit (method); /* sort of... */
1012 /* intern the strings in the method. */
1014 end = ip + header->code_size;
1021 opcode = &mono_opcodes [i];
1022 switch (opcode->argument) {
1023 case MonoInlineNone:
1026 case MonoInlineString:
1027 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
1030 case MonoInlineType:
1031 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1032 class = mono_class_get_full (image, read32 (ip + 1), generic_context);
1033 mono_class_init (class);
1034 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
1035 mono_class_vtable (domain, class);
1039 case MonoInlineField:
1043 case MonoInlineMethod:
1044 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1045 m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context);
1046 mono_class_init (m->klass);
1047 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
1048 mono_class_vtable (domain, m->klass);
1054 case MonoShortInlineR:
1056 case MonoInlineBrTarget:
1062 case MonoShortInlineVar:
1063 case MonoShortInlineI:
1064 case MonoShortInlineBrTarget:
1067 case MonoInlineSwitch: {
1080 g_assert_not_reached ();
1085 /* the rest needs to be locked so it is only done once */
1086 EnterCriticalSection(&calc_section);
1087 if (method->info != NULL) {
1088 LeaveCriticalSection(&calc_section);
1089 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1092 rtd = (MethodRuntimeData *)g_malloc0 (sizeof(MethodRuntimeData) + (header->num_locals - 1 + signature->hasthis + signature->param_count) * sizeof(guint32));
1093 for (i = 0; i < header->num_locals; ++i) {
1094 size = mono_type_size (header->locals [i], &align);
1095 offset += align - 1;
1096 offset &= ~(align - 1);
1097 rtd->offsets [i] = offset;
1100 rtd->locals_size = offset;
1102 if (signature->hasthis) {
1103 offset += sizeof (gpointer) - 1;
1104 offset &= ~(sizeof (gpointer) - 1);
1105 rtd->offsets [header->num_locals] = offset;
1106 offset += sizeof (gpointer);
1108 for (i = 0; i < signature->param_count; ++i) {
1109 if (signature->pinvoke) {
1110 size = mono_type_native_stack_size (signature->params [i], &align);
1114 size = mono_type_stack_size (signature->params [i], &align);
1115 offset += align - 1;
1116 offset &= ~(align - 1);
1117 rtd->offsets [signature->hasthis + header->num_locals + i] = offset;
1120 rtd->args_size = offset;
1121 rtd->field_info = g_malloc(n_fields * sizeof(MonoRuntimeFieldInfo));
1123 header->code = g_memdup(header->code, header->code_size);
1126 end = ip + header->code_size;
1133 opcode = &mono_opcodes [i];
1134 switch (opcode->argument) {
1135 case MonoInlineNone:
1138 case MonoInlineString:
1141 case MonoInlineType:
1144 case MonoInlineField:
1145 token = read32 (ip + 1);
1146 rtd->field_info[n_fields].field = mono_field_from_token (image, token, &class, generic_context);
1147 mono_class_vtable (domain, class);
1148 g_assert(rtd->field_info[n_fields].field->parent == class);
1149 write32 ((unsigned char *)ip + 1, n_fields);
1153 case MonoInlineMethod:
1158 case MonoShortInlineR:
1160 case MonoInlineBrTarget:
1166 case MonoShortInlineVar:
1167 case MonoShortInlineI:
1168 case MonoShortInlineBrTarget:
1171 case MonoInlineSwitch: {
1184 g_assert_not_reached ();
1190 * We store the inline info in addr, since it's unused for IL methods.
1192 if (method->klass == mono_defaults.string_class) {
1193 if (strcmp (method->name, "get_Length") == 0)
1194 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
1195 else if (strcmp (method->name, "get_Chars") == 0)
1196 method->addr = GUINT_TO_POINTER (INLINE_STRING_GET_CHARS);
1197 } else if (method->klass == mono_defaults.array_class) {
1198 if (strcmp (method->name, "get_Length") == 0)
1199 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
1200 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
1201 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
1202 } else if (method->klass == mono_defaults.monotype_class) {
1203 if (strcmp (method->name, "GetElementType") == 0)
1204 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
1206 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1208 LeaveCriticalSection(&calc_section);
1211 #define LOCAL_POS(n) (frame->locals + rtd->offsets [n])
1212 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1214 #define ARG_POS(n) (args_pointers [(n)])
1215 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1216 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1218 typedef struct _vtallocation vtallocation;
1220 struct _vtallocation {
1225 char data [MONO_ZERO_LEN_ARRAY];
1226 double force_alignment;
1230 #define vt_allocmem(sz, var) \
1232 vtallocation *tmp, *prev; \
1235 while (tmp && (tmp->max_size < (sz))) { \
1240 tmp = alloca (sizeof (vtallocation) + (sz)); \
1241 tmp->max_size = (sz); \
1242 g_assert ((sz) < 10000); \
1246 prev->next = tmp->next; \
1248 vtalloc = tmp->next; \
1250 var = tmp->u.data; \
1253 #define vt_alloc(vtype,sp,native) \
1254 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1255 if (!(vtype)->byref) { \
1257 if (native) vtsize = mono_class_native_size ((vtype)->data.klass, NULL); \
1258 else vtsize = mono_class_value_size ((vtype)->data.klass, NULL); \
1259 vt_allocmem(vtsize, (sp)->data.vt); \
1263 #define vt_free(sp) \
1265 if ((sp)->type == VAL_VALUET) { \
1266 vtallocation *tmp = (vtallocation*)(((char*)(sp)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1267 tmp->next = vtalloc; \
1272 #define stackvalpush(val, sp) \
1274 (sp)->type = (val)->type; \
1275 (sp)->data = (val)->data; \
1276 if ((val)->type == VAL_VALUET) { \
1277 vtallocation *vala = (vtallocation*)(((char*)(val)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1278 vt_allocmem(vala->size, (sp)->data.vt); \
1279 memcpy((sp)->data.vt, (val)->data.vt, vala->size); \
1284 #define stackvalcpy(src, dest) \
1286 (dest)->type = (src)->type; \
1287 (dest)->data = (src)->data; \
1288 if ((dest)->type == VAL_VALUET) { \
1289 vtallocation *tmp = (vtallocation*)(((char*)(src)->data.vt) - G_STRUCT_OFFSET (vtallocation, u)); \
1290 memcpy((dest)->data.vt, (src)->data.vt, tmp->size); \
1296 verify_method (MonoMethod *m)
1298 GSList *errors, *tmp;
1299 MonoVerifyInfo *info;
1301 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1303 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1304 for (tmp = errors; tmp; tmp = tmp->next) {
1306 g_print ("%s\n", info->message);
1310 mono_free_verify_list (errors);
1314 #define MYGUINT64_MAX 18446744073709551615ULL
1315 #define MYGINT64_MAX 9223372036854775807LL
1316 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1318 #define MYGUINT32_MAX 4294967295U
1319 #define MYGINT32_MAX 2147483647
1320 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1322 #define CHECK_ADD_OVERFLOW(a,b) \
1323 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1324 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1326 #define CHECK_SUB_OVERFLOW(a,b) \
1327 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1328 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1330 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1331 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1333 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1334 (guint32)(a) < (guint32)(b) ? -1 : 0
1336 #define CHECK_ADD_OVERFLOW64(a,b) \
1337 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1338 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1340 #define CHECK_SUB_OVERFLOW64(a,b) \
1341 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1342 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1344 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1345 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1347 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1348 (guint64)(a) < (guint64)(b) ? -1 : 0
1350 #if SIZEOF_VOID_P == 4
1351 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1352 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1354 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1355 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1358 /* Resolves to TRUE if the operands would overflow */
1359 #define CHECK_MUL_OVERFLOW(a,b) \
1360 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1361 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1362 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1363 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1364 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1365 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1366 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1368 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1369 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1370 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1372 #define CHECK_MUL_OVERFLOW64(a,b) \
1373 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1374 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1375 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1376 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1377 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1378 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1379 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1381 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1382 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1383 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1385 #if SIZEOF_VOID_P == 4
1386 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1387 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1389 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1390 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1394 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1396 MonoInvocation frame;
1397 ThreadContext *context = TlsGetValue (thread_context_id);
1398 MonoObject *retval = NULL;
1399 MonoMethodSignature *sig = method->signature;
1400 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1401 int i, type, isobject = 0;
1404 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1405 ThreadContext context_struct;
1406 MonoInvocation *old_frame;
1408 if (context == NULL) {
1409 context = &context_struct;
1410 context_struct.base_frame = &frame;
1411 context_struct.current_frame = NULL;
1412 context_struct.env_frame = NULL;
1413 context_struct.current_env = NULL;
1414 context_struct.search_for_handler = 0;
1415 TlsSetValue (thread_context_id, context);
1418 old_frame = context->current_frame;
1421 /* FIXME: Set frame for execption handling. */
1423 switch (sig->ret->type) {
1424 case MONO_TYPE_VOID:
1426 case MONO_TYPE_STRING:
1427 case MONO_TYPE_OBJECT:
1428 case MONO_TYPE_CLASS:
1429 case MONO_TYPE_ARRAY:
1430 case MONO_TYPE_SZARRAY:
1433 case MONO_TYPE_VALUETYPE:
1434 retval = mono_object_new (mono_domain_get (), klass);
1435 ret = ((char*)retval) + sizeof (MonoObject);
1436 if (!sig->ret->data.klass->enumtype)
1437 result.data.vt = ret;
1440 retval = mono_object_new (mono_domain_get (), klass);
1441 ret = ((char*)retval) + sizeof (MonoObject);
1445 for (i = 0; i < sig->param_count; ++i) {
1446 if (sig->params [i]->byref) {
1447 args [i].type = VAL_POINTER;
1448 args [i].data.p = params [i];
1451 type = sig->params [i]->type;
1456 case MONO_TYPE_BOOLEAN:
1457 args [i].type = VAL_I32;
1458 args [i].data.i = *(MonoBoolean*)params [i];
1462 case MONO_TYPE_CHAR:
1463 args [i].type = VAL_I32;
1464 args [i].data.i = *(gint16*)params [i];
1466 #if SIZEOF_VOID_P == 4
1467 case MONO_TYPE_U: /* use VAL_POINTER? */
1472 args [i].type = VAL_I32;
1473 args [i].data.i = *(gint32*)params [i];
1475 #if SIZEOF_VOID_P == 8
1481 args [i].type = VAL_I64;
1482 args [i].data.l = *(gint64*)params [i];
1484 case MONO_TYPE_VALUETYPE:
1485 if (sig->params [i]->data.klass->enumtype) {
1486 type = sig->params [i]->data.klass->enum_basetype->type;
1489 args [i].type = VAL_POINTER;
1490 args [i].data.p = params [i];
1493 case MONO_TYPE_STRING:
1494 case MONO_TYPE_CLASS:
1495 case MONO_TYPE_ARRAY:
1496 case MONO_TYPE_SZARRAY:
1497 case MONO_TYPE_OBJECT:
1498 args [i].type = VAL_OBJ;
1499 args [i].data.p = params [i];
1502 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1506 if (method->klass->valuetype)
1507 /* Unbox the instance, since valuetype methods expect an interior pointer. */
1508 obj = mono_object_unbox (obj);
1510 INIT_FRAME(&frame,context->current_frame,obj,args,&result,method);
1512 frame.invoke_trap = 1;
1513 ves_exec_method_with_context (&frame, context);
1514 if (context == &context_struct)
1515 TlsSetValue (thread_context_id, NULL);
1517 context->current_frame = old_frame;
1518 if (frame.ex != NULL) {
1520 *exc = (MonoObject*) frame.ex;
1521 if (*exc == (MonoObject *)quit_exception)
1522 mono_print_unhandled_exception(*exc);
1525 if (context->current_env != NULL) {
1526 context->env_frame->ex = frame.ex;
1527 longjmp(*context->current_env, 1);
1530 printf("dropped exception...\n");
1532 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1534 if (isobject || method->string_ctor)
1535 return result.data.p;
1536 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1540 static CRITICAL_SECTION create_method_pointer_mutex;
1542 static MonoGHashTable *method_pointer_hash = NULL;
1545 mono_create_method_pointer (MonoMethod *method)
1550 EnterCriticalSection (&create_method_pointer_mutex);
1551 if (!method_pointer_hash) {
1552 method_pointer_hash = mono_g_hash_table_new (NULL, NULL);
1554 addr = mono_g_hash_table_lookup (method_pointer_hash, method);
1556 LeaveCriticalSection (&create_method_pointer_mutex);
1561 * If it is a static P/Invoke method, we can just return the pointer
1562 * to the method implementation.
1564 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
1565 ji = g_new0 (MonoJitInfo, 1);
1566 ji->method = method;
1568 ji->code_start = method->addr;
1570 mono_jit_info_table_add (mono_root_domain, ji);
1572 addr = method->addr;
1575 addr = mono_arch_create_method_pointer (method);
1577 mono_g_hash_table_insert (method_pointer_hash, method, addr);
1578 LeaveCriticalSection (&create_method_pointer_mutex);
1584 * Need to optimize ALU ops when natural int == int32
1586 * IDEA: if we maintain a stack of ip, sp to be checked
1587 * in the return opcode, we could inline simple methods that don't
1588 * use the stack or local variables....
1590 * The {,.S} versions of many opcodes can/should be merged to reduce code
1595 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
1597 MonoDomain *domain = mono_domain_get ();
1598 MonoInvocation child_frame;
1599 MonoMethodHeader *header;
1600 MonoMethodSignature *signature;
1601 MonoGenericContext *generic_context = NULL;
1603 GSList *finally_ips = NULL;
1604 const unsigned char *endfinally_ip = NULL;
1605 register const unsigned char *ip;
1606 register stackval *sp = NULL;
1607 MethodRuntimeData *rtd;
1608 void **args_pointers;
1609 gint tracing = global_tracing;
1610 unsigned char tail_recursion = 0;
1611 unsigned char unaligned_address = 0;
1612 unsigned char volatile_address = 0;
1613 vtallocation *vtalloc = NULL;
1614 MonoVTable *method_class_vt;
1618 frame->ip = ip = NULL;
1619 context->current_frame = frame;
1621 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1622 frame->method = mono_marshal_get_native_wrapper (frame->method);
1623 if (frame->method == NULL)
1627 method_class_vt = mono_class_vtable (domain, frame->method->klass);
1628 if (!method_class_vt->initialized)
1629 mono_runtime_class_init (method_class_vt);
1630 signature = frame->method->signature;
1632 if (frame->method->signature->is_inflated)
1633 generic_context = ((MonoMethodInflated *) frame->method)->context;
1637 header = ((MonoMethodNormal *)frame->method)->header;
1639 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1640 if (!frame->method->addr) {
1641 /* assumes all internal calls with an array this are built in... */
1642 if (signature->hasthis && frame->method->klass->rank) {
1643 ves_runtime_method (frame, context);
1645 goto handle_exception;
1648 frame->method->addr = mono_lookup_internal_call (frame->method);
1650 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1651 frame->method->string_ctor, context);
1653 goto handle_exception;
1656 else if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1657 ves_runtime_method (frame, context);
1659 goto handle_exception;
1663 /*verify_method (frame->method);*/
1665 image = frame->method->klass->image;
1667 if (!frame->method->info)
1668 calc_offsets (image, frame->method);
1669 rtd = frame->method->info;
1672 * with alloca we get the expected huge performance gain
1673 * stackval *stack = g_new0(stackval, header->max_stack);
1675 g_assert (header->max_stack < 10000);
1676 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1678 if (header->num_locals) {
1679 g_assert (rtd->locals_size < 65536);
1680 frame->locals = alloca (rtd->locals_size);
1682 * yes, we do it unconditionally, because it needs to be done for
1683 * some cases anyway and checking for that would be even slower.
1685 memset (frame->locals, 0, rtd->locals_size);
1689 * Copy args from stack_args to args.
1691 if (signature->param_count || signature->hasthis) {
1693 int has_this = signature->hasthis;
1695 g_assert (rtd->args_size < 10000);
1696 frame->args = alloca (rtd->args_size);
1697 g_assert ((signature->param_count + has_this) < 1000);
1698 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1701 this_arg = args_pointers [0] = frame->args;
1702 *this_arg = frame->obj;
1704 for (i = 0; i < signature->param_count; ++i) {
1705 args_pointers [i + has_this] = frame->args + rtd->offsets [header->num_locals + has_this + i];
1706 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
1710 child_frame.parent = frame;
1717 * using while (ip < end) may result in a 15% performance drop,
1718 * but it may be useful for debug
1722 /*g_assert (sp >= stack);*/
1726 char *ins, *discode;
1727 if (sp > frame->stack) {
1728 ins = dump_stack (frame->stack, sp);
1730 ins = g_strdup ("");
1733 discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
1734 discode [strlen (discode) - 1] = 0; /* no \n */
1735 g_print ("(%u) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1747 G_BREAKPOINT (); /* this is not portable... */
1752 CASE (CEE_LDARG_3) {
1753 int n = (*ip)-CEE_LDARG_0;
1755 vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
1756 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
1763 CASE (CEE_LDLOC_3) {
1764 int n = (*ip)-CEE_LDLOC_0;
1765 MonoType *vartype = LOCAL_TYPE (header, n);
1767 if (vartype->type == MONO_TYPE_I4) {
1769 sp->data.i = *(gint32*) LOCAL_POS (n);
1773 vt_alloc (vartype, sp, FALSE);
1774 stackval_from_data (vartype, sp, LOCAL_POS (n), FALSE);
1782 CASE (CEE_STLOC_3) {
1783 int n = (*ip)-CEE_STLOC_0;
1786 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1787 gint32 *p = (gint32*)LOCAL_POS (n);
1791 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
1798 vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
1799 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1803 CASE (CEE_LDARGA_S) {
1805 sp->data.vt = ARG_POS (*ip);
1814 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
1820 vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
1821 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1825 CASE (CEE_LDLOCA_S) {
1827 sp->data.p = LOCAL_POS (*ip);
1836 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
1846 CASE (CEE_LDC_I4_M1)
1862 sp->data.i = (*ip) - CEE_LDC_I4_0;
1869 sp->data.i = *(const gint8 *)ip;
1876 sp->data.i = read32 (ip);
1883 sp->data.l = read64 (ip);
1890 sp->type = VAL_DOUBLE;
1899 sp->type = VAL_DOUBLE;
1900 readr8(ip, &sp->data.f);
1904 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1906 stackvalpush(sp - 1, sp);
1914 CASE (CEE_JMP) ves_abort(); BREAK;
1915 CASE (CEE_CALLVIRT) /* Fall through */
1916 CASE (CEE_CALLI) /* Fall through */
1918 MonoMethodSignature *csignature;
1920 stackval *endsp = sp;
1922 int virtual = *ip == CEE_CALLVIRT;
1923 int calli = *ip == CEE_CALLI;
1924 unsigned char *code = NULL;
1927 * We ignore tail recursion for now.
1934 token = read32 (ip);
1940 if (frame->method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE &&
1941 (ji = mono_jit_info_table_find (mono_root_domain, code)) != NULL) {
1942 child_frame.method = ji->method;
1943 csignature = ji->method->signature;
1945 else if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1946 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1947 child_frame.method = NULL;
1949 g_assert_not_reached ();
1953 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
1954 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
1956 child_frame.method = mono_get_method_full (image, token, NULL, generic_context);
1957 if (!child_frame.method)
1958 THROW_EX (mono_get_exception_missing_method (), ip -5);
1959 csignature = child_frame.method->signature;
1961 stackval *this_arg = &sp [-csignature->param_count-1];
1962 if (!this_arg->data.p)
1963 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1964 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1965 if (!child_frame.method)
1966 THROW_EX (mono_get_exception_missing_method (), ip -5);
1970 if (frame->method->wrapper_type == MONO_WRAPPER_NONE)
1971 if (child_frame.method && child_frame.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1972 child_frame.method = mono_marshal_get_synchronized_wrapper (child_frame.method);
1974 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
1975 /* decrement by the actual number of args */
1976 if (csignature->param_count) {
1977 sp -= csignature->param_count;
1978 child_frame.stack_args = sp;
1980 child_frame.stack_args = NULL;
1982 if (csignature->hasthis) {
1983 g_assert (sp >= frame->stack);
1986 * It may also be a TP from LD(S)FLDA
1987 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_MP);
1989 if (sp->type == VAL_OBJ && child_frame.method &&
1990 child_frame.method->klass->valuetype) /* unbox it */
1991 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1993 child_frame.obj = sp->data.p;
1995 child_frame.obj = NULL;
1997 if (csignature->ret->type != MONO_TYPE_VOID) {
1998 vt_alloc (csignature->ret, &retval, csignature->pinvoke);
1999 child_frame.retval = &retval;
2001 child_frame.retval = NULL;
2004 child_frame.ip = NULL;
2005 child_frame.ex = NULL;
2006 child_frame.ex_handler = NULL;
2008 if (!child_frame.method) {
2010 ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE, context);
2011 if (child_frame.ex) {
2012 frame->ex = child_frame.ex;
2013 goto handle_exception;
2015 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
2016 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
2017 g_assert (child_frame.method);
2018 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
2019 ves_exec_method_with_context (&child_frame, context);
2021 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
2022 case INLINE_STRING_LENGTH:
2023 retval.type = VAL_I32;
2024 retval.data.i = ((MonoString*)sp->data.p)->length;
2025 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
2027 case INLINE_STRING_GET_CHARS: {
2028 int idx = GET_NATI(sp [1]);
2029 if ((idx < 0) || (idx >= mono_string_length ((MonoString*)sp->data.p))) {
2030 child_frame.ex = mono_get_exception_index_out_of_range ();
2031 FILL_IN_TRACE(child_frame.ex, &child_frame);
2034 retval.type = VAL_I32;
2035 retval.data.i = mono_string_chars((MonoString*)sp->data.p)[idx];
2039 case INLINE_ARRAY_LENGTH:
2040 retval.type = VAL_I32;
2041 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
2043 case INLINE_ARRAY_RANK:
2044 retval.type = VAL_I32;
2045 retval.data.i = mono_object_class (sp->data.p)->rank;
2047 case INLINE_TYPE_ELEMENT_TYPE:
2048 retval.type = VAL_OBJ;
2050 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
2051 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
2052 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
2053 else if (c->element_class)
2054 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
2056 retval.data.p = NULL;
2060 ves_exec_method_with_context (&child_frame, context);
2064 context->current_frame = frame;
2066 while (endsp > sp) {
2071 if (child_frame.ex) {
2073 * An exception occurred, need to run finally, fault and catch handlers..
2075 frame->ex = child_frame.ex;
2076 if (context->search_for_handler) {
2077 context->search_for_handler = 0;
2078 goto handle_exception;
2080 goto handle_finally;
2083 /* need to handle typedbyref ... */
2084 if (csignature->ret->type != MONO_TYPE_VOID) {
2091 if (signature->ret->type != MONO_TYPE_VOID) {
2093 if (sp->type == VAL_VALUET) {
2094 /* the caller has already allocated the memory */
2095 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
2098 *frame->retval = *sp;
2101 if (sp > frame->stack)
2102 g_warning ("more values on stack: %d", sp-frame->stack);
2105 CASE (CEE_BR_S) /* Fall through */
2107 if (*ip == CEE_BR) {
2109 ip += (gint32) read32(ip);
2113 ip += (signed char) *ip;
2117 CASE (CEE_BRFALSE) /* Fall through */
2118 CASE (CEE_BRFALSE_S) {
2121 if (*ip == CEE_BRFALSE_S) {
2122 broffset = (signed char)ip [1];
2125 broffset = (gint32) read32 (ip + 1);
2130 case VAL_I32: result = sp->data.i == 0; break;
2131 case VAL_I64: result = sp->data.l == 0; break;
2132 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
2133 default: result = sp->data.p == NULL; break;
2139 CASE (CEE_BRTRUE) /* Fall through */
2140 CASE (CEE_BRTRUE_S) {
2143 if (*ip == CEE_BRTRUE_S) {
2144 broffset = (signed char)ip [1];
2147 broffset = (gint32) read32 (ip + 1);
2152 case VAL_I32: result = sp->data.i != 0; break;
2153 case VAL_I64: result = sp->data.l != 0; break;
2154 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
2155 default: result = sp->data.p != NULL; break;
2161 CASE (CEE_BEQ) /* Fall through */
2165 if (*ip == CEE_BEQ_S) {
2166 broffset = (signed char)ip [1];
2169 broffset = (gint32) read32 (ip + 1);
2173 if (sp->type == VAL_I32)
2174 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
2175 else if (sp->type == VAL_I64)
2176 result = sp [0].data.l == sp [1].data.l;
2177 else if (sp->type == VAL_DOUBLE)
2178 result = sp [0].data.f == sp [1].data.f;
2180 result = sp [0].data.nati == (mono_i)GET_NATI (sp [1]);
2185 CASE (CEE_BGE) /* Fall through */
2189 if (*ip == CEE_BGE_S) {
2190 broffset = (signed char)ip [1];
2193 broffset = (gint32) read32 (ip + 1);
2197 if (sp->type == VAL_I32)
2198 result = (mono_i)sp [0].data.i >= (mono_i)GET_NATI (sp [1]);
2199 else if (sp->type == VAL_I64)
2200 result = sp [0].data.l >= sp [1].data.l;
2201 else if (sp->type == VAL_DOUBLE)
2202 result = sp [0].data.f >= sp [1].data.f;
2204 result = (mono_i)sp [0].data.nati >= (mono_i)GET_NATI (sp [1]);
2209 CASE (CEE_BGT) /* Fall through */
2213 if (*ip == CEE_BGT_S) {
2214 broffset = (signed char)ip [1];
2217 broffset = (gint32) read32 (ip + 1);
2221 if (sp->type == VAL_I32)
2222 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
2223 else if (sp->type == VAL_I64)
2224 result = sp [0].data.l > sp [1].data.l;
2225 else if (sp->type == VAL_DOUBLE)
2226 result = sp [0].data.f > sp [1].data.f;
2228 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
2233 CASE (CEE_BLT) /* Fall through */
2237 if (*ip == CEE_BLT_S) {
2238 broffset = (signed char)ip [1];
2241 broffset = (gint32) read32 (ip + 1);
2245 if (sp->type == VAL_I32)
2246 result = (mono_i)sp[0].data.i < (mono_i)GET_NATI(sp[1]);
2247 else if (sp->type == VAL_I64)
2248 result = sp[0].data.l < sp[1].data.l;
2249 else if (sp->type == VAL_DOUBLE)
2250 result = sp[0].data.f < sp[1].data.f;
2252 result = (mono_i)sp[0].data.nati < (mono_i)GET_NATI(sp[1]);
2257 CASE (CEE_BLE) /* fall through */
2261 if (*ip == CEE_BLE_S) {
2262 broffset = (signed char)ip [1];
2265 broffset = (gint32) read32 (ip + 1);
2270 if (sp->type == VAL_I32)
2271 result = (mono_i)sp [0].data.i <= (mono_i)GET_NATI (sp [1]);
2272 else if (sp->type == VAL_I64)
2273 result = sp [0].data.l <= sp [1].data.l;
2274 else if (sp->type == VAL_DOUBLE)
2275 result = sp [0].data.f <= sp [1].data.f;
2277 result = (mono_i)sp [0].data.nati <= (mono_i)GET_NATI (sp [1]);
2283 CASE (CEE_BNE_UN) /* Fall through */
2284 CASE (CEE_BNE_UN_S) {
2287 if (*ip == CEE_BNE_UN_S) {
2288 broffset = (signed char)ip [1];
2291 broffset = (gint32) read32 (ip + 1);
2295 if (sp->type == VAL_I32)
2296 result = (mono_u)sp [0].data.i != (mono_u)GET_NATI (sp [1]);
2297 else if (sp->type == VAL_I64)
2298 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
2299 else if (sp->type == VAL_DOUBLE)
2300 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2301 (sp [0].data.f != sp [1].data.f);
2303 result = (mono_u)sp [0].data.nati != (mono_u)GET_NATI (sp [1]);
2308 CASE (CEE_BGE_UN) /* Fall through */
2309 CASE (CEE_BGE_UN_S) {
2312 if (*ip == CEE_BGE_UN_S) {
2313 broffset = (signed char)ip [1];
2316 broffset = (gint32) read32 (ip + 1);
2320 if (sp->type == VAL_I32)
2321 result = (mono_u)sp [0].data.i >= (mono_u)GET_NATI (sp [1]);
2322 else if (sp->type == VAL_I64)
2323 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
2324 else if (sp->type == VAL_DOUBLE)
2325 result = !isless (sp [0].data.f,sp [1].data.f);
2327 result = (mono_u)sp [0].data.nati >= (mono_u)GET_NATI (sp [1]);
2332 CASE (CEE_BGT_UN) /* Fall through */
2333 CASE (CEE_BGT_UN_S) {
2336 if (*ip == CEE_BGT_UN_S) {
2337 broffset = (signed char)ip [1];
2340 broffset = (gint32) read32 (ip + 1);
2344 if (sp->type == VAL_I32)
2345 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
2346 else if (sp->type == VAL_I64)
2347 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
2348 else if (sp->type == VAL_DOUBLE)
2349 result = isgreater (sp [0].data.f, sp [1].data.f);
2351 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
2356 CASE (CEE_BLE_UN) /* Fall through */
2357 CASE (CEE_BLE_UN_S) {
2360 if (*ip == CEE_BLE_UN_S) {
2361 broffset = (signed char)ip [1];
2364 broffset = (gint32) read32 (ip + 1);
2368 if (sp->type == VAL_I32)
2369 result = (mono_u)sp [0].data.i <= (mono_u)GET_NATI (sp [1]);
2370 else if (sp->type == VAL_I64)
2371 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2372 else if (sp->type == VAL_DOUBLE)
2373 result = islessequal (sp [0].data.f, sp [1].data.f);
2375 result = (mono_u)sp [0].data.nati <= (mono_u)GET_NATI (sp [1]);
2380 CASE (CEE_BLT_UN) /* Fall through */
2381 CASE (CEE_BLT_UN_S) {
2384 if (*ip == CEE_BLT_UN_S) {
2385 broffset = (signed char)ip [1];
2388 broffset = (gint32) read32 (ip + 1);
2392 if (sp->type == VAL_I32)
2393 result = (mono_u)sp[0].data.i < (mono_u)GET_NATI(sp[1]);
2394 else if (sp->type == VAL_I64)
2395 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2396 else if (sp->type == VAL_DOUBLE)
2397 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2398 (sp [0].data.f < sp [1].data.f);
2400 result = (mono_u)sp[0].data.nati < (mono_u)GET_NATI(sp[1]);
2407 const unsigned char *st;
2411 st = ip + sizeof (gint32) * n;
2413 if ((guint32)sp->data.i < n) {
2415 ip += sizeof (gint32) * (guint32)sp->data.i;
2416 offset = read32 (ip);
2425 sp[-1].type = VAL_I32;
2426 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2430 sp[-1].type = VAL_I32;
2431 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2435 sp[-1].type = VAL_I32;
2436 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2440 sp[-1].type = VAL_I32;
2441 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2443 CASE (CEE_LDIND_I4) /* Fall through */
2446 sp[-1].type = VAL_I32;
2447 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2451 sp[-1].type = VAL_I64;
2452 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2456 sp[-1].type = VAL_NATI;
2457 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2461 sp[-1].type = VAL_DOUBLE;
2462 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2466 sp[-1].type = VAL_DOUBLE;
2467 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2469 CASE (CEE_LDIND_REF)
2471 sp[-1].type = VAL_OBJ;
2472 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2474 CASE (CEE_STIND_REF) {
2482 CASE (CEE_STIND_I1) {
2487 *p = (gint8)sp[1].data.i;
2490 CASE (CEE_STIND_I2) {
2495 *p = (gint16)sp[1].data.i;
2498 CASE (CEE_STIND_I4) {
2506 CASE (CEE_STIND_I) {
2511 *p = (mono_i)sp[1].data.p;
2514 CASE (CEE_STIND_I8) {
2522 CASE (CEE_STIND_R4) {
2527 *p = (gfloat)sp[1].data.f;
2530 CASE (CEE_STIND_R8) {
2541 /* should probably consider the pointers as unsigned */
2542 if (sp->type == VAL_I32) {
2543 if (sp [-1].type == VAL_I32)
2544 sp [-1].data.i += sp [0].data.i;
2546 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.i;
2547 } else if (sp->type == VAL_I64)
2548 sp [-1].data.l += sp [0].data.l;
2549 else if (sp->type == VAL_DOUBLE)
2550 sp [-1].data.f += sp [0].data.f;
2552 if (sp [-1].type == VAL_I32) {
2553 sp [-1].data.nati = sp [-1].data.i + sp [0].data.nati;
2554 sp [-1].type = sp [0].type;
2556 sp [-1].data.nati = sp [-1].data.nati + sp [0].data.nati;
2562 /* should probably consider the pointers as unsigned */
2563 if (sp->type == VAL_I32) {
2564 if (sp [-1].type == VAL_I32)
2565 sp [-1].data.i -= sp [0].data.i;
2567 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
2568 sp [-1].type = VAL_NATI;
2570 } else if (sp->type == VAL_I64)
2571 sp [-1].data.l -= sp [0].data.l;
2572 else if (sp->type == VAL_DOUBLE)
2573 sp [-1].data.f -= sp [0].data.f;
2575 if (sp [-1].type == VAL_I32) {
2576 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
2577 sp [-1].type = sp [0].type;
2579 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
2585 if (sp->type == VAL_I32) {
2586 if (sp [-1].type == VAL_I32)
2587 sp [-1].data.i *= sp [0].data.i;
2589 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
2590 } else if (sp->type == VAL_I64)
2591 sp [-1].data.l *= sp [0].data.l;
2592 else if (sp->type == VAL_DOUBLE)
2593 sp [-1].data.f *= sp [0].data.f;
2595 if (sp [-1].type == VAL_NATI)
2596 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.nati;
2598 sp [-1].data.nati = sp [-1].data.i * sp [0].data.nati;
2599 sp [-1].type = VAL_NATI;
2606 if (sp->type == VAL_I32) {
2607 if (sp [0].data.i == 0)
2608 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2609 if (sp [-1].type == VAL_I32)
2610 sp [-1].data.i /= sp [0].data.i;
2612 sp [-1].data.nati /= sp [0].data.i;
2613 } else if (sp->type == VAL_I64) {
2614 if (sp [0].data.l == 0)
2615 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2616 sp [-1].data.l /= sp [0].data.l;
2617 } else if (sp->type == VAL_DOUBLE) {
2618 /* set NaN is divisor is 0.0 */
2619 sp [-1].data.f /= sp [0].data.f;
2621 if (sp [-1].type == VAL_NATI)
2622 sp [-1].data.nati = sp [-1].data.nati / sp [0].data.nati;
2624 sp [-1].data.nati = sp [-1].data.i / sp [0].data.nati;
2625 sp [-1].type = VAL_NATI;
2632 if (sp->type == VAL_I32) {
2633 if (sp [0].data.i == 0)
2634 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2635 if (sp [-1].type == VAL_NATI)
2636 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.i;
2638 sp [-1].data.i = (guint32)sp [-1].data.i / (guint32)sp [0].data.i;
2639 } else if (sp->type == VAL_I64) {
2641 if (sp [0].data.l == 0)
2642 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2643 val = sp [-1].data.l;
2644 val /= (guint64)sp [0].data.l;
2645 sp [-1].data.l = val;
2647 if (sp [0].data.nati == 0)
2648 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2649 if (sp [-1].type == VAL_NATI)
2650 sp [-1].data.nati = (mono_u)sp [-1].data.nati / (mono_u)sp [0].data.nati;
2652 sp [-1].data.nati = (mono_u)sp [-1].data.i / (mono_u)sp [0].data.nati;
2653 sp [-1].type = VAL_NATI;
2660 if (sp->type == VAL_I32) {
2661 if (sp [0].data.i == 0)
2662 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2663 if (sp [-1].type == VAL_NATI)
2664 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.i;
2666 sp [-1].data.i = sp [-1].data.i % sp [0].data.i;
2667 } else if (sp->type == VAL_I64) {
2668 if (sp [0].data.l == 0)
2669 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2670 sp [-1].data.l %= sp [0].data.l;
2671 } else if (sp->type == VAL_DOUBLE) {
2672 /* FIXME: what do we actually do here? */
2673 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2675 if (sp [0].data.nati == 0)
2676 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2677 if (sp [-1].type == VAL_NATI)
2678 sp [-1].data.nati = (mono_i)sp [-1].data.nati % (mono_i)sp [0].data.nati;
2680 sp [-1].data.nati = (mono_i)sp [-1].data.i % (mono_i)sp [0].data.nati;
2681 sp [-1].type = VAL_NATI;
2688 if (sp->type == VAL_I32) {
2689 if (sp [0].data.i == 0)
2690 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2691 if (sp [-1].type == VAL_NATI)
2692 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.i;
2694 sp [-1].data.i = (guint32)sp [-1].data.i % (guint32)sp [0].data.i;
2695 } else if (sp->type == VAL_I64) {
2696 if (sp [0].data.l == 0)
2697 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2698 sp [-1].data.l = (guint64)sp [-1].data.l % (guint64)sp [0].data.l;
2699 } else if (sp->type == VAL_DOUBLE) {
2700 /* unspecified behaviour according to the spec */
2702 if (sp [0].data.nati == 0)
2703 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2704 if (sp [-1].type == VAL_NATI)
2705 sp [-1].data.nati = (mono_u)sp [-1].data.nati % (mono_u)sp [0].data.nati;
2707 sp [-1].data.nati = (mono_u)sp [-1].data.i % (mono_u)sp [0].data.nati;
2708 sp [-1].type = VAL_NATI;
2715 if (sp->type == VAL_I32) {
2716 if (sp [-1].type == VAL_NATI)
2717 sp [-1].data.nati &= sp [0].data.i;
2719 sp [-1].data.i &= sp [0].data.i;
2721 else if (sp->type == VAL_I64)
2722 sp [-1].data.l &= sp [0].data.l;
2724 if (sp [-1].type == VAL_NATI)
2725 sp [-1].data.nati = (mono_i)sp [-1].data.nati & (mono_i)sp [0].data.nati;
2727 sp [-1].data.nati = (mono_i)sp [-1].data.i & (mono_i)sp [0].data.nati;
2728 sp [-1].type = VAL_NATI;
2735 if (sp->type == VAL_I32) {
2736 if (sp [-1].type == VAL_NATI)
2737 sp [-1].data.nati |= sp [0].data.i;
2739 sp [-1].data.i |= sp [0].data.i;
2741 else if (sp->type == VAL_I64)
2742 sp [-1].data.l |= sp [0].data.l;
2744 if (sp [-1].type == VAL_NATI)
2745 sp [-1].data.nati = (mono_i)sp [-1].data.nati | (mono_i)sp [0].data.nati;
2747 sp [-1].data.nati = (mono_i)sp [-1].data.i | (mono_i)sp [0].data.nati;
2748 sp [-1].type = VAL_NATI;
2755 if (sp->type == VAL_I32) {
2756 if (sp [-1].type == VAL_NATI)
2757 sp [-1].data.nati ^= sp [0].data.i;
2759 sp [-1].data.i ^= sp [0].data.i;
2761 else if (sp->type == VAL_I64)
2762 sp [-1].data.l ^= sp [0].data.l;
2764 if (sp [-1].type == VAL_NATI)
2765 sp [-1].data.nati = (mono_i)sp [-1].data.nati ^ (mono_i)sp [0].data.nati;
2767 sp [-1].data.nati = (mono_i)sp [-1].data.i ^ (mono_i)sp [0].data.nati;
2768 sp [-1].type = VAL_NATI;
2775 if (sp [-1].type == VAL_I32)
2776 sp [-1].data.i <<= GET_NATI (sp [0]);
2777 else if (sp [-1].type == VAL_I64)
2778 sp [-1].data.l <<= GET_NATI (sp [0]);
2780 sp [-1].data.nati <<= GET_NATI (sp [0]);
2785 if (sp [-1].type == VAL_I32)
2786 sp [-1].data.i >>= GET_NATI (sp [0]);
2787 else if (sp [-1].type == VAL_I64)
2788 sp [-1].data.l >>= GET_NATI (sp [0]);
2790 sp [-1].data.nati = ((mono_i)sp [-1].data.nati) >> GET_NATI (sp [0]);
2795 if (sp [-1].type == VAL_I32)
2796 sp [-1].data.i = (guint)sp [-1].data.i >> GET_NATI (sp [0]);
2797 else if (sp [-1].type == VAL_I64)
2798 sp [-1].data.l = (guint64)sp [-1].data.l >> GET_NATI (sp [0]);
2800 sp [-1].data.nati = ((mono_u)sp[-1].data.nati) >> GET_NATI (sp [0]);
2805 if (sp->type == VAL_I32)
2806 sp->data.i = - sp->data.i;
2807 else if (sp->type == VAL_I64)
2808 sp->data.l = - sp->data.l;
2809 else if (sp->type == VAL_DOUBLE)
2810 sp->data.f = - sp->data.f;
2811 else if (sp->type == VAL_NATI)
2812 sp->data.nati = - (mono_i)sp->data.nati;
2818 if (sp->type == VAL_I32)
2819 sp->data.i = ~ sp->data.i;
2820 else if (sp->type == VAL_I64)
2821 sp->data.l = ~ sp->data.l;
2822 else if (sp->type == VAL_NATI)
2823 sp->data.nati = ~ (mono_i)sp->data.p;
2826 CASE (CEE_CONV_U1) {
2828 switch (sp [-1].type) {
2830 sp [-1].data.i = (guint8)sp [-1].data.f;
2833 sp [-1].data.i = (guint8)sp [-1].data.l;
2838 sp [-1].data.i = (guint8)sp [-1].data.i;
2841 sp [-1].data.i = (guint8)sp [-1].data.nati;
2844 sp [-1].type = VAL_I32;
2847 CASE (CEE_CONV_I1) {
2849 switch (sp [-1].type) {
2851 sp [-1].data.i = (gint8)sp [-1].data.f;
2854 sp [-1].data.i = (gint8)sp [-1].data.l;
2859 sp [-1].data.i = (gint8)sp [-1].data.i;
2862 sp [-1].data.i = (gint8)sp [-1].data.nati;
2865 sp [-1].type = VAL_I32;
2868 CASE (CEE_CONV_U2) {
2870 switch (sp [-1].type) {
2872 sp [-1].data.i = (guint16)sp [-1].data.f;
2875 sp [-1].data.i = (guint16)sp [-1].data.l;
2880 sp [-1].data.i = (guint16)sp [-1].data.i;
2883 sp [-1].data.i = (guint16)sp [-1].data.nati;
2886 sp [-1].type = VAL_I32;
2889 CASE (CEE_CONV_I2) {
2891 switch (sp [-1].type) {
2893 sp [-1].data.i = (gint16)sp [-1].data.f;
2896 sp [-1].data.i = (gint16)sp [-1].data.l;
2901 sp [-1].data.i = (gint16)sp [-1].data.i;
2904 sp [-1].data.i = (gint16)sp [-1].data.nati;
2907 sp [-1].type = VAL_I32;
2910 CASE (CEE_CONV_U4) /* Fall through */
2911 #if SIZEOF_VOID_P == 4
2912 CASE (CEE_CONV_I) /* Fall through */
2913 CASE (CEE_CONV_U) /* Fall through */
2915 CASE (CEE_CONV_I4) {
2917 switch (sp [-1].type) {
2919 sp [-1].data.i = (gint32)sp [-1].data.f;
2922 sp [-1].data.i = (gint32)sp [-1].data.l;
2929 sp [-1].data.i = (gint32)sp [-1].data.p;
2932 sp [-1].type = VAL_I32;
2935 #if SIZEOF_VOID_P == 8
2936 CASE (CEE_CONV_I) /* Fall through */
2940 switch (sp [-1].type) {
2942 sp [-1].data.l = (gint64)sp [-1].data.f;
2949 sp [-1].data.l = (gint64)sp [-1].data.i;
2952 sp [-1].data.l = (gint64)sp [-1].data.nati;
2955 sp [-1].type = ip[-1] == CEE_CONV_I ? VAL_NATI : VAL_I64;
2957 CASE (CEE_CONV_R4) {
2959 switch (sp [-1].type) {
2961 sp [-1].data.f = (float)sp [-1].data.f;
2964 sp [-1].data.f = (float)sp [-1].data.l;
2969 sp [-1].data.f = (float)sp [-1].data.i;
2972 sp [-1].data.f = (float)sp [-1].data.nati;
2975 sp [-1].type = VAL_DOUBLE;
2978 CASE (CEE_CONV_R8) {
2980 switch (sp [-1].type) {
2982 sp [-1].data.f = (double)sp [-1].data.f;
2985 sp [-1].data.f = (double)sp [-1].data.l;
2990 sp [-1].data.f = (double)sp [-1].data.i;
2993 sp [-1].data.f = (double)sp [-1].data.nati;
2996 sp [-1].type = VAL_DOUBLE;
2999 #if SIZEOF_VOID_P == 8
3000 CASE (CEE_CONV_U) /* Fall through */
3005 switch (sp [-1].type){
3007 sp [-1].data.l = (guint64)sp [-1].data.f;
3014 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3017 sp [-1].data.l = (guint64) sp [-1].data.nati;
3020 sp [-1].type = ip[-1] == CEE_CONV_U ? VAL_NATI : VAL_I64;
3025 vtklass = mono_class_get_full (image, read32 (ip), generic_context);
3028 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
3037 token = read32 (ip);
3040 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3041 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3043 c = mono_class_get_full (image, token, generic_context);
3045 addr = sp [-1].data.vt;
3046 vt_alloc (&c->byval_arg, &sp [-1], FALSE);
3047 stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
3055 str_index = mono_metadata_token_index (read32 (ip));
3058 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
3059 o = (MonoObject *)mono_string_new_wrapper(
3060 mono_method_get_wrapper_data (frame->method, str_index));
3063 o = (MonoObject*)mono_ldstr (domain, image, str_index);
3072 MonoClass *newobj_class;
3073 MonoMethodSignature *csig;
3074 stackval valuetype_this;
3075 stackval *endsp = sp;
3082 token = read32 (ip);
3085 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3086 child_frame.method = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
3088 child_frame.method = mono_get_method_full (image, token, NULL, generic_context);
3089 if (!child_frame.method)
3090 THROW_EX (mono_get_exception_missing_method (), ip -5);
3092 csig = child_frame.method->signature;
3093 newobj_class = child_frame.method->klass;
3094 /*if (profiling_classes) {
3095 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3097 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3101 if (newobj_class->parent == mono_defaults.array_class) {
3102 sp -= csig->param_count;
3103 o = ves_array_create (domain, newobj_class, csig, sp);
3104 goto array_constructed;
3108 * First arg is the object.
3110 if (newobj_class->valuetype) {
3112 vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
3113 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
3114 zero = valuetype_this.data.vt;
3115 child_frame.obj = valuetype_this.data.vt;
3117 memset (&valuetype_this, 0, sizeof (stackval));
3118 zero = &valuetype_this;
3119 child_frame.obj = &valuetype_this;
3121 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
3123 if (newobj_class != mono_defaults.string_class) {
3124 o = mono_object_new (domain, newobj_class);
3125 child_frame.obj = o;
3127 child_frame.retval = &retval;
3131 if (csig->param_count) {
3132 sp -= csig->param_count;
3133 child_frame.stack_args = sp;
3135 child_frame.stack_args = NULL;
3138 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3140 child_frame.ip = NULL;
3141 child_frame.ex = NULL;
3142 child_frame.ex_handler = NULL;
3144 ves_exec_method_with_context (&child_frame, context);
3146 context->current_frame = frame;
3148 while (endsp > sp) {
3153 if (child_frame.ex) {
3155 * An exception occurred, need to run finally, fault and catch handlers..
3157 frame->ex = child_frame.ex;
3158 goto handle_finally;
3161 * a constructor returns void, but we need to return the object we created
3164 if (newobj_class->valuetype && !newobj_class->enumtype) {
3165 *sp = valuetype_this;
3166 } else if (newobj_class == mono_defaults.string_class) {
3175 CASE (CEE_CASTCLASS) /* Fall through */
3180 int do_isinst = *ip == CEE_ISINST;
3183 token = read32 (ip);
3184 c = mono_class_get_full (image, token, generic_context);
3186 g_assert (sp [-1].type == VAL_OBJ);
3188 if ((o = sp [-1].data.p)) {
3189 if (!mono_object_isinst (o, c)) {
3191 sp [-1].data.p = NULL;
3193 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3199 CASE (CEE_CONV_R_UN)
3201 switch (sp [-1].type) {
3205 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3210 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3213 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
3216 sp [-1].type = VAL_DOUBLE;
3219 CASE (CEE_UNUSED1) ves_abort(); BREAK;
3226 token = read32 (ip);
3228 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3229 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3231 c = mono_class_get_full (image, token, generic_context);
3235 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3237 if (!(mono_object_isinst (o, c) ||
3238 ((o->vtable->klass->rank == 0) &&
3239 (o->vtable->klass->element_class == c->element_class))))
3240 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
3242 sp [-1].type = VAL_MP;
3243 sp [-1].data.p = (char *)o + sizeof (MonoObject);
3250 frame->ex_handler = NULL;
3252 sp->data.p = mono_get_exception_null_reference ();
3253 THROW_EX ((MonoException *)sp->data.p, ip);
3255 CASE (CEE_LDFLDA) /* Fall through */
3258 MonoClassField *field;
3260 int load_addr = *ip == CEE_LDFLDA;
3263 if (!sp [-1].data.p)
3264 THROW_EX (mono_get_exception_null_reference (), ip);
3267 token = read32 (ip);
3268 field = rtd->field_info[token].field;
3271 if (sp [-1].type == VAL_OBJ) {
3272 obj = sp [-1].data.p;
3273 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3274 MonoClass *klass = ((MonoTransparentProxy*)obj)->remote_class->proxy_class;
3275 addr = mono_load_remote_field (obj, klass, field, NULL);
3277 addr = (char*)obj + field->offset;
3280 obj = sp [-1].data.vt;
3281 addr = (char*)obj + field->offset - sizeof (MonoObject);
3285 sp [-1].type = VAL_MP;
3286 sp [-1].data.p = addr;
3288 vt_alloc (field->type, &sp [-1], FALSE);
3289 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3295 MonoClassField *field;
3296 guint32 token, offset;
3301 THROW_EX (mono_get_exception_null_reference (), ip);
3304 token = read32 (ip);
3305 field = rtd->field_info[token].field;
3308 if (sp [0].type == VAL_OBJ) {
3309 obj = sp [0].data.p;
3311 if (obj->vtable->klass == mono_defaults.transparent_proxy_class && field->parent->marshalbyref) {
3312 MonoClass *klass = ((MonoTransparentProxy*)obj)->remote_class->proxy_class;
3313 mono_store_remote_field (obj, klass, field, &sp [1].data);
3315 offset = field->offset;
3316 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3320 obj = sp [0].data.vt;
3321 offset = field->offset - sizeof (MonoObject);
3322 stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
3328 CASE (CEE_LDSFLD) /* Fall through */
3329 CASE (CEE_LDSFLDA) {
3331 MonoClassField *field;
3333 int load_addr = *ip == CEE_LDSFLDA;
3337 token = read32 (ip);
3338 field = rtd->field_info[token].field;
3341 vt = mono_class_vtable (domain, field->parent);
3342 if (!vt->initialized)
3343 mono_runtime_class_init (vt);
3345 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3346 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3348 addr = (char*)(vt->data) + field->offset;
3354 vt_alloc (field->type, sp, FALSE);
3355 stackval_from_data (field->type, sp, addr, FALSE);
3362 MonoClassField *field;
3367 token = read32 (ip);
3368 field = rtd->field_info[token].field;
3372 vt = mono_class_vtable (domain, field->parent);
3373 if (!vt->initialized)
3374 mono_runtime_class_init (vt);
3376 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
3377 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3379 addr = (char*)(vt->data) + field->offset;
3381 stackval_to_data (field->type, sp, addr, FALSE);
3388 vtklass = mono_class_get_full (image, read32 (ip), generic_context);
3393 * LAMESPEC: According to the spec, the stack should contain a
3394 * pointer to a value type. In reality, it can contain anything.
3396 if (sp [1].type == VAL_VALUET)
3397 memcpy (sp [0].data.p, sp [1].data.vt, mono_class_value_size (vtklass, NULL));
3399 memcpy (sp [0].data.p, &sp [1].data, mono_class_value_size (vtklass, NULL));
3402 #if SIZEOF_VOID_P == 8
3403 CASE (CEE_CONV_OVF_I_UN)
3405 CASE (CEE_CONV_OVF_I8_UN) {
3406 switch (sp [-1].type) {
3408 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
3409 THROW_EX (mono_get_exception_overflow (), ip);
3410 sp [-1].data.l = (guint64)sp [-1].data.f;
3417 /* Can't overflow */
3418 sp [-1].data.l = (guint64)sp [-1].data.i;
3421 sp [-1].data.l = (guint64)sp [-1].data.nati;
3424 sp [-1].type = VAL_I64;
3428 #if SIZEOF_VOID_P == 8
3429 CASE (CEE_CONV_OVF_U_UN)
3431 CASE (CEE_CONV_OVF_U8_UN) {
3432 switch (sp [-1].type) {
3434 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
3435 THROW_EX (mono_get_exception_overflow (), ip);
3436 sp [-1].data.l = (guint64)sp [-1].data.f;
3444 /* Can't overflow */
3445 sp [-1].data.l = (guint64)sp [-1].data.i;
3448 /* Can't overflow */
3449 sp [-1].data.l = (guint64)sp [-1].data.nati;
3452 sp [-1].type = VAL_I64;
3456 #if SIZEOF_VOID_P == 4
3457 CASE (CEE_CONV_OVF_I_UN)
3458 CASE (CEE_CONV_OVF_U_UN)
3460 CASE (CEE_CONV_OVF_I1_UN)
3461 CASE (CEE_CONV_OVF_I2_UN)
3462 CASE (CEE_CONV_OVF_I4_UN)
3463 CASE (CEE_CONV_OVF_U1_UN)
3464 CASE (CEE_CONV_OVF_U2_UN)
3465 CASE (CEE_CONV_OVF_U4_UN) {
3467 switch (sp [-1].type) {
3469 if (sp [-1].data.f <= -1.0)
3470 THROW_EX (mono_get_exception_overflow (), ip);
3471 value = (guint64)sp [-1].data.f;
3474 value = (guint64)sp [-1].data.l;
3479 value = (guint64)sp [-1].data.i;
3482 value = (guint64)sp [-1].data.nati;
3486 case CEE_CONV_OVF_I1_UN:
3488 THROW_EX (mono_get_exception_overflow (), ip);
3489 sp [-1].data.i = value;
3490 sp [-1].type = VAL_I32;
3492 case CEE_CONV_OVF_I2_UN:
3494 THROW_EX (mono_get_exception_overflow (), ip);
3495 sp [-1].data.i = value;
3496 sp [-1].type = VAL_I32;
3498 #if SIZEOF_VOID_P == 4
3499 case CEE_CONV_OVF_I_UN: /* Fall through */
3501 case CEE_CONV_OVF_I4_UN:
3502 if (value > MYGUINT32_MAX)
3503 THROW_EX (mono_get_exception_overflow (), ip);
3504 sp [-1].data.i = value;
3505 sp [-1].type = VAL_I32;
3507 case CEE_CONV_OVF_U1_UN:
3509 THROW_EX (mono_get_exception_overflow (), ip);
3510 sp [-1].data.i = value;
3511 sp [-1].type = VAL_I32;
3513 case CEE_CONV_OVF_U2_UN:
3515 THROW_EX (mono_get_exception_overflow (), ip);
3516 sp [-1].data.i = value;
3517 sp [-1].type = VAL_I32;
3519 #if SIZEOF_VOID_P == 4
3520 case CEE_CONV_OVF_U_UN: /* Fall through */
3522 case CEE_CONV_OVF_U4_UN:
3523 if (value > 4294967295U)
3524 THROW_EX (mono_get_exception_overflow (), ip);
3525 sp [-1].data.i = value;
3526 sp [-1].type = VAL_I32;
3529 g_assert_not_reached ();
3539 token = read32 (ip);
3541 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3542 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3544 class = mono_class_get_full (image, token, generic_context);
3545 g_assert (class != NULL);
3547 sp [-1].type = VAL_OBJ;
3548 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3549 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3551 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
3552 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3554 /* need to vt_free (sp); */
3566 token = read32 (ip);
3568 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3569 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3571 class = mono_class_get_full (image, token, generic_context);
3573 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3576 sp [-1].type = VAL_OBJ;
3578 /*if (profiling_classes) {
3579 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3581 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3591 g_assert (sp [-1].type == VAL_OBJ);
3595 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3597 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3599 sp [-1].type = VAL_I32;
3600 sp [-1].data.i = mono_array_length (o);
3604 CASE (CEE_LDELEMA) {
3606 guint32 esize, token;
3610 token = read32 (ip);
3614 g_assert (sp [0].type == VAL_OBJ);
3617 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3619 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3620 if (aindex >= mono_array_length (o))
3621 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3623 /* check the array element corresponds to token */
3624 esize = mono_array_element_size (o->obj.vtable->klass);
3627 sp->data.p = mono_array_addr_with_size (o, esize, aindex);
3632 CASE (CEE_LDELEM_I1) /* fall through */
3633 CASE (CEE_LDELEM_U1) /* fall through */
3634 CASE (CEE_LDELEM_I2) /* fall through */
3635 CASE (CEE_LDELEM_U2) /* fall through */
3636 CASE (CEE_LDELEM_I4) /* fall through */
3637 CASE (CEE_LDELEM_U4) /* fall through */
3638 CASE (CEE_LDELEM_I8) /* fall through */
3639 CASE (CEE_LDELEM_I) /* fall through */
3640 CASE (CEE_LDELEM_R4) /* fall through */
3641 CASE (CEE_LDELEM_R8) /* fall through */
3642 CASE (CEE_LDELEM_REF) {
3648 g_assert (sp [0].type == VAL_OBJ);
3651 THROW_EX (mono_get_exception_null_reference (), ip);
3653 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3655 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3656 if (aindex >= mono_array_length (o))
3657 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3660 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3664 sp [0].data.i = mono_array_get (o, gint8, aindex);
3665 sp [0].type = VAL_I32;
3668 sp [0].data.i = mono_array_get (o, guint8, aindex);
3669 sp [0].type = VAL_I32;
3672 sp [0].data.i = mono_array_get (o, gint16, aindex);
3673 sp [0].type = VAL_I32;
3676 sp [0].data.i = mono_array_get (o, guint16, aindex);
3677 sp [0].type = VAL_I32;
3680 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3681 sp [0].type = VAL_NATI;
3684 sp [0].data.i = mono_array_get (o, gint32, aindex);
3685 sp [0].type = VAL_I32;
3688 sp [0].data.i = mono_array_get (o, guint32, aindex);
3689 sp [0].type = VAL_I32;
3692 sp [0].data.l = mono_array_get (o, guint64, aindex);
3693 sp [0].type = VAL_I64;
3696 sp [0].data.f = mono_array_get (o, float, aindex);
3697 sp [0].type = VAL_DOUBLE;
3700 sp [0].data.f = mono_array_get (o, double, aindex);
3701 sp [0].type = VAL_DOUBLE;
3703 case CEE_LDELEM_REF:
3704 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3705 sp [0].type = VAL_OBJ;
3715 CASE (CEE_STELEM_I) /* fall through */
3716 CASE (CEE_STELEM_I1) /* fall through */
3717 CASE (CEE_STELEM_I2) /* fall through */
3718 CASE (CEE_STELEM_I4) /* fall through */
3719 CASE (CEE_STELEM_I8) /* fall through */
3720 CASE (CEE_STELEM_R4) /* fall through */
3721 CASE (CEE_STELEM_R8) /* fall through */
3722 CASE (CEE_STELEM_REF) {
3729 g_assert (sp [0].type == VAL_OBJ);
3732 THROW_EX (mono_get_exception_null_reference (), ip);
3734 ac = o->obj.vtable->klass;
3735 g_assert (MONO_CLASS_IS_ARRAY (ac));
3737 aindex = sp [1].type == VAL_I32? sp [1].data.i: sp [1].data.nati;
3738 if (aindex >= mono_array_length (o))
3739 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3743 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3746 mono_array_set (o, gint8, aindex, sp [2].data.i);
3749 mono_array_set (o, gint16, aindex, sp [2].data.i);
3752 mono_array_set (o, gint32, aindex, sp [2].data.i);
3755 mono_array_set (o, gint64, aindex, sp [2].data.l);
3758 mono_array_set (o, float, aindex, sp [2].data.f);
3761 mono_array_set (o, double, aindex, sp [2].data.f);
3763 case CEE_STELEM_REF:
3764 g_assert (sp [2].type == VAL_OBJ);
3765 if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
3766 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3767 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3778 CASE (CEE_UNBOX_ANY)
3791 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3793 #if SIZEOF_VOID_P == 4
3794 CASE (CEE_CONV_OVF_I)
3795 CASE (CEE_CONV_OVF_U)
3797 CASE (CEE_CONV_OVF_I1)
3798 CASE (CEE_CONV_OVF_I2)
3799 CASE (CEE_CONV_OVF_I4)
3800 CASE (CEE_CONV_OVF_U1)
3801 CASE (CEE_CONV_OVF_U2)
3802 CASE (CEE_CONV_OVF_U4) {
3804 switch (sp [-1].type) {
3806 value = (gint64)sp [-1].data.f;
3809 value = (gint64)sp [-1].data.l;
3814 value = (gint64)sp [-1].data.i;
3817 value = (gint64)sp [-1].data.nati;
3821 case CEE_CONV_OVF_I1:
3822 if (value < -128 || value > 127)
3823 THROW_EX (mono_get_exception_overflow (), ip);
3824 sp [-1].data.i = value;
3825 sp [-1].type = VAL_I32;
3827 case CEE_CONV_OVF_I2:
3828 if (value < -32768 || value > 32767)
3829 THROW_EX (mono_get_exception_overflow (), ip);
3830 sp [-1].data.i = value;
3831 sp [-1].type = VAL_I32;
3833 #if SIZEOF_VOID_P == 4
3834 case CEE_CONV_OVF_I: /* Fall through */
3836 case CEE_CONV_OVF_I4:
3837 if (value < MYGINT32_MIN || value > MYGINT32_MAX)
3838 THROW_EX (mono_get_exception_overflow (), ip);
3839 sp [-1].data.i = value;
3840 sp [-1].type = VAL_I32;
3842 case CEE_CONV_OVF_U1:
3843 if (value < 0 || value > 255)
3844 THROW_EX (mono_get_exception_overflow (), ip);
3845 sp [-1].data.i = value;
3846 sp [-1].type = VAL_I32;
3848 case CEE_CONV_OVF_U2:
3849 if (value < 0 || value > 65535)
3850 THROW_EX (mono_get_exception_overflow (), ip);
3851 sp [-1].data.i = value;
3852 sp [-1].type = VAL_I32;
3854 #if SIZEOF_VOID_P == 4
3855 case CEE_CONV_OVF_U: /* Fall through */
3857 case CEE_CONV_OVF_U4:
3858 if (value < 0 || value > MYGUINT32_MAX)
3859 THROW_EX (mono_get_exception_overflow (), ip);
3860 sp [-1].data.i = value;
3861 sp [-1].type = VAL_I32;
3864 g_assert_not_reached ();
3870 #if SIZEOF_VOID_P == 8
3871 CASE (CEE_CONV_OVF_I)
3873 CASE (CEE_CONV_OVF_I8)
3874 /* FIXME: handle other cases */
3875 if (sp [-1].type == VAL_I32) {
3876 sp [-1].data.l = (guint64)sp [-1].data.i;
3877 sp [-1].type = VAL_I64;
3878 } else if(sp [-1].type == VAL_I64) {
3879 /* defined as NOP */
3886 #if SIZEOF_VOID_P == 8
3887 CASE (CEE_CONV_OVF_U)
3889 CASE (CEE_CONV_OVF_U8)
3890 /* FIXME: handle other cases */
3891 if (sp [-1].type == VAL_I32) {
3892 sp [-1].data.l = (guint64) sp [-1].data.i;
3893 sp [-1].type = VAL_I64;
3894 } else if(sp [-1].type == VAL_I64) {
3895 /* defined as NOP */
3907 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3908 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3910 if (!finite(sp [-1].data.f))
3911 THROW_EX (mono_get_exception_arithmetic (), ip);
3914 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3915 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3916 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3925 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3926 CASE (CEE_LDTOKEN) {
3928 MonoClass *handle_class;
3930 handle = mono_ldtoken (image, read32 (ip), &handle_class, generic_context);
3932 vt_alloc (&handle_class->byval_arg, sp, FALSE);
3933 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
3939 /* FIXME: check overflow */
3940 if (sp->type == VAL_I32) {
3941 if (sp [-1].type == VAL_I32) {
3942 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, sp [0].data.i))
3943 THROW_EX (mono_get_exception_overflow (), ip);
3944 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)sp [0].data.i;
3946 if (CHECK_ADD_OVERFLOW_NAT (sp [-1].data.nati, (mono_i)sp [0].data.i))
3947 THROW_EX (mono_get_exception_overflow (), ip);
3948 sp [-1].data.nati = sp [-1].data.nati + (mono_i)sp [0].data.i;
3950 } else if (sp->type == VAL_I64) {
3951 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3952 THROW_EX (mono_get_exception_overflow (), ip);
3953 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3954 } else if (sp->type == VAL_DOUBLE)
3955 sp [-1].data.f += sp [0].data.f;
3957 char *p = sp [-1].data.p;
3958 p += GET_NATI (sp [0]);
3963 CASE (CEE_ADD_OVF_UN)
3965 /* FIXME: check overflow, make unsigned */
3966 if (sp->type == VAL_I32) {
3967 if (sp [-1].type == VAL_I32) {
3968 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
3969 THROW_EX (mono_get_exception_overflow (), ip);
3970 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)sp [0].data.i;
3972 if (CHECK_ADD_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
3973 THROW_EX (mono_get_exception_overflow (), ip);
3974 sp [-1].data.nati = (mono_u)sp [-1].data.nati + (mono_u)sp [0].data.i;
3976 } else if (sp->type == VAL_I64) {
3977 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3978 THROW_EX (mono_get_exception_overflow (), ip);
3979 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3980 } else if (sp->type == VAL_DOUBLE)
3981 sp [-1].data.f += sp [0].data.f;
3983 char *p = sp [-1].data.p;
3984 p += GET_NATI (sp [0]);
3991 /* FIXME: check overflow */
3992 if (sp->type == VAL_I32) {
3993 if (sp [-1].type == VAL_NATI) {
3994 if (CHECK_MUL_OVERFLOW_NAT (sp [-1].data.nati, sp [0].data.i))
3995 THROW_EX (mono_get_exception_overflow (), ip);
3996 sp [-1].data.nati = sp [-1].data.nati * sp [0].data.i;
3997 sp [-1].type = VAL_NATI;
3999 if (CHECK_MUL_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4000 THROW_EX (mono_get_exception_overflow (), ip);
4001 sp [-1].data.i *= sp [0].data.i;
4004 else if (sp->type == VAL_I64) {
4005 if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4006 THROW_EX (mono_get_exception_overflow (), ip);
4007 sp [-1].data.l *= sp [0].data.l;
4009 else if (sp->type == VAL_DOUBLE)
4010 sp [-1].data.f *= sp [0].data.f;
4015 CASE (CEE_MUL_OVF_UN)
4017 /* FIXME: check overflow, make unsigned */
4018 if (sp->type == VAL_I32) {
4019 if (sp [-1].type == VAL_NATI) {
4020 if (CHECK_MUL_OVERFLOW_NAT_UN (sp [-1].data.nati, (mono_u)sp [0].data.i))
4021 THROW_EX (mono_get_exception_overflow (), ip);
4022 sp [-1].data.nati = (mono_u)sp [-1].data.nati * (mono_u)sp [0].data.i;
4023 sp [-1].type = VAL_NATI;
4025 if (CHECK_MUL_OVERFLOW_UN ((guint32)sp [-1].data.i, (guint32)sp [0].data.i))
4026 THROW_EX (mono_get_exception_overflow (), ip);
4027 sp [-1].data.i *= sp [0].data.i;
4030 else if (sp->type == VAL_I64) {
4031 if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4032 THROW_EX (mono_get_exception_overflow (), ip);
4033 sp [-1].data.l *= sp [0].data.l;
4035 else if (sp->type == VAL_DOUBLE)
4036 sp [-1].data.f *= sp [0].data.f;
4043 /* FIXME: handle undeflow/unsigned */
4044 /* should probably consider the pointers as unsigned */
4045 if (sp->type == VAL_I32) {
4046 if (sp [-1].type == VAL_I32) {
4047 if (CHECK_SUB_OVERFLOW (sp [-1].data.i, sp [0].data.i))
4048 THROW_EX (mono_get_exception_overflow (), ip);
4049 sp [-1].data.i -= sp [0].data.i;
4051 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4052 sp [-1].type = VAL_NATI;
4055 else if (sp->type == VAL_I64) {
4056 if (CHECK_SUB_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
4057 THROW_EX (mono_get_exception_overflow (), ip);
4058 sp [-1].data.l -= sp [0].data.l;
4060 else if (sp->type == VAL_DOUBLE)
4061 sp [-1].data.f -= sp [0].data.f;
4063 if (sp [-1].type == VAL_I32) {
4064 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4065 sp [-1].type = sp [0].type;
4067 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4071 CASE (CEE_SUB_OVF_UN)
4073 /* FIXME: handle undeflow/unsigned */
4074 /* should probably consider the pointers as unsigned */
4075 if (sp->type == VAL_I32) {
4076 if (sp [-1].type == VAL_I32) {
4077 if (CHECK_SUB_OVERFLOW_UN (sp [-1].data.i, sp [0].data.i))
4078 THROW_EX (mono_get_exception_overflow (), ip);
4079 sp [-1].data.i -= sp [0].data.i;
4081 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.i;
4082 sp [-1].type = VAL_NATI;
4085 else if (sp->type == VAL_I64) {
4086 if (CHECK_SUB_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
4087 THROW_EX (mono_get_exception_overflow (), ip);
4088 sp [-1].data.l -= sp [0].data.l;
4090 else if (sp->type == VAL_DOUBLE)
4091 sp [-1].data.f -= sp [0].data.f;
4093 if (sp [-1].type == VAL_I32) {
4094 sp [-1].data.nati = sp [-1].data.i - sp [0].data.nati;
4095 sp [-1].type = sp [0].type;
4097 sp [-1].data.nati = sp [-1].data.nati - sp [0].data.nati;
4101 CASE (CEE_ENDFINALLY)
4103 ip = finally_ips->data;
4104 finally_ips = g_slist_remove (finally_ips, ip);
4111 CASE (CEE_LEAVE) /* Fall through */
4113 while (sp > frame->stack) {
4118 if (*ip == CEE_LEAVE_S) {
4120 ip += (signed char) *ip;
4124 ip += (gint32) read32 (ip);
4128 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - header->code)) {
4129 frame->ex_handler = NULL;
4132 goto handle_finally;
4137 case CEE_MONO_FUNC1: {
4138 MonoMarshalConv conv;
4147 sp->type = VAL_NATI;
4150 case MONO_MARSHAL_CONV_STR_LPWSTR:
4151 sp->data.p = mono_string_to_utf16 (sp->data.p);
4153 case MONO_MARSHAL_CONV_LPSTR_STR:
4154 sp->data.p = mono_string_new_wrapper (sp->data.p);
4156 case MONO_MARSHAL_CONV_STR_LPTSTR:
4157 case MONO_MARSHAL_CONV_STR_LPSTR:
4158 sp->data.p = mono_string_to_utf8 (sp->data.p);
4160 case MONO_MARSHAL_CONV_STR_BSTR:
4161 sp->data.p = mono_string_to_bstr (sp->data.p);
4163 case MONO_MARSHAL_CONV_STR_TBSTR:
4164 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4165 sp->data.p = mono_string_to_ansibstr (sp->data.p);
4167 case MONO_MARSHAL_CONV_SB_LPSTR:
4168 case MONO_MARSHAL_CONV_SB_LPTSTR:
4169 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
4171 case MONO_MARSHAL_CONV_SB_LPWSTR:
4172 sp->data.p = mono_string_builder_to_utf16 (sp->data.p);
4174 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4175 sp->data.p = mono_array_to_savearray (sp->data.p);
4177 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4178 sp->data.p = mono_array_to_lparray (sp->data.p);
4180 case MONO_MARSHAL_CONV_DEL_FTN:
4181 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
4183 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4184 sp->data.p = mono_marshal_string_array (sp->data.p);
4186 case MONO_MARSHAL_CONV_STRARRAY_STRWLPARRAY:
4187 sp->data.p = mono_marshal_string_array_to_unicode (sp->data.p);
4189 case MONO_MARSHAL_CONV_LPWSTR_STR:
4190 sp->data.p = mono_string_from_utf16 (sp->data.p);
4193 fprintf(stderr, "MONO_FUNC1 %d", conv);
4194 g_assert_not_reached ();
4199 case CEE_MONO_PROC2: {
4200 MonoMarshalConv conv;
4208 case MONO_MARSHAL_CONV_LPSTR_SB:
4209 case MONO_MARSHAL_CONV_LPTSTR_SB:
4210 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
4212 case MONO_MARSHAL_CONV_LPWSTR_SB:
4213 mono_string_utf16_to_builder (sp [0].data.p, sp [1].data.p);
4215 case MONO_MARSHAL_FREE_ARRAY:
4216 mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
4219 g_assert_not_reached ();
4223 case CEE_MONO_PROC3: {
4224 MonoMarshalConv conv;
4232 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4233 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4235 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4236 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4239 g_assert_not_reached ();
4243 case CEE_MONO_VTADDR: {
4246 sp [-1].type = VAL_MP;
4250 case CEE_MONO_LDPTR: {
4254 token = read32 (ip);
4257 sp->type = VAL_NATI;
4258 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
4262 case CEE_MONO_FREE: {
4266 g_free (sp->data.p);
4269 case CEE_MONO_OBJADDR: {
4276 case CEE_MONO_NEWOBJ: {
4281 token = read32 (ip);
4284 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4285 sp->data.p = mono_object_new (domain, class);
4289 case CEE_MONO_RETOBJ: {
4294 token = read32 (ip);
4299 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4301 stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);
4303 if (sp > frame->stack)
4304 g_warning ("more values on stack: %d", sp-frame->stack);
4307 case CEE_MONO_LDNATIVEOBJ: {
4312 token = read32 (ip);
4315 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
4316 g_assert(class->valuetype);
4318 sp [-1].type = VAL_MP;
4323 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
4354 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
4356 * Note: Exceptions thrown when executing a prefixed opcode need
4357 * to take into account the number of prefix bytes (usually the
4358 * throw point is just (ip - n_prefix_bytes).
4363 case CEE_ARGLIST: ves_abort(); break;
4369 if (sp->type == VAL_I32)
4370 result = (mono_i)sp [0].data.i == (mono_i)GET_NATI (sp [1]);
4371 else if (sp->type == VAL_I64)
4372 result = sp [0].data.l == sp [1].data.l;
4373 else if (sp->type == VAL_DOUBLE) {
4374 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4377 result = sp [0].data.f == sp [1].data.f;
4379 result = sp [0].data.nati == GET_NATI (sp [1]);
4381 sp->data.i = result;
4391 if (sp->type == VAL_I32)
4392 result = (mono_i)sp [0].data.i > (mono_i)GET_NATI (sp [1]);
4393 else if (sp->type == VAL_I64)
4394 result = sp [0].data.l > sp [1].data.l;
4395 else if (sp->type == VAL_DOUBLE) {
4396 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4399 result = sp [0].data.f > sp [1].data.f;
4401 result = (mono_i)sp [0].data.nati > (mono_i)GET_NATI (sp [1]);
4403 sp->data.i = result;
4413 if (sp->type == VAL_I32)
4414 result = (mono_u)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
4415 else if (sp->type == VAL_I64)
4416 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
4417 else if (sp->type == VAL_DOUBLE)
4418 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4419 sp[0].data.f > sp[1].data.f;
4421 result = (mono_u)sp [0].data.nati > (mono_u)GET_NATI (sp [1]);
4423 sp->data.i = result;
4433 if (sp->type == VAL_I32)
4434 result = (mono_i)sp [0].data.i < (mono_i)GET_NATI (sp [1]);
4435 else if (sp->type == VAL_I64)
4436 result = sp [0].data.l < sp [1].data.l;
4437 else if (sp->type == VAL_DOUBLE) {
4438 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
4441 result = sp [0].data.f < sp [1].data.f;
4443 result = (mono_i)sp [0].data.nati < (mono_i)GET_NATI (sp [1]);
4445 sp->data.i = result;
4455 if (sp->type == VAL_I32)
4456 result = (mono_u)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
4457 else if (sp->type == VAL_I64)
4458 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
4459 else if (sp->type == VAL_DOUBLE)
4460 result = isnan (sp [0].data.f) || isnan (sp [1].data.f) ||
4461 sp[0].data.f < sp[1].data.f;
4463 result = (mono_u)sp [0].data.nati < (mono_u)GET_NATI (sp [1]);
4465 sp->data.i = result;
4471 case CEE_LDVIRTFTN: {
4472 int virtual = *ip == CEE_LDVIRTFTN;
4476 token = read32 (ip);
4479 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
4480 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
4482 m = mono_get_method_full (image, token, NULL, generic_context);
4485 THROW_EX (mono_get_exception_missing_method (), ip - 5);
4489 THROW_EX (mono_get_exception_null_reference (), ip - 5);
4491 m = get_virtual_method (domain, m, sp);
4495 * This prevents infinite cycles since the wrapper contains
4498 if (frame->method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
4499 if (m && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4500 m = mono_marshal_get_synchronized_wrapper (m);
4502 sp->type = VAL_NATI;
4503 sp->data.p = mono_create_method_pointer (m);
4507 case CEE_UNUSED56: ves_abort(); break;
4511 arg_pos = read16 (ip);
4513 vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
4514 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4523 sp->data.vt = ARG_POS (anum);
4531 arg_pos = read16 (ip);
4534 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
4541 loc_pos = read16 (ip);
4543 vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
4544 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4553 loc_pos = read16 (ip);
4555 t = LOCAL_TYPE (header, loc_pos);
4556 sp->data.vt = LOCAL_POS (loc_pos);
4566 loc_pos = read16 (ip);
4569 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
4575 if (sp != frame->stack)
4576 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4578 sp->data.p = alloca (sp->data.i);
4582 case CEE_UNUSED57: ves_abort(); break;
4583 case CEE_ENDFILTER: ves_abort(); break;
4584 case CEE_UNALIGNED_:
4586 unaligned_address = 1;
4590 volatile_address = 1;
4601 token = read32 (ip);
4604 class = mono_class_get_full (image, token, generic_context);
4607 g_assert (sp->type == VAL_TP || sp->type == VAL_MP);
4608 memset (sp->data.vt, 0, mono_class_value_size (class, NULL));
4611 case CEE_CONSTRAINED_: {
4613 /* FIXME: implement */
4615 token = read32 (ip);
4621 if (!sp [0].data.p || !sp [1].data.p)
4622 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4624 /* FIXME: value and size may be int64... */
4625 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4630 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4632 /* FIXME: value and size may be int64... */
4633 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4636 /* FIXME: implement */
4641 * need to clarify what this should actually do:
4642 * start the search from the last found handler in
4643 * this method or continue in the caller or what.
4644 * Also, do we need to run finally/fault handlers after a retrow?
4645 * Well, this implementation will follow the usual search
4646 * for an handler, considering the current ip as throw spot.
4647 * We need to NULL frame->ex_handler for the later code to
4648 * actually run the new found handler.
4650 frame->ex_handler = NULL;
4651 THROW_EX (frame->ex, ip - 1);
4653 case CEE_UNUSED: ves_abort(); break;
4658 token = read32 (ip);
4660 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4661 MonoType *type = mono_type_create_from_typespec (image, token);
4662 sp->data.i = mono_type_size (type, &align);
4664 MonoClass *szclass = mono_class_get_full (image, token, generic_context);
4665 mono_class_init (szclass);
4666 if (!szclass->valuetype)
4667 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4668 sp->data.i = mono_class_value_size (szclass, &align);
4674 case CEE_REFANYTYPE: ves_abort(); break;
4676 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4683 g_assert_not_reached ();
4685 * Exception handling code.
4686 * The exception object is stored in frame->ex.
4693 MonoInvocation *inv;
4694 MonoMethodHeader *hd;
4695 MonoExceptionClause *clause;
4701 g_print ("* Handling exception '%s' at IL_%04x\n", frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, frame->ip - header->code);
4703 if (die_on_exception)
4706 if (frame->ex == quit_exception)
4707 goto handle_finally;
4709 for (inv = frame; inv; inv = inv->parent) {
4710 if (inv->method == NULL)
4712 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4714 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4716 hd = ((MonoMethodNormal*)inv->method)->header;
4717 ip_offset = inv->ip - hd->code;
4718 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4719 for (i = 0; i < hd->num_clauses; ++i) {
4720 clause = &hd->clauses [i];
4721 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4722 if (!clause->flags) {
4723 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4725 * OK, we found an handler, now we need to execute the finally
4726 * and fault blocks before branching to the handler code.
4728 inv->ex_handler = clause;
4731 g_print ("* Found handler at '%s'\n", inv->method->name);
4733 goto handle_finally;
4736 /* FIXME: handle filter clauses */
4743 * If we get here, no handler was found: print a stack trace.
4745 for (inv = frame; inv; inv = inv->parent) {
4746 if (inv->invoke_trap)
4747 goto handle_finally;
4750 ex_obj = (MonoObject*)frame->ex;
4751 mono_unhandled_exception (ex_obj);
4758 MonoExceptionClause *clause;
4759 GSList *old_list = finally_ips;
4763 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - header->code);
4765 if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4766 || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4769 ip_offset = frame->ip - header->code;
4771 if (endfinally_ip != NULL)
4772 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4773 for (i = 0; i < header->num_clauses; ++i)
4774 if (frame->ex_handler == &header->clauses [i])
4778 clause = &header->clauses [i];
4779 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code)))) {
4780 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4781 ip = header->code + clause->handler_offset;
4782 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4785 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4791 endfinally_ip = NULL;
4793 if (old_list != finally_ips && finally_ips) {
4794 ip = finally_ips->data;
4795 finally_ips = g_slist_remove (finally_ips, ip);
4796 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4801 * If an exception is set, we need to execute the fault handler, too,
4802 * otherwise, we continue normally.
4812 MonoExceptionClause *clause;
4816 g_print ("* Handle fault\n");
4818 ip_offset = frame->ip - header->code;
4819 for (i = 0; i < header->num_clauses; ++i) {
4820 clause = &header->clauses [i];
4821 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4822 ip = header->code + clause->handler_offset;
4825 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4831 * If the handler for the exception was found in this method, we jump
4832 * to it right away, otherwise we return and let the caller run
4833 * the finally, fault and catch blocks.
4834 * This same code should be present in the endfault opcode, but it
4835 * is corrently not assigned in the ECMA specs: LAMESPEC.
4837 if (frame->ex_handler) {
4840 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4842 ip = header->code + frame->ex_handler->handler_offset;
4845 sp->data.p = frame->ex;
4856 ves_exec_method (MonoInvocation *frame)
4858 ThreadContext *context = TlsGetValue (thread_context_id);
4859 ThreadContext context_struct;
4860 if (context == NULL) {
4861 context = &context_struct;
4862 context_struct.base_frame = frame;
4863 context_struct.current_frame = NULL;
4864 context_struct.current_env = NULL;
4865 context_struct.search_for_handler = 0;
4866 TlsSetValue (thread_context_id, context);
4869 frame->parent = context->current_frame;
4870 ves_exec_method_with_context(frame, context);
4872 if (context->current_env) {
4873 context->env_frame->ex = frame->ex;
4874 longjmp (*context->current_env, 1);
4877 mono_unhandled_exception ((MonoObject*)frame->ex);
4879 if (context->base_frame == frame)
4880 TlsSetValue (thread_context_id, NULL);
4882 context->current_frame = frame->parent;
4886 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4888 MonoImage *image = assembly->image;
4889 MonoCLIImageInfo *iinfo;
4891 MonoObject *exc = NULL;
4894 iinfo = image->image_info;
4895 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4897 g_error ("No entry point method found in %s", image->name);
4899 rval = mono_runtime_run_main (method, argc, argv, &exc);
4901 mono_unhandled_exception (exc);
4910 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4911 "Usage is: mint [options] executable args...\n\n", VERSION);
4913 "Runtime Debugging:\n"
4918 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4921 " --traceclassinit\n"
4924 " --debug method_name\n"
4930 " --config filename load the specified config file instead of the default\n"
4931 " --workers n maximum number of worker threads\n"
4938 test_load_class (MonoImage* image)
4940 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4944 for (i = 1; i <= t->rows; ++i) {
4945 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4946 mono_class_init (klass);
4951 static MonoException * segv_exception = NULL;
4954 segv_handler (int signum)
4956 signal (signum, segv_handler);
4957 mono_raise_exception (segv_exception);
4962 quit_handler (int signum)
4964 signal (signum, quit_handler);
4965 mono_raise_exception (quit_exception);
4969 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4970 MonoReflectionMethod **method,
4971 gint32 *iloffset, gint32 *native_offset,
4972 MonoString **file, gint32 *line, gint32 *column)
4985 *file = mono_string_new (mono_domain_get (), "unknown");
4991 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4999 int enable_debugging;
5005 static void main_thread_handler (gpointer user_data)
5007 MainThreadArgs *main_args=(MainThreadArgs *)user_data;
5008 MonoAssembly *assembly;
5010 if (main_args->enable_debugging)
5011 mono_debug_init (main_args->domain, MONO_DEBUG_FORMAT_MONO);
5013 assembly = mono_domain_assembly_open (main_args->domain,
5017 fprintf (stderr, "Can not open image %s\n", main_args->file);
5021 if (main_args->enable_debugging)
5022 mono_debug_init_2 (assembly);
5025 test_load_class (assembly->image);
5027 segv_exception = mono_get_exception_null_reference ();
5028 segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
5029 signal (SIGSEGV, segv_handler);
5030 /* perhaps we should use a different class for this exception... */
5031 quit_exception = mono_get_exception_null_reference ();
5032 quit_exception->message = mono_string_new (main_args->domain, "Quit");
5033 signal (SIGINT, quit_handler);
5035 ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
5040 mono_runtime_install_handlers (void)
5042 /* FIXME: anything to do here? */
5046 quit_function (MonoDomain *domain, gpointer user_data)
5048 mono_profiler_shutdown ();
5050 mono_runtime_cleanup (domain);
5051 mono_domain_free (domain, TRUE);
5056 mono_interp_cleanup(MonoDomain *domain)
5058 quit_function (domain, NULL);
5062 mono_interp_exec(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
5064 return ves_exec (domain, assembly, argc, argv);
5068 mono_interp_init(const char *file)
5072 g_set_prgname (file);
5073 mono_set_rootdir ();
5075 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
5076 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
5078 g_thread_init (NULL);
5080 thread_context_id = TlsAlloc ();
5081 TlsSetValue (thread_context_id, NULL);
5082 InitializeCriticalSection(&calc_section);
5083 InitializeCriticalSection(&create_method_pointer_mutex);
5085 mono_install_compile_method (mono_create_method_pointer);
5086 mono_install_runtime_invoke (interp_mono_runtime_invoke);
5087 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
5089 mono_install_handler (interp_ex_handler);
5090 mono_install_stack_walk (interp_walk_stack);
5091 mono_runtime_install_cleanup (quit_function);
5093 domain = mono_init (file);
5094 #ifdef __hpux /* generates very big stack frames */
5095 mono_threads_set_default_stacksize(32*1024*1024);
5098 mono_threads_set_default_stacksize(8*1024*1024);
5101 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
5102 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
5103 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
5105 mono_runtime_init (domain, NULL, NULL);
5111 mono_main (int argc, char *argv [])
5114 int retval = 0, i, ocount = 0;
5115 char *file, *config_file = NULL;
5116 int enable_debugging = FALSE;
5117 MainThreadArgs main_args;
5120 setlocale (LC_ALL, "");
5124 for (i = 1; i < argc && argv [i][0] == '-'; i++){
5125 if (strcmp (argv [i], "--trace") == 0)
5127 if (strcmp (argv [i], "--noptr") == 0)
5128 global_no_pointers = 1;
5129 if (strcmp (argv [i], "--traceops") == 0)
5131 if (strcmp (argv [i], "--dieonex") == 0) {
5132 die_on_exception = 1;
5133 enable_debugging = 1;
5135 if (strcmp (argv [i], "--print-vtable") == 0)
5136 mono_print_vtable = TRUE;
5137 if (strcmp (argv [i], "--profile") == 0)
5138 mono_profiler_load (NULL);
5139 if (strcmp (argv [i], "--opcode-count") == 0)
5141 if (strcmp (argv [i], "--config") == 0)
5142 config_file = argv [++i];
5143 if (strcmp (argv [i], "--workers") == 0) {
5144 mono_max_worker_threads = atoi (argv [++i]);
5145 if (mono_max_worker_threads < 1)
5146 mono_max_worker_threads = 1;
5148 if (strcmp (argv [i], "--help") == 0)
5151 if (strcmp (argv [i], "--debug") == 0) {
5152 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
5154 g_error ("Invalid method name '%s'", argv [i]);
5155 db_methods = g_list_append (db_methods, desc);
5165 domain = mono_interp_init(file);
5166 mono_config_parse (config_file);
5168 error = mono_check_corlib_version ();
5170 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
5171 fprintf (stderr, "Download a newer corlib at http://www.go-mono.com/daily.\n");
5175 main_args.domain=domain;
5176 main_args.file=file;
5177 main_args.argc=argc-i;
5178 main_args.argv=argv+i;
5179 main_args.enable_debugging=enable_debugging;
5181 mono_runtime_exec_managed_code (domain, main_thread_handler,
5184 quit_function (domain, NULL);
5186 /* Get the return value from System.Environment.ExitCode */
5187 retval=mono_environment_exitcode_get ();
5191 fprintf (stderr, "opcode count: %ld\n", opcode_count);
5192 fprintf (stderr, "fcall count: %ld\n", fcall_count);