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.
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/os/util.h>
61 /*#include <mono/cli/types.h>*/
67 #define finite _finite
70 /* If true, then we output the opcodes as we interpret them */
71 static int global_tracing = 0;
72 static int global_no_pointers = 0;
74 static int debug_indent_level = 0;
77 * Pull the list of opcodes
79 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
83 #include "mono/cil/opcode.def"
88 #define GET_NATI(sp) ((sp).data.nati)
89 #define CSIZE(x) (sizeof (x) / 4)
91 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
93 (frame)->parent = (parent_frame); \
94 (frame)->obj = (obj_this); \
95 (frame)->stack_args = (method_args); \
96 (frame)->retval = (method_retval); \
97 (frame)->method = (mono_method); \
98 (frame)->ex_handler = NULL; \
100 (frame)->child = NULL; \
103 void ves_exec_method (MonoInvocation *frame);
105 typedef void (*ICallMethod) (MonoInvocation *frame);
107 static guint32 die_on_exception = 0;
108 static guint32 frame_thread_id = 0;
110 #define DEBUG_INTERP 1
113 static unsigned long opcode_count = 0;
114 static unsigned long fcall_count = 0;
115 static int break_on_method = 0;
116 static GList *db_methods = NULL;
123 for (h = 0; h < debug_indent_level; h++)
128 db_match_method (gpointer data, gpointer user_data)
130 MonoMethod *m = (MonoMethod*)user_data;
131 MonoMethodDesc *desc = data;
133 if (mono_method_desc_full_match (desc, m))
137 #define DEBUG_ENTER() \
139 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
140 if (break_on_method) tracing=2; \
141 break_on_method = 0; \
143 MonoClass *klass = frame->method->klass; \
144 char *mn, *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
145 debug_indent_level++; \
147 mn = mono_method_full_name (frame->method, FALSE); \
148 g_print ("(%d) Entering %s (", GetCurrentThreadId(), mn); \
150 if (signature->hasthis) { \
151 if (global_no_pointers) { \
152 g_print ("this%s ", frame->obj ? "" : "=null"); \
154 g_print ("%p ", frame->obj); } \
156 g_print ("%s)\n", args); \
159 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
160 mono_profiler_method_enter (frame->method);
162 #define DEBUG_LEAVE() \
164 MonoClass *klass = frame->method->klass; \
166 if (signature->ret->type != MONO_TYPE_VOID) \
167 args = dump_stack (frame->retval, frame->retval + 1); \
169 args = g_strdup (""); \
171 mn = mono_method_full_name (frame->method, FALSE); \
172 g_print ("(%d) Leaving %s", GetCurrentThreadId(), mn); \
174 g_print (" => %s\n", args); \
176 debug_indent_level--; \
178 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
179 mono_profiler_method_leave (frame->method);
183 #define DEBUG_ENTER()
184 #define DEBUG_LEAVE()
189 interp_ex_handler (MonoException *ex) {
190 MonoInvocation *frame = TlsGetValue (frame_thread_id);
192 longjmp (*(jmp_buf*)frame->locals, 1);
196 ves_real_abort (int line, MonoMethod *mh,
197 const unsigned char *ip, stackval *stack, stackval *sp)
199 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
200 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
201 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
202 ip-mm->header->code);
203 g_print ("0x%04x %02x\n",
204 ip-mm->header->code, *ip);
206 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
208 #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);
210 static MonoMethodMessage *
211 arch_method_call_message_new (MonoMethod *method, void *obj, stackval *args, MonoMethod *invoke,
212 MonoDelegate **cb, MonoObject **state)
214 MonoDomain *domain = mono_domain_get ();
215 MonoMethodSignature *sig = method->signature;
216 MonoMethodMessage *msg;
217 int i, count, type, size, align;
218 /*char *cpos = stack;*/
220 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
223 mono_message_init (domain, msg, mono_method_get_object (domain, invoke), NULL);
224 count = sig->param_count - 2;
226 mono_message_init (domain, msg, mono_method_get_object (domain, method), NULL);
227 count = sig->param_count;
230 for (i = 0; i < count; i++) {
235 size = mono_type_stack_size (sig->params [i], &align);
237 /* FIXME: endian issues */
238 if (sig->params [i]->byref)
239 vpos = *((gpointer *)args [i].data.p);
241 vpos = &args [i].data;
243 type = sig->params [i]->type;
244 class = mono_class_from_mono_type (sig->params [i]);
246 if (class->valuetype)
247 arg = mono_value_box (domain, class, vpos);
249 arg = args [i].data.p;
251 mono_array_set (msg->args, gpointer, i, arg);
255 /* the last two arguments of begininvoke */
256 *cb = args [count].data.p;
257 *state = args [count + 1].data.p;
263 interp_create_remoting_trampoline (MonoMethod *method)
269 invoke_remoting_trampoline (MonoInvocation *frame) {
270 MonoMethodMessage *msg;
271 MonoTransparentProxy *this;
272 MonoObject *res, *exc;
276 msg = arch_method_call_message_new (frame->method, frame->obj, frame->stack_args, NULL, NULL, NULL);
278 res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
281 mono_raise_exception ((MonoException *)exc);
283 /*arch_method_return_message_restore (method, &first_arg, res, out_args);*/
287 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
293 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
297 klass = obj->vtable->klass;
298 vtable = (MonoMethod **)obj->vtable->vtable;
300 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
301 return *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
304 g_assert (vtable [m->slot]);
306 return vtable [m->slot];
310 stackval_from_data (MonoType *type, stackval *result, char *data)
313 switch (type->type) {
314 case MONO_TYPE_OBJECT:
315 case MONO_TYPE_CLASS:
316 case MONO_TYPE_STRING:
317 case MONO_TYPE_ARRAY:
318 case MONO_TYPE_SZARRAY:
319 result->type = VAL_OBJ;
322 result->type = VAL_VALUETA;
325 result->data.p = *(gpointer*)data;
326 result->data.vt.klass = mono_class_from_mono_type (type);
329 switch (type->type) {
333 result->type = VAL_I32;
334 result->data.i = *(gint8*)data;
337 case MONO_TYPE_BOOLEAN:
338 result->type = VAL_I32;
339 result->data.i = *(guint8*)data;
342 result->type = VAL_I32;
343 result->data.i = *(gint16*)data;
347 result->type = VAL_I32;
348 result->data.i = *(guint16*)data;
351 result->type = VAL_I32;
352 result->data.i = *(gint32*)data;
357 result->type = VAL_TP;
358 result->data.p = *(gpointer*)data;
361 result->type = VAL_I32;
362 result->data.i = *(guint32*)data;
365 result->type = VAL_DOUBLE;
366 result->data.f = *(float*)data;
370 result->type = VAL_I64;
371 result->data.l = *(gint64*)data;
374 result->type = VAL_DOUBLE;
375 result->data.f = *(double*)data;
377 case MONO_TYPE_STRING:
378 case MONO_TYPE_SZARRAY:
379 case MONO_TYPE_CLASS:
380 case MONO_TYPE_OBJECT:
381 case MONO_TYPE_ARRAY:
382 result->type = VAL_OBJ;
383 result->data.p = *(gpointer*)data;
384 result->data.vt.klass = mono_class_from_mono_type (type);
386 case MONO_TYPE_VALUETYPE:
387 if (type->data.klass->enumtype) {
388 return stackval_from_data (type->data.klass->enum_basetype, result, data);
390 result->type = VAL_VALUET;
391 result->data.vt.klass = type->data.klass;
394 int i, size = mono_class_value_size (type->data.klass, NULL);
395 for (i = 0; i < size; i++)
396 printf ("VT %s %d %02x\n", type->data.klass->name, i, ((guint8 *)data) [i]);
397 memcpy (result->data.vt.vt, data, size);
400 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
404 g_warning ("got type 0x%02x", type->type);
405 g_assert_not_reached ();
410 stackval_to_data (MonoType *type, stackval *val, char *data)
413 gpointer *p = (gpointer*)data;
417 switch (type->type) {
420 guint8 *p = (guint8*)data;
424 case MONO_TYPE_BOOLEAN: {
425 guint8 *p = (guint8*)data;
426 *p = (val->data.i != 0);
431 case MONO_TYPE_CHAR: {
432 guint16 *p = (guint16*)data;
436 #if SIZEOF_VOID_P == 4
442 gint32 *p = (gint32*)data;
446 #if SIZEOF_VOID_P == 8
452 gint64 *p = (gint64*)data;
457 float *p = (float*)data;
462 double *p = (double*)data;
466 case MONO_TYPE_STRING:
467 case MONO_TYPE_SZARRAY:
468 case MONO_TYPE_CLASS:
469 case MONO_TYPE_OBJECT:
470 case MONO_TYPE_ARRAY:
471 case MONO_TYPE_PTR: {
472 gpointer *p = (gpointer*)data;
476 case MONO_TYPE_VALUETYPE:
477 if (type->data.klass->enumtype) {
478 return stackval_to_data (type->data.klass->enum_basetype, val, data);
480 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
484 g_warning ("got type %x", type->type);
485 g_assert_not_reached ();
490 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
493 guint32 *lower_bounds;
496 lengths = alloca (sizeof (guint32) * klass->rank * 2);
497 for (i = 0; i < sig->param_count; ++i) {
498 lengths [i] = values->data.i;
501 if (klass->rank == sig->param_count) {
502 /* Only lengths provided. */
505 /* lower bounds are first. */
506 lower_bounds = lengths;
507 lengths += klass->rank;
509 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
513 ves_array_set (MonoInvocation *frame)
515 stackval *sp = frame->stack_args;
519 gint32 i, t, pos, esize;
525 ac = o->vtable->klass;
527 g_assert (ac->rank >= 1);
530 if (ao->bounds != NULL) {
531 pos -= ao->bounds [0].lower_bound;
532 for (i = 1; i < ac->rank; i++) {
533 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
534 ao->bounds [i].length) {
535 g_warning ("wrong array index");
536 g_assert_not_reached ();
538 pos = pos*ao->bounds [i].length + sp [i].data.i -
539 ao->bounds [i].lower_bound;
543 esize = mono_array_element_size (ac);
544 ea = mono_array_addr_with_size (ao, esize, pos);
546 mt = frame->method->signature->params [ac->rank];
547 stackval_to_data (mt, &sp [ac->rank], ea);
551 ves_array_get (MonoInvocation *frame)
553 stackval *sp = frame->stack_args;
557 gint32 i, pos, esize;
563 ac = o->vtable->klass;
565 g_assert (ac->rank >= 1);
568 if (ao->bounds != NULL) {
569 pos -= ao->bounds [0].lower_bound;
570 for (i = 1; i < ac->rank; i++)
571 pos = pos*ao->bounds [i].length + sp [i].data.i -
572 ao->bounds [i].lower_bound;
575 esize = mono_array_element_size (ac);
576 ea = mono_array_addr_with_size (ao, esize, pos);
578 mt = frame->method->signature->ret;
579 stackval_from_data (mt, frame->retval, ea);
583 ves_array_element_address (MonoInvocation *frame)
585 stackval *sp = frame->stack_args;
589 gint32 i, pos, esize;
594 ac = o->vtable->klass;
596 g_assert (ac->rank >= 1);
599 if (ao->bounds != NULL) {
600 pos -= ao->bounds [0].lower_bound;
601 for (i = 1; i < ac->rank; i++)
602 pos = pos*ao->bounds [i].length + sp [i].data.i -
603 ao->bounds [i].lower_bound;
606 esize = mono_array_element_size (ac);
607 ea = mono_array_addr_with_size (ao, esize, pos);
609 frame->retval->type = VAL_TP;
610 frame->retval->data.p = ea;
613 /* This is the implementation of the ldftn opcode
614 * used to implement CreateDelegate
617 ves_delegate_createdelegate (MonoReflectionMethod *info)
619 return mono_create_method_pointer (info->method);
623 interp_walk_stack (MonoStackWalk func, gpointer user_data)
625 MonoInvocation *frame = TlsGetValue (frame_thread_id);
627 MonoMethodHeader *hd;
630 if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
631 (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
634 hd = ((MonoMethodNormal*)frame->method)->header;
635 il_offset = frame->ip - hd->code;
637 if (func (frame->method, -1, il_offset, user_data))
639 frame = frame->parent;
644 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor)
650 TlsSetValue (frame_thread_id, frame->args);
655 if (!frame->method->info) {
656 func = frame->method->info = mono_create_trampoline (sig, string_ctor);
658 func = (MonoPIFunc)frame->method->info;
661 func = mono_create_trampoline (sig, string_ctor);
665 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
666 * locals will point to the jmp_buf, while args will point to the previous
667 * MonoInvocation frame: this is needed to make exception searching work across
668 * managed/unmanaged boundaries.
670 frame->locals = (char*)&env;
671 frame->args = (char*)TlsGetValue (frame_thread_id);
672 TlsSetValue (frame_thread_id, frame);
674 func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
677 stackval_from_data (&mono_defaults.string_class->byval_arg,
678 frame->retval, (char*)&frame->retval->data.p);
680 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p);
682 TlsSetValue (frame_thread_id, frame->args);
687 * runtime specifies that the implementation of the method is automatically
688 * provided by the runtime and is primarily used for the methods of delegates.
691 ves_runtime_method (MonoInvocation *frame)
693 const char *name = frame->method->name;
694 MonoObject *obj = (MonoObject*)frame->obj;
695 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
700 mono_class_init (frame->method->klass);
702 if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
703 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
704 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
707 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
714 code = (guchar*)delegate->delegate.method_ptr;
715 if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
717 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
718 ves_exec_method (&call);
720 g_assert_not_reached ();
723 delegate = delegate->prev;
727 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
728 nm = mono_marshal_get_delegate_begin_invoke (frame->method);
729 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
730 ves_exec_method (&call);
733 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
734 nm = mono_marshal_get_delegate_end_invoke (frame->method);
735 INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
736 ves_exec_method (&call);
741 if (obj && mono_object_isinst (obj, mono_defaults.array_class)) {
742 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
743 ves_array_set (frame);
746 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
747 ves_array_get (frame);
750 if (*name == 'A' && (strcmp (name, "Address") == 0)) {
751 ves_array_element_address (frame);
756 g_error ("Don't know how to exec runtime method %s.%s::%s",
757 frame->method->klass->name_space, frame->method->klass->name,
758 frame->method->name);
762 dump_stack (stackval *stack, stackval *sp)
765 GString *str = g_string_new ("");
768 return g_string_free (str, FALSE);
772 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
773 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
774 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
776 if (!global_no_pointers)
777 g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
779 g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
782 MonoObject *obj = s->data.p;
783 if (global_no_pointers && obj && obj->vtable) {
784 MonoClass *klass = mono_object_class (obj);
785 if (klass == mono_defaults.string_class) {
786 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
787 g_string_sprintfa (str, "[str:%s] ", utf8);
790 } else if (klass == mono_defaults.sbyte_class) {
791 g_string_sprintfa (str, "[b:%d] ",
792 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
794 } else if (klass == mono_defaults.int16_class) {
795 g_string_sprintfa (str, "[b:%d] ",
796 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
798 } else if (klass == mono_defaults.int32_class) {
799 g_string_sprintfa (str, "[b:%d] ",
800 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
802 } else if (klass == mono_defaults.byte_class) {
803 g_string_sprintfa (str, "[b:%u] ",
804 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
806 } else if (klass == mono_defaults.char_class
807 || klass == mono_defaults.uint16_class) {
808 g_string_sprintfa (str, "[b:%u] ",
809 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
811 } else if (klass == mono_defaults.uint32_class) {
812 g_string_sprintfa (str, "[b:%u] ",
813 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
815 } else if (klass == mono_defaults.int64_class) {
816 g_string_sprintfa (str, "[b:%lld] ",
817 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
819 } else if (klass == mono_defaults.uint64_class) {
820 g_string_sprintfa (str, "[b:%llu] ",
821 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
823 } else if (klass == mono_defaults.double_class) {
824 g_string_sprintfa (str, "[b:%0.5f] ",
825 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
827 } else if (klass == mono_defaults.single_class) {
828 g_string_sprintfa (str, "[b:%0.5f] ",
829 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
831 } else if (klass == mono_defaults.boolean_class) {
832 g_string_sprintfa (str, "[b:%s] ",
833 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
841 if (!global_no_pointers)
842 g_string_sprintfa (str, "[%p] ", s->data.p);
844 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
849 return g_string_free (str, FALSE);
853 dump_frame (MonoInvocation *inv)
855 GString *str = g_string_new ("");
858 for (i = 0; inv; inv = inv->parent, ++i) {
859 MonoClass *k = inv->method->klass;
862 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
863 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
867 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
869 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
872 opname = mono_opcode_names [codep];
873 codep = inv->ip - hd->code;
875 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
876 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
877 k->name_space, k->name, inv->method->name, args);
880 return g_string_free (str, FALSE);
883 static CRITICAL_SECTION metadata_lock;
886 INLINE_STRING_LENGTH = 1,
889 INLINE_TYPE_ELEMENT_TYPE
893 calc_offsets (MonoImage *image, MonoMethod *method)
895 int i, align, size, offset = 0;
896 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
897 MonoMethodSignature *signature = method->signature;
898 int hasthis = signature->hasthis;
899 register const unsigned char *ip, *end;
900 const MonoOpcode *opcode;
904 MonoDomain *domain = mono_domain_get ();
907 mono_profiler_method_jit (method); /* sort of... */
908 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
909 for (i = 0; i < header->num_locals; ++i) {
910 size = mono_type_size (header->locals [i], &align);
912 offset &= ~(align - 1);
913 offsets [2 + i] = offset;
916 offsets [0] = offset;
919 offset += sizeof (gpointer) - 1;
920 offset &= ~(sizeof (gpointer) - 1);
921 offsets [2 + header->num_locals] = offset;
922 offset += sizeof (gpointer);
924 for (i = 0; i < signature->param_count; ++i) {
925 size = mono_type_size (signature->params [i], &align);
927 offset &= ~(align - 1);
928 offsets [2 + hasthis + header->num_locals + i] = offset;
931 offsets [1] = offset;
933 EnterCriticalSection (&metadata_lock);
934 /* intern the strings in the method. */
936 end = ip + header->code_size;
943 opcode = &mono_opcodes [i];
944 switch (opcode->argument) {
948 case MonoInlineString:
949 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
953 if (method->wrapper_type == MONO_WRAPPER_NONE) {
954 class = mono_class_get (image, read32 (ip + 1));
955 mono_class_init (class);
956 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
957 mono_class_vtable (domain, class);
961 case MonoInlineField:
962 token = read32 (ip + 1);
963 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
964 mono_field_from_memberref (image, token, &class);
966 class = mono_class_get (image,
967 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
969 mono_class_init (class);
970 mono_class_vtable (domain, class);
973 case MonoInlineMethod:
974 if (method->wrapper_type == MONO_WRAPPER_NONE) {
975 m = mono_get_method (image, read32 (ip + 1), NULL);
976 mono_class_init (m->klass);
977 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
978 mono_class_vtable (domain, m->klass);
984 case MonoShortInlineR:
986 case MonoInlineBrTarget:
992 case MonoShortInlineVar:
993 case MonoShortInlineI:
994 case MonoShortInlineBrTarget:
997 case MonoInlineSwitch: {
1010 g_assert_not_reached ();
1014 method->info = offsets;
1017 * We store the inline info in addr, since it's unused for IL methods.
1019 if (method->klass == mono_defaults.string_class) {
1020 if (strcmp (method->name, "get_Length") == 0)
1021 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
1022 } else if (method->klass == mono_defaults.array_class) {
1023 if (strcmp (method->name, "get_Length") == 0)
1024 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
1025 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
1026 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
1027 } else if (method->klass == mono_defaults.monotype_class) {
1028 if (strcmp (method->name, "GetElementType") == 0)
1029 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
1031 LeaveCriticalSection (&metadata_lock);
1032 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1035 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
1036 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1038 #define ARG_POS(n) (args_pointers [(n)])
1039 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1040 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1042 #define THROW_EX(exception,ex_ip) \
1044 char *stack_trace; \
1045 frame->ip = (ex_ip); \
1046 stack_trace = dump_frame (frame); \
1047 frame->ex = (MonoException*)(exception); \
1048 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
1049 g_free (stack_trace); \
1050 goto handle_exception; \
1053 typedef struct _vtallocation vtallocation;
1055 struct _vtallocation {
1058 char data [MONO_ZERO_LEN_ARRAY];
1062 * we don't use vtallocation->next, yet
1064 #define vt_alloc(vtype,sp) \
1065 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1066 if (!(vtype)->byref) { \
1068 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
1069 if (!vtalloc || vtalloc->size <= size) { \
1070 vtalloc = alloca (sizeof (vtallocation) + size); \
1071 vtalloc->size = size; \
1072 g_assert (size < 10000); \
1074 (sp)->data.vt.vt = vtalloc->data; \
1077 (sp)->data.vt.klass = (vtype)->data.klass; \
1081 #define vt_free(sp) \
1083 if ((sp)->type == VAL_VALUET) { \
1084 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
1089 verify_method (MonoMethod *m)
1091 GSList *errors, *tmp;
1092 MonoVerifyInfo *info;
1094 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1096 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1097 for (tmp = errors; tmp; tmp = tmp->next) {
1099 g_print ("%s\n", info->message);
1103 mono_free_verify_list (errors);
1106 #define MYGUINT64_MAX 18446744073709551615UL
1107 #define MYGINT64_MAX 9223372036854775807LL
1108 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1110 #define MYGUINT32_MAX 4294967295U
1111 #define MYGINT32_MAX 2147483647
1112 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1114 #define CHECK_ADD_OVERFLOW(a,b) \
1115 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1116 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1118 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1119 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1121 #define CHECK_ADD_OVERFLOW64(a,b) \
1122 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1123 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1125 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1126 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1129 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1131 MonoInvocation frame;
1132 MonoObject *retval = NULL;
1133 MonoMethodSignature *sig = method->signature;
1134 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1135 int i, type, isobject = 0;
1138 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1140 /* FIXME: Set frame for execption handling. */
1142 switch (sig->ret->type) {
1143 case MONO_TYPE_VOID:
1145 case MONO_TYPE_STRING:
1146 case MONO_TYPE_OBJECT:
1147 case MONO_TYPE_CLASS:
1148 case MONO_TYPE_ARRAY:
1149 case MONO_TYPE_SZARRAY:
1152 case MONO_TYPE_VALUETYPE:
1153 retval = mono_object_new (mono_domain_get (), klass);
1154 ret = ((char*)retval) + sizeof (MonoObject);
1155 if (!sig->ret->data.klass->enumtype)
1156 result.data.vt.vt = ret;
1159 retval = mono_object_new (mono_domain_get (), klass);
1160 ret = ((char*)retval) + sizeof (MonoObject);
1164 for (i = 0; i < sig->param_count; ++i) {
1165 if (sig->params [i]->byref) {
1166 args [i].type = VAL_POINTER;
1167 args [i].data.p = params [i];
1170 type = sig->params [i]->type;
1175 case MONO_TYPE_BOOLEAN:
1176 args [i].type = VAL_I32;
1177 args [i].data.i = *(MonoBoolean*)params [i];
1178 args [i].data.vt.klass = NULL;
1182 case MONO_TYPE_CHAR:
1183 args [i].type = VAL_I32;
1184 args [i].data.i = *(gint16*)params [i];
1185 args [i].data.vt.klass = NULL;
1187 #if SIZEOF_VOID_P == 4
1188 case MONO_TYPE_U: /* use VAL_POINTER? */
1193 args [i].type = VAL_I32;
1194 args [i].data.i = *(gint32*)params [i];
1195 args [i].data.vt.klass = NULL;
1197 #if SIZEOF_VOID_P == 8
1203 args [i].type = VAL_I64;
1204 args [i].data.l = *(gint64*)params [i];
1205 args [i].data.vt.klass = NULL;
1207 case MONO_TYPE_VALUETYPE:
1208 if (sig->params [i]->data.klass->enumtype) {
1209 type = sig->params [i]->data.klass->enum_basetype->type;
1212 args [i].type = VAL_POINTER;
1213 args [i].data.p = params [i];
1214 args [i].data.vt.klass = NULL;
1217 case MONO_TYPE_STRING:
1218 case MONO_TYPE_CLASS:
1219 case MONO_TYPE_ARRAY:
1220 case MONO_TYPE_SZARRAY:
1221 case MONO_TYPE_OBJECT:
1222 args [i].type = VAL_OBJ;
1223 args [i].data.p = params [i];
1224 args [i].data.vt.klass = NULL;
1227 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1231 INIT_FRAME(&frame,NULL,obj,args,&result,method);
1232 ves_exec_method (&frame);
1233 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1235 if (isobject || method->string_ctor)
1236 return result.data.p;
1237 stackval_to_data (sig->ret, &result, ret);
1242 * Need to optimize ALU ops when natural int == int32
1244 * IDEA: if we maintain a stack of ip, sp to be checked
1245 * in the return opcode, we could inline simple methods that don't
1246 * use the stack or local variables....
1248 * The {,.S} versions of many opcodes can/should be merged to reduce code
1253 ves_exec_method (MonoInvocation *frame)
1255 MonoDomain *domain = mono_domain_get ();
1256 MonoInvocation child_frame;
1257 MonoMethodHeader *header;
1258 MonoMethodSignature *signature;
1260 GSList *finally_ips = NULL;
1261 const unsigned char *endfinally_ip;
1262 register const unsigned char *ip;
1263 register stackval *sp;
1264 void **args_pointers;
1266 gint il_ins_count = -1;
1267 gint tracing = global_tracing;
1268 unsigned char tail_recursion = 0;
1269 unsigned char unaligned_address = 0;
1270 unsigned char volatile_address = 0;
1271 vtallocation *vtalloc = NULL;
1274 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1275 frame->method = mono_marshal_get_native_wrapper (frame->method);
1277 signature = frame->method->signature;
1281 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1282 if (!frame->method->addr) {
1283 /* ugly, but needed by the iflags setting in loader.c */
1284 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1285 ves_runtime_method (frame);
1287 goto handle_exception;
1291 if (frame->method->addr) {
1292 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1293 goto handle_exception;
1296 ves_pinvoke_method (frame, frame->method->signature, frame->method->addr,
1297 frame->method->string_ctor);
1299 goto handle_exception;
1304 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1305 ves_runtime_method (frame);
1307 goto handle_exception;
1312 /*verify_method (frame->method);*/
1314 header = ((MonoMethodNormal *)frame->method)->header;
1315 image = frame->method->klass->image;
1317 if (!frame->method->info)
1318 calc_offsets (image, frame->method);
1319 offsets = frame->method->info;
1322 * with alloca we get the expected huge performance gain
1323 * stackval *stack = g_new0(stackval, header->max_stack);
1325 g_assert (header->max_stack < 10000);
1326 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1328 if (header->num_locals) {
1329 g_assert (offsets [0] < 10000);
1330 frame->locals = alloca (offsets [0]);
1332 * yes, we do it unconditionally, because it needs to be done for
1333 * some cases anyway and checking for that would be even slower.
1335 memset (frame->locals, 0, offsets [0]);
1338 * Copy args from stack_args to args.
1340 if (signature->param_count || signature->hasthis) {
1342 int has_this = signature->hasthis;
1344 g_assert (offsets [1] < 10000);
1345 frame->args = alloca (offsets [1]);
1346 g_assert ((signature->param_count + has_this) < 1000);
1347 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1350 this_arg = args_pointers [0] = frame->args;
1351 *this_arg = frame->obj;
1353 for (i = 0; i < signature->param_count; ++i) {
1354 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1355 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this]);
1359 child_frame.parent = frame;
1360 frame->child = &child_frame;
1367 * using while (ip < end) may result in a 15% performance drop,
1368 * but it may be useful for debug
1372 /*g_assert (sp >= stack);*/
1376 char *ins, *discode;
1377 if (sp > frame->stack) {
1378 ins = dump_stack (frame->stack, sp);
1380 ins = g_strdup ("");
1383 discode = mono_disasm_code_one (NULL, frame->method, ip);
1384 discode [strlen (discode) - 1] = 0; /* no \n */
1385 g_print ("(%d) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1389 if (il_ins_count > 0)
1390 if (!(--il_ins_count))
1400 G_BREAKPOINT (); /* this is not portable... */
1405 CASE (CEE_LDARG_3) {
1406 int n = (*ip)-CEE_LDARG_0;
1408 vt_alloc (ARG_TYPE (signature, n), sp);
1409 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
1416 CASE (CEE_LDLOC_3) {
1417 int n = (*ip)-CEE_LDLOC_0;
1419 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1421 sp->data.i = *(gint32*) LOCAL_POS (n);
1425 vt_alloc (LOCAL_TYPE (header, n), sp);
1426 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1434 CASE (CEE_STLOC_3) {
1435 int n = (*ip)-CEE_STLOC_0;
1438 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1439 gint32 *p = (gint32*)LOCAL_POS (n);
1443 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1450 vt_alloc (ARG_TYPE (signature, *ip), sp);
1451 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1455 CASE (CEE_LDARGA_S) {
1460 t = ARG_TYPE (signature, *ip);
1461 c = mono_class_from_mono_type (t);
1462 sp->data.vt.klass = c;
1463 sp->data.vt.vt = ARG_POS (*ip);
1466 sp->type = VAL_VALUETA;
1477 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1483 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1484 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1488 CASE (CEE_LDLOCA_S) {
1493 t = LOCAL_TYPE (header, *ip);
1494 c = mono_class_from_mono_type (t);
1495 sp->data.vt.klass = c;
1496 sp->data.p = LOCAL_POS (*ip);
1499 sp->type = VAL_VALUETA;
1510 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1518 sp->data.vt.klass = NULL;
1521 CASE (CEE_LDC_I4_M1)
1537 sp->data.i = (*ip) - CEE_LDC_I4_0;
1544 sp->data.i = *(const gint8 *)ip;
1551 sp->data.i = read32 (ip);
1558 sp->data.l = read64 (ip);
1565 sp->type = VAL_DOUBLE;
1574 sp->type = VAL_DOUBLE;
1575 readr8(ip, &sp->data.f);
1579 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1581 if (sp [-1].type == VAL_VALUET) {
1582 MonoClass *c = sp [-1].data.vt.klass;
1583 vt_alloc (&c->byval_arg, sp);
1584 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1596 CASE (CEE_JMP) ves_abort(); BREAK;
1597 CASE (CEE_CALLVIRT) /* Fall through */
1598 CASE (CEE_CALLI) /* Fall through */
1600 MonoMethodSignature *csignature;
1602 stackval *endsp = sp;
1604 int virtual = *ip == CEE_CALLVIRT;
1605 int calli = *ip == CEE_CALLI;
1606 unsigned char *code = NULL;
1609 * We ignore tail recursion for now.
1616 token = read32 (ip);
1622 if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
1623 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
1624 child_frame.method = NULL;
1625 } else if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
1626 child_frame.method = ji->method;
1628 g_assert_not_reached ();
1632 child_frame.method = mono_get_method (image, token, NULL);
1633 if (!child_frame.method)
1634 THROW_EX (mono_get_exception_missing_method (), ip -5);
1635 csignature = child_frame.method->signature;
1637 stackval *this_arg = &sp [-csignature->param_count-1];
1638 if (!this_arg->data.p)
1639 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1640 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1641 if (!child_frame.method)
1642 THROW_EX (mono_get_exception_missing_method (), ip -5);
1646 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1647 /* decrement by the actual number of args */
1648 if (csignature->param_count) {
1649 sp -= csignature->param_count;
1650 child_frame.stack_args = sp;
1652 child_frame.stack_args = NULL;
1654 if (csignature->hasthis) {
1655 g_assert (sp >= frame->stack);
1658 * It may also be a TP from LD(S)FLDA
1659 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1661 if (sp->type == VAL_OBJ && child_frame.method &&
1662 child_frame.method->klass->valuetype) /* unbox it */
1663 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1665 child_frame.obj = sp->data.p;
1667 child_frame.obj = NULL;
1669 if (csignature->ret->type != MONO_TYPE_VOID) {
1670 vt_alloc (csignature->ret, &retval);
1671 child_frame.retval = &retval;
1673 child_frame.retval = NULL;
1676 child_frame.ex = NULL;
1677 child_frame.ex_handler = NULL;
1679 if (!child_frame.method) {
1681 ves_pinvoke_method (&child_frame, csignature, code, FALSE);
1682 } else if (csignature->hasthis && sp->type == VAL_OBJ &&
1683 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
1684 /* implement remoting */
1685 g_assert (child_frame.method);
1686 child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
1687 ves_exec_method (&child_frame);
1688 //invoke_remoting_trampoline (&child_frame);
1690 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1691 case INLINE_STRING_LENGTH:
1692 retval.type = VAL_I32;
1693 retval.data.i = ((MonoString*)sp->data.p)->length;
1694 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
1696 case INLINE_ARRAY_LENGTH:
1697 retval.type = VAL_I32;
1698 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1700 case INLINE_ARRAY_RANK:
1701 retval.type = VAL_I32;
1702 retval.data.i = mono_object_class (sp->data.p)->rank;
1704 case INLINE_TYPE_ELEMENT_TYPE:
1705 retval.type = VAL_OBJ;
1707 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1708 retval.data.vt.klass = NULL;
1709 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1710 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1711 else if (c->element_class)
1712 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1714 retval.data.p = NULL;
1718 ves_exec_method (&child_frame);
1722 while (endsp > sp) {
1727 if (child_frame.ex) {
1729 * An exception occurred, need to run finally, fault and catch handlers..
1731 frame->ex = child_frame.ex;
1732 goto handle_finally;
1735 /* need to handle typedbyref ... */
1736 if (csignature->ret->type != MONO_TYPE_VOID) {
1743 if (signature->ret->type != MONO_TYPE_VOID) {
1745 if (sp->type == VAL_VALUET) {
1746 /* the caller has already allocated the memory */
1747 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1750 *frame->retval = *sp;
1753 if (sp > frame->stack)
1754 g_warning ("more values on stack: %d", sp-frame->stack);
1758 CASE (CEE_BR_S) /* Fall through */
1760 if (*ip == CEE_BR) {
1762 ip += (gint32) read32(ip);
1766 ip += (signed char) *ip;
1770 CASE (CEE_BRFALSE) /* Fall through */
1771 CASE (CEE_BRFALSE_S) {
1773 int near_jump = *ip == CEE_BRFALSE_S;
1777 case VAL_I32: result = sp->data.i == 0; break;
1778 case VAL_I64: result = sp->data.l == 0; break;
1779 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1780 default: result = sp->data.p == NULL; break;
1784 ip += (signed char)*ip;
1786 ip += (gint32) read32 (ip);
1788 ip += near_jump ? 1: 4;
1791 CASE (CEE_BRTRUE) /* Fall through */
1792 CASE (CEE_BRTRUE_S) {
1794 int near_jump = *ip == CEE_BRTRUE_S;
1798 case VAL_I32: result = sp->data.i != 0; break;
1799 case VAL_I64: result = sp->data.l != 0; break;
1800 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1801 default: result = sp->data.p != NULL; break;
1805 ip += (signed char)*ip;
1807 ip += (gint32) read32 (ip);
1809 ip += near_jump ? 1: 4;
1812 CASE (CEE_BEQ) /* Fall through */
1815 int near_jump = *ip == CEE_BEQ_S;
1818 if (sp->type == VAL_I32)
1819 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1820 else if (sp->type == VAL_I64)
1821 result = sp [0].data.l == sp [1].data.l;
1822 else if (sp->type == VAL_DOUBLE)
1823 result = sp [0].data.f == sp [1].data.f;
1825 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1828 ip += (signed char)*ip;
1830 ip += (gint32) read32 (ip);
1832 ip += near_jump ? 1: 4;
1835 CASE (CEE_BGE) /* Fall through */
1839 if (*ip == CEE_BGE_S) {
1840 broffset = (signed char)ip [1];
1843 broffset = (gint32) read32 (ip + 1);
1847 if (sp->type == VAL_I32)
1848 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1849 else if (sp->type == VAL_I64)
1850 result = sp [0].data.l >= sp [1].data.l;
1851 else if (sp->type == VAL_DOUBLE)
1852 result = sp [0].data.f >= sp [1].data.f;
1854 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1859 CASE (CEE_BGT) /* Fall through */
1862 int near_jump = *ip == CEE_BGT_S;
1865 if (sp->type == VAL_I32)
1866 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1867 else if (sp->type == VAL_I64)
1868 result = sp [0].data.l > sp [1].data.l;
1869 else if (sp->type == VAL_DOUBLE)
1870 result = sp [0].data.f > sp [1].data.f;
1872 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1875 ip += (signed char)*ip;
1877 ip += (gint32) read32 (ip);
1879 ip += near_jump ? 1: 4;
1882 CASE (CEE_BLT) /* Fall through */
1885 int near_jump = *ip == CEE_BLT_S;
1888 if (sp->type == VAL_I32)
1889 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1890 else if (sp->type == VAL_I64)
1891 result = sp[0].data.l < sp[1].data.l;
1892 else if (sp->type == VAL_DOUBLE)
1893 result = sp[0].data.f < sp[1].data.f;
1895 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1898 ip += 1 + (signed char)*ip;
1900 ip += 4 + (gint32) read32 (ip);
1903 ip += near_jump ? 1: 4;
1907 CASE (CEE_BLE) /* fall through */
1910 int near_jump = *ip == CEE_BLE_S;
1914 if (sp->type == VAL_I32)
1915 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1916 else if (sp->type == VAL_I64)
1917 result = sp [0].data.l <= sp [1].data.l;
1918 else if (sp->type == VAL_DOUBLE)
1919 result = sp [0].data.f <= sp [1].data.f;
1922 * FIXME: here and in other places GET_NATI on the left side
1923 * _will_ be wrong when we change the macro to work on 64 bits
1926 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1930 ip += (signed char)*ip;
1932 ip += (gint32) read32 (ip);
1934 ip += near_jump ? 1: 4;
1937 CASE (CEE_BNE_UN) /* Fall through */
1938 CASE (CEE_BNE_UN_S) {
1940 int near_jump = *ip == CEE_BNE_UN_S;
1943 if (sp->type == VAL_I32)
1944 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1945 else if (sp->type == VAL_I64)
1946 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1947 else if (sp->type == VAL_DOUBLE)
1948 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1949 (sp [0].data.f != sp [1].data.f);
1951 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1954 ip += (signed char)*ip;
1956 ip += (gint32) read32 (ip);
1958 ip += near_jump ? 1: 4;
1961 CASE (CEE_BGE_UN) /* Fall through */
1962 CASE (CEE_BGE_UN_S) {
1964 int near_jump = *ip == CEE_BGE_UN_S;
1967 if (sp->type == VAL_I32)
1968 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1969 else if (sp->type == VAL_I64)
1970 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1971 else if (sp->type == VAL_DOUBLE)
1972 result = !isless (sp [0].data.f,sp [1].data.f);
1974 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1977 ip += (signed char)*ip;
1979 ip += (gint32) read32 (ip);
1981 ip += near_jump ? 1: 4;
1984 CASE (CEE_BGT_UN) /* Fall through */
1985 CASE (CEE_BGT_UN_S) {
1987 int near_jump = *ip == CEE_BGT_UN_S;
1990 if (sp->type == VAL_I32)
1991 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1992 else if (sp->type == VAL_I64)
1993 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1994 else if (sp->type == VAL_DOUBLE)
1995 result = isgreater (sp [0].data.f, sp [1].data.f);
1997 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
2000 ip += (signed char)*ip;
2002 ip += (gint32) read32 (ip);
2004 ip += near_jump ? 1: 4;
2007 CASE (CEE_BLE_UN) /* Fall through */
2008 CASE (CEE_BLE_UN_S) {
2010 int near_jump = *ip == CEE_BLE_UN_S;
2013 if (sp->type == VAL_I32)
2014 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
2015 else if (sp->type == VAL_I64)
2016 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
2017 else if (sp->type == VAL_DOUBLE)
2018 result = islessequal (sp [0].data.f, sp [1].data.f);
2020 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
2023 ip += (signed char)*ip;
2025 ip += (gint32) read32 (ip);
2027 ip += near_jump ? 1: 4;
2030 CASE (CEE_BLT_UN) /* Fall through */
2031 CASE (CEE_BLT_UN_S) {
2033 int near_jump = *ip == CEE_BLT_UN_S;
2036 if (sp->type == VAL_I32)
2037 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
2038 else if (sp->type == VAL_I64)
2039 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2040 else if (sp->type == VAL_DOUBLE)
2041 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2042 (sp [0].data.f < sp [1].data.f);
2044 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
2047 ip += (signed char)*ip;
2049 ip += (gint32) read32 (ip);
2051 ip += near_jump ? 1: 4;
2056 const unsigned char *st;
2060 st = ip + sizeof (gint32) * n;
2062 if ((guint32)sp->data.i < n) {
2064 ip += sizeof (gint32) * (guint32)sp->data.i;
2065 offset = read32 (ip);
2074 sp[-1].type = VAL_I32;
2075 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2079 sp[-1].type = VAL_I32;
2080 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2084 sp[-1].type = VAL_I32;
2085 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2089 sp[-1].type = VAL_I32;
2090 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2092 CASE (CEE_LDIND_I4) /* Fall through */
2095 sp[-1].type = VAL_I32;
2096 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2100 sp[-1].type = VAL_I64;
2101 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2105 sp[-1].type = VAL_NATI;
2106 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2110 sp[-1].type = VAL_DOUBLE;
2111 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2115 sp[-1].type = VAL_DOUBLE;
2116 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2118 CASE (CEE_LDIND_REF)
2120 sp[-1].type = VAL_OBJ;
2121 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2122 sp[-1].data.vt.klass = NULL;
2124 CASE (CEE_STIND_REF) {
2132 CASE (CEE_STIND_I1) {
2137 *p = (gint8)sp[1].data.i;
2140 CASE (CEE_STIND_I2) {
2145 *p = (gint16)sp[1].data.i;
2148 CASE (CEE_STIND_I4) {
2156 CASE (CEE_STIND_I) {
2161 *p = (mono_i)sp[1].data.p;
2164 CASE (CEE_STIND_I8) {
2172 CASE (CEE_STIND_R4) {
2177 *p = (gfloat)sp[1].data.f;
2180 CASE (CEE_STIND_R8) {
2191 /* should probably consider the pointers as unsigned */
2192 if (sp->type == VAL_I32)
2193 sp [-1].data.i += GET_NATI (sp [0]);
2194 else if (sp->type == VAL_I64)
2195 sp [-1].data.l += sp [0].data.l;
2196 else if (sp->type == VAL_DOUBLE)
2197 sp [-1].data.f += sp [0].data.f;
2199 char *p = sp [-1].data.p;
2200 p += GET_NATI (sp [0]);
2207 /* should probably consider the pointers as unsigned */
2208 if (sp->type == VAL_I32)
2209 sp [-1].data.i -= GET_NATI (sp [0]);
2210 else if (sp->type == VAL_I64)
2211 sp [-1].data.l -= sp [0].data.l;
2212 else if (sp->type == VAL_DOUBLE)
2213 sp [-1].data.f -= sp [0].data.f;
2215 char *p = sp [-1].data.p;
2216 p -= GET_NATI (sp [0]);
2223 if (sp->type == VAL_I32)
2224 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
2225 else if (sp->type == VAL_I64)
2226 sp [-1].data.l *= sp [0].data.l;
2227 else if (sp->type == VAL_DOUBLE)
2228 sp [-1].data.f *= sp [0].data.f;
2233 if (sp->type == VAL_I32) {
2234 if (GET_NATI (sp [0]) == 0)
2235 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2236 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2237 } else if (sp->type == VAL_I64) {
2238 if (sp [0].data.l == 0)
2239 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2240 sp [-1].data.l /= sp [0].data.l;
2241 } else if (sp->type == VAL_DOUBLE) {
2242 /* set NaN is divisor is 0.0 */
2243 sp [-1].data.f /= sp [0].data.f;
2249 if (sp->type == VAL_I32) {
2251 if (GET_NATI (sp [0]) == 0)
2252 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2253 val = sp [-1].data.i;
2254 val /= (guint32)GET_NATI (sp [0]);
2255 sp [-1].data.i = val;
2256 } else if (sp->type == VAL_I64) {
2258 if (sp [0].data.l == 0)
2259 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2260 val = sp [-1].data.l;
2261 val /= (guint64)sp [0].data.l;
2262 sp [-1].data.l = val;
2263 } else if (sp->type == VAL_NATI) {
2265 if (GET_NATI (sp [0]) == 0)
2266 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2267 val = (mono_u)sp [-1].data.p;
2268 val /= (mono_u)sp [0].data.p;
2269 sp [-1].data.p = (gpointer)val;
2275 if (sp->type == VAL_I32) {
2276 if (GET_NATI (sp [0]) == 0)
2277 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2278 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2279 } else if (sp->type == VAL_I64) {
2280 if (sp [0].data.l == 0)
2281 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2282 sp [-1].data.l %= sp [0].data.l;
2283 } else if (sp->type == VAL_DOUBLE) {
2284 /* FIXME: what do we actually do here? */
2285 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2287 if (GET_NATI (sp [0]) == 0)
2288 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2289 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2295 if (sp->type == VAL_I32) {
2296 if (GET_NATI (sp [0]) == 0)
2297 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2298 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2299 } else if (sp->type == VAL_I64) {
2300 if (sp [0].data.l == 0)
2301 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2302 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2303 } else if (sp->type == VAL_DOUBLE) {
2304 /* unspecified behaviour according to the spec */
2306 if (GET_NATI (sp [0]) == 0)
2307 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2308 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2314 if (sp->type == VAL_I32)
2315 sp [-1].data.i &= GET_NATI (sp [0]);
2316 else if (sp->type == VAL_I64)
2317 sp [-1].data.l &= sp [0].data.l;
2319 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2324 if (sp->type == VAL_I32)
2325 sp [-1].data.i |= GET_NATI (sp [0]);
2326 else if (sp->type == VAL_I64)
2327 sp [-1].data.l |= sp [0].data.l;
2329 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2334 if (sp->type == VAL_I32)
2335 sp [-1].data.i ^= GET_NATI (sp [0]);
2336 else if (sp->type == VAL_I64)
2337 sp [-1].data.l ^= sp [0].data.l;
2339 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2344 if (sp [-1].type == VAL_I32)
2345 sp [-1].data.i <<= GET_NATI (sp [0]);
2346 else if (sp [-1].type == VAL_I64)
2347 sp [-1].data.l <<= GET_NATI (sp [0]);
2349 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2354 if (sp [-1].type == VAL_I32)
2355 sp [-1].data.i >>= GET_NATI (sp [0]);
2356 else if (sp [-1].type == VAL_I64)
2357 sp [-1].data.l >>= GET_NATI (sp [0]);
2359 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2364 if (sp [-1].type == VAL_I32)
2365 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2366 else if (sp [-1].type == VAL_I64)
2367 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2369 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2374 if (sp->type == VAL_I32)
2375 sp->data.i = - sp->data.i;
2376 else if (sp->type == VAL_I64)
2377 sp->data.l = - sp->data.l;
2378 else if (sp->type == VAL_DOUBLE)
2379 sp->data.f = - sp->data.f;
2380 else if (sp->type == VAL_NATI)
2381 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2387 if (sp->type == VAL_I32)
2388 sp->data.i = ~ sp->data.i;
2389 else if (sp->type == VAL_I64)
2390 sp->data.l = ~ sp->data.l;
2391 else if (sp->type == VAL_NATI)
2392 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2395 CASE (CEE_CONV_U1) /* fall through */
2396 CASE (CEE_CONV_I1) {
2398 switch (sp [-1].type) {
2400 sp [-1].data.i = (gint8)sp [-1].data.f;
2403 sp [-1].data.i = (gint8)sp [-1].data.l;
2408 sp [-1].data.i = (gint8)sp [-1].data.i;
2411 sp [-1].data.i = (gint8)sp [-1].data.nati;
2414 sp [-1].type = VAL_I32;
2417 CASE (CEE_CONV_U2) /* fall through */
2418 CASE (CEE_CONV_I2) {
2420 switch (sp [-1].type) {
2422 sp [-1].data.i = (gint16)sp [-1].data.f;
2425 sp [-1].data.i = (gint16)sp [-1].data.l;
2430 sp [-1].data.i = (gint16)sp [-1].data.i;
2433 sp [-1].data.i = (gint16)sp [-1].data.nati;
2436 sp [-1].type = VAL_I32;
2439 CASE (CEE_CONV_U4) /* Fall through */
2440 #if SIZEOF_VOID_P == 4
2441 CASE (CEE_CONV_I) /* Fall through */
2442 CASE (CEE_CONV_U) /* Fall through */
2444 CASE (CEE_CONV_I4) {
2446 switch (sp [-1].type) {
2448 sp [-1].data.i = (gint32)sp [-1].data.f;
2451 sp [-1].data.i = (gint32)sp [-1].data.l;
2458 sp [-1].data.i = (gint32)sp [-1].data.p;
2461 sp [-1].type = VAL_I32;
2464 #if SIZEOF_VOID_P == 8
2465 CASE (CEE_CONV_I) /* Fall through */
2469 switch (sp [-1].type) {
2471 sp [-1].data.l = (gint64)sp [-1].data.f;
2478 sp [-1].data.l = (gint64)sp [-1].data.i;
2481 sp [-1].data.l = (gint64)sp [-1].data.nati;
2484 sp [-1].type = VAL_I64;
2486 CASE (CEE_CONV_R4) {
2488 switch (sp [-1].type) {
2490 sp [-1].data.f = (float)sp [-1].data.f;
2493 sp [-1].data.f = (float)sp [-1].data.l;
2498 sp [-1].data.f = (float)sp [-1].data.i;
2501 sp [-1].data.f = (float)sp [-1].data.nati;
2504 sp [-1].type = VAL_DOUBLE;
2507 CASE (CEE_CONV_R8) {
2509 switch (sp [-1].type) {
2511 sp [-1].data.f = (double)sp [-1].data.f;
2514 sp [-1].data.f = (double)sp [-1].data.l;
2519 sp [-1].data.f = (double)sp [-1].data.i;
2522 sp [-1].data.f = (double)sp [-1].data.nati;
2525 sp [-1].type = VAL_DOUBLE;
2528 #if SIZEOF_VOID_P == 8
2529 CASE (CEE_CONV_U) /* Fall through */
2534 switch (sp [-1].type){
2536 sp [-1].data.l = (guint64)sp [-1].data.f;
2543 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
2546 sp [-1].data.l = (guint64) sp [-1].data.nati;
2549 sp [-1].type = VAL_I64;
2554 vtklass = mono_class_get (image, read32 (ip));
2557 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2566 token = read32 (ip);
2569 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
2570 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
2572 c = mono_class_get (image, token);
2574 addr = sp [-1].data.vt.vt;
2575 vt_alloc (&c->byval_arg, &sp [-1]);
2576 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2584 str_index = mono_metadata_token_index (read32 (ip));
2587 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2590 sp->data.vt.klass = NULL;
2597 MonoClass *newobj_class;
2598 MonoMethodSignature *csig;
2599 stackval valuetype_this;
2600 stackval *endsp = sp;
2607 token = read32 (ip);
2610 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2611 THROW_EX (mono_get_exception_missing_method (), ip -5);
2613 csig = child_frame.method->signature;
2614 newobj_class = child_frame.method->klass;
2615 /*if (profiling_classes) {
2616 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2618 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2622 if (newobj_class->parent == mono_defaults.array_class) {
2623 sp -= csig->param_count;
2624 o = ves_array_create (domain, newobj_class, csig, sp);
2625 goto array_constructed;
2629 * First arg is the object.
2631 if (newobj_class->valuetype) {
2633 vt_alloc (&newobj_class->byval_arg, &valuetype_this);
2634 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2635 zero = valuetype_this.data.vt.vt;
2636 child_frame.obj = valuetype_this.data.vt.vt;
2638 memset (&valuetype_this, 0, sizeof (stackval));
2639 zero = &valuetype_this;
2640 child_frame.obj = &valuetype_this;
2642 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero);
2644 if (newobj_class != mono_defaults.string_class) {
2645 o = mono_object_new (domain, newobj_class);
2646 child_frame.obj = o;
2648 child_frame.retval = &retval;
2652 if (csig->param_count) {
2653 sp -= csig->param_count;
2654 child_frame.stack_args = sp;
2656 child_frame.stack_args = NULL;
2659 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2661 child_frame.ex = NULL;
2662 child_frame.ex_handler = NULL;
2664 ves_exec_method (&child_frame);
2666 while (endsp > sp) {
2671 if (child_frame.ex) {
2673 * An exception occurred, need to run finally, fault and catch handlers..
2675 frame->ex = child_frame.ex;
2676 goto handle_finally;
2679 * a constructor returns void, but we need to return the object we created
2682 if (newobj_class->valuetype && !newobj_class->enumtype) {
2683 *sp = valuetype_this;
2684 } else if (newobj_class == mono_defaults.string_class) {
2689 sp->data.vt.klass = newobj_class;
2694 CASE (CEE_CASTCLASS) /* Fall through */
2698 MonoClass *c , *oclass;
2700 int do_isinst = *ip == CEE_ISINST;
2701 gboolean found = FALSE;
2704 token = read32 (ip);
2705 c = mono_class_get (image, token);
2707 g_assert (sp [-1].type == VAL_OBJ);
2709 if ((o = sp [-1].data.p)) {
2714 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2715 if ((c->interface_id <= oclass->max_interface_id) &&
2716 vt->interface_offsets [c->interface_id])
2719 if (oclass == mono_defaults.transparent_proxy_class) {
2720 /* fixme: add check for IRemotingTypeInfo */
2721 MonoRealProxy *rp = ((MonoTransparentProxy *)o)->rp;
2723 type = rp->class_to_proxy->type;
2724 oclass = mono_class_from_mono_type (type);
2726 /* handle array casts */
2727 if (oclass->rank && oclass->rank == c->rank) {
2728 if ((oclass->element_class->baseval - c->element_class->baseval) <= c->element_class->diffval) {
2729 sp [-1].data.vt.klass = c;
2732 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2733 sp [-1].data.vt.klass = c;
2740 sp [-1].data.p = NULL;
2741 sp [-1].data.vt.klass = NULL;
2743 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2749 CASE (CEE_CONV_R_UN)
2751 switch (sp [-1].type) {
2755 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2760 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2763 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2766 sp [-1].type = VAL_DOUBLE;
2769 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2776 token = read32 (ip);
2778 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
2779 c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
2781 c = mono_class_get (image, token);
2785 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2787 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2788 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2790 sp [-1].type = VAL_MP;
2791 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2798 frame->ex_handler = NULL;
2800 sp->data.p = mono_get_exception_null_reference ();
2801 THROW_EX (sp->data.p, ip);
2803 CASE (CEE_LDFLDA) /* Fall through */
2806 MonoClassField *field;
2807 guint32 token, offset;
2808 int load_addr = *ip == CEE_LDFLDA;
2810 if (!sp [-1].data.p)
2811 THROW_EX (mono_get_exception_null_reference (), ip);
2814 token = read32 (ip);
2817 if (sp [-1].type == VAL_OBJ) {
2818 obj = sp [-1].data.p;
2820 if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
2821 g_assert_not_reached ();
2823 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2824 field = mono_field_from_memberref (image, token, NULL);
2826 field = mono_class_get_field (obj->vtable->klass, token);
2827 offset = field->offset;
2830 obj = sp [-1].data.vt.vt;
2831 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2832 offset = field->offset - sizeof (MonoObject);
2836 sp [-1].type = VAL_TP;
2837 sp [-1].data.p = (char*)obj + offset;
2838 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2840 vt_alloc (field->type, &sp [-1]);
2841 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2848 MonoClassField *field;
2849 guint32 token, offset;
2854 THROW_EX (mono_get_exception_null_reference (), ip);
2857 token = read32 (ip);
2860 if (sp [0].type == VAL_OBJ) {
2861 obj = sp [0].data.p;
2863 if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
2864 g_assert_not_reached ();
2866 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2867 field = mono_field_from_memberref (image, token, NULL);
2869 field = mono_class_get_field (obj->vtable->klass, token);
2870 offset = field->offset;
2873 obj = sp [0].data.vt.vt;
2874 field = mono_class_get_field (sp [0].data.vt.klass, token);
2875 offset = field->offset - sizeof (MonoObject);
2878 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2882 CASE (CEE_LDSFLD) /* Fall through */
2883 CASE (CEE_LDSFLDA) {
2886 MonoClassField *field;
2888 int load_addr = *ip == CEE_LDSFLDA;
2892 token = read32 (ip);
2895 /* need to handle fieldrefs */
2896 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2897 field = mono_field_from_memberref (image, token, &klass);
2899 klass = mono_class_get (image,
2900 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2901 field = mono_class_get_field (klass, token);
2905 vt = mono_class_vtable (domain, klass);
2906 addr = (char*)(vt->data) + field->offset;
2911 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2913 vt_alloc (field->type, sp);
2914 stackval_from_data (field->type, sp, addr);
2922 MonoClassField *field;
2927 token = read32 (ip);
2931 /* need to handle fieldrefs */
2932 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2933 field = mono_field_from_memberref (image, token, &klass);
2935 klass = mono_class_get (image,
2936 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2937 field = mono_class_get_field (klass, token);
2941 vt = mono_class_vtable (domain, klass);
2942 addr = (char*)(vt->data) + field->offset;
2944 stackval_to_data (field->type, sp, addr);
2951 vtklass = mono_class_get (image, read32 (ip));
2954 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2957 #if SIZEOF_VOID_P == 8
2958 CASE (CEE_CONV_OVF_I_UN)
2960 CASE (CEE_CONV_OVF_I8_UN) {
2961 switch (sp [-1].type) {
2963 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2964 THROW_EX (mono_get_exception_overflow (), ip);
2965 sp [-1].data.l = (guint64)sp [-1].data.f;
2972 /* Can't overflow */
2973 sp [-1].data.l = (guint64)sp [-1].data.i;
2976 sp [-1].data.l = (guint64)sp [-1].data.nati;
2979 sp [-1].type = VAL_I64;
2983 #if SIZEOF_VOID_P == 8
2984 CASE (CEE_CONV_OVF_U_UN)
2986 CASE (CEE_CONV_OVF_U8_UN) {
2987 switch (sp [-1].type) {
2989 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
2990 THROW_EX (mono_get_exception_overflow (), ip);
2991 sp [-1].data.l = (guint64)sp [-1].data.f;
2999 /* Can't overflow */
3000 sp [-1].data.l = (guint64)sp [-1].data.i;
3003 /* Can't overflow */
3004 sp [-1].data.l = (guint64)sp [-1].data.nati;
3007 sp [-1].type = VAL_I64;
3011 #if SIZEOF_VOID_P == 4
3012 CASE (CEE_CONV_OVF_I_UN)
3013 CASE (CEE_CONV_OVF_U_UN)
3015 CASE (CEE_CONV_OVF_I1_UN)
3016 CASE (CEE_CONV_OVF_I2_UN)
3017 CASE (CEE_CONV_OVF_I4_UN)
3018 CASE (CEE_CONV_OVF_U1_UN)
3019 CASE (CEE_CONV_OVF_U2_UN)
3020 CASE (CEE_CONV_OVF_U4_UN) {
3022 switch (sp [-1].type) {
3024 value = (guint64)sp [-1].data.f;
3027 value = (guint64)sp [-1].data.l;
3032 value = (guint64)sp [-1].data.i;
3035 value = (guint64)sp [-1].data.nati;
3039 case CEE_CONV_OVF_I1_UN:
3041 THROW_EX (mono_get_exception_overflow (), ip);
3042 sp [-1].data.i = value;
3043 sp [-1].type = VAL_I32;
3045 case CEE_CONV_OVF_I2_UN:
3047 THROW_EX (mono_get_exception_overflow (), ip);
3048 sp [-1].data.i = value;
3049 sp [-1].type = VAL_I32;
3051 #if SIZEOF_VOID_P == 4
3052 case CEE_CONV_OVF_I_UN: /* Fall through */
3054 case CEE_CONV_OVF_I4_UN:
3055 if (value > 2147483647)
3056 THROW_EX (mono_get_exception_overflow (), ip);
3057 sp [-1].data.i = value;
3058 sp [-1].type = VAL_I32;
3060 case CEE_CONV_OVF_U1_UN:
3062 THROW_EX (mono_get_exception_overflow (), ip);
3063 sp [-1].data.i = value;
3064 sp [-1].type = VAL_I32;
3066 case CEE_CONV_OVF_U2_UN:
3068 THROW_EX (mono_get_exception_overflow (), ip);
3069 sp [-1].data.i = value;
3070 sp [-1].type = VAL_I32;
3072 #if SIZEOF_VOID_P == 4
3073 case CEE_CONV_OVF_U_UN: /* Fall through */
3075 case CEE_CONV_OVF_U4_UN:
3076 if (value > 4294967295U)
3077 THROW_EX (mono_get_exception_overflow (), ip);
3078 sp [-1].data.i = value;
3079 sp [-1].type = VAL_I32;
3082 g_assert_not_reached ();
3092 token = read32 (ip);
3094 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3095 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3097 class = mono_class_get (image, token);
3098 g_assert (class != NULL);
3100 sp [-1].type = VAL_OBJ;
3101 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3102 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3104 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1]);
3105 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3107 /* need to vt_free (sp); */
3119 token = read32 (ip);
3121 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3122 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3124 class = mono_class_get (image, token);
3126 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3129 sp [-1].type = VAL_OBJ;
3131 /*if (profiling_classes) {
3132 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3134 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3144 g_assert (sp [-1].type == VAL_OBJ);
3148 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3150 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3152 sp [-1].type = VAL_I32;
3153 sp [-1].data.i = mono_array_length (o);
3157 CASE (CEE_LDELEMA) {
3159 guint32 esize, token;
3162 token = read32 (ip);
3166 g_assert (sp [0].type == VAL_OBJ);
3169 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3171 if (sp [1].data.nati >= mono_array_length (o))
3172 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3174 /* check the array element corresponds to token */
3175 esize = mono_array_element_size (o->obj.vtable->klass);
3178 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
3179 sp->data.vt.klass = o->obj.vtable->klass->element_class;
3184 CASE (CEE_LDELEM_I1) /* fall through */
3185 CASE (CEE_LDELEM_U1) /* fall through */
3186 CASE (CEE_LDELEM_I2) /* fall through */
3187 CASE (CEE_LDELEM_U2) /* fall through */
3188 CASE (CEE_LDELEM_I4) /* fall through */
3189 CASE (CEE_LDELEM_U4) /* fall through */
3190 CASE (CEE_LDELEM_I8) /* fall through */
3191 CASE (CEE_LDELEM_I) /* fall through */
3192 CASE (CEE_LDELEM_R4) /* fall through */
3193 CASE (CEE_LDELEM_R8) /* fall through */
3194 CASE (CEE_LDELEM_REF) {
3200 g_assert (sp [0].type == VAL_OBJ);
3203 THROW_EX (mono_get_exception_null_reference (), ip);
3205 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3207 aindex = sp [1].data.nati;
3208 if (aindex >= mono_array_length (o))
3209 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3212 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3216 sp [0].data.i = mono_array_get (o, gint8, aindex);
3217 sp [0].type = VAL_I32;
3220 sp [0].data.i = mono_array_get (o, guint8, aindex);
3221 sp [0].type = VAL_I32;
3224 sp [0].data.i = mono_array_get (o, gint16, aindex);
3225 sp [0].type = VAL_I32;
3228 sp [0].data.i = mono_array_get (o, guint16, aindex);
3229 sp [0].type = VAL_I32;
3232 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3233 sp [0].type = VAL_NATI;
3236 sp [0].data.i = mono_array_get (o, gint32, aindex);
3237 sp [0].type = VAL_I32;
3240 sp [0].data.i = mono_array_get (o, guint32, aindex);
3241 sp [0].type = VAL_I32;
3244 sp [0].data.l = mono_array_get (o, guint64, aindex);
3245 sp [0].type = VAL_I64;
3248 sp [0].data.f = mono_array_get (o, float, aindex);
3249 sp [0].type = VAL_DOUBLE;
3252 sp [0].data.f = mono_array_get (o, double, aindex);
3253 sp [0].type = VAL_DOUBLE;
3255 case CEE_LDELEM_REF:
3256 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3257 sp [0].data.vt.klass = NULL;
3258 sp [0].type = VAL_OBJ;
3268 CASE (CEE_STELEM_I) /* fall through */
3269 CASE (CEE_STELEM_I1) /* fall through */
3270 CASE (CEE_STELEM_I2) /* fall through */
3271 CASE (CEE_STELEM_I4) /* fall through */
3272 CASE (CEE_STELEM_I8) /* fall through */
3273 CASE (CEE_STELEM_R4) /* fall through */
3274 CASE (CEE_STELEM_R8) /* fall through */
3275 CASE (CEE_STELEM_REF) {
3282 g_assert (sp [0].type == VAL_OBJ);
3285 THROW_EX (mono_get_exception_null_reference (), ip);
3287 ac = o->obj.vtable->klass;
3288 g_assert (MONO_CLASS_IS_ARRAY (ac));
3290 aindex = sp [1].data.nati;
3291 if (aindex >= mono_array_length (o))
3292 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3295 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3299 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3302 mono_array_set (o, gint8, aindex, sp [2].data.i);
3305 mono_array_set (o, gint16, aindex, sp [2].data.i);
3308 mono_array_set (o, gint32, aindex, sp [2].data.i);
3311 mono_array_set (o, gint64, aindex, sp [2].data.l);
3314 mono_array_set (o, float, aindex, sp [2].data.f);
3317 mono_array_set (o, double, aindex, sp [2].data.f);
3319 case CEE_STELEM_REF:
3320 g_assert (sp [2].type == VAL_OBJ);
3321 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3345 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3346 CASE (CEE_CONV_OVF_I1)
3347 if (sp [-1].type == VAL_I32) {
3348 if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
3349 THROW_EX (mono_get_exception_overflow (), ip);
3350 sp [-1].data.i = (gint8)sp [-1].data.i;
3351 } else if (sp [-1].type == VAL_I64) {
3352 if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
3353 THROW_EX (mono_get_exception_overflow (), ip);
3354 sp [-1].data.i = (gint8)sp [-1].data.l;
3360 CASE (CEE_CONV_OVF_U1)
3361 if (sp [-1].type == VAL_I32) {
3362 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3363 THROW_EX (mono_get_exception_overflow (), ip);
3364 sp [-1].data.i = (gint8)sp [-1].data.i;
3365 } else if (sp [-1].type == VAL_I64) {
3366 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3367 THROW_EX (mono_get_exception_overflow (), ip);
3368 sp [-1].data.i = (gint8)sp [-1].data.l;
3374 CASE (CEE_CONV_OVF_I2)
3375 CASE (CEE_CONV_OVF_U2)
3377 /* FIXME: handle other cases */
3378 if (sp [-1].type == VAL_I32) {
3379 /* defined as NOP */
3384 CASE (CEE_CONV_OVF_I4)
3385 /* FIXME: handle other cases */
3386 if (sp [-1].type == VAL_I32) {
3387 /* defined as NOP */
3388 } else if(sp [-1].type == VAL_I64) {
3389 sp [-1].data.i = (gint32)sp [-1].data.l;
3390 sp [-1].type = VAL_I32;
3396 CASE (CEE_CONV_OVF_U4)
3397 /* FIXME: handle other cases */
3398 if (sp [-1].type == VAL_I32) {
3399 /* defined as NOP */
3400 } else if(sp [-1].type == VAL_I64) {
3401 sp [-1].data.i = (guint32)sp [-1].data.l;
3402 sp [-1].type = VAL_I32;
3408 CASE (CEE_CONV_OVF_I8)
3409 /* FIXME: handle other cases */
3410 if (sp [-1].type == VAL_I32) {
3411 sp [-1].data.l = (guint64)sp [-1].data.i;
3412 sp [-1].type = VAL_I64;
3413 } else if(sp [-1].type == VAL_I64) {
3414 /* defined as NOP */
3420 CASE (CEE_CONV_OVF_U8)
3421 /* FIXME: handle other cases */
3422 if (sp [-1].type == VAL_I32) {
3423 sp [-1].data.l = (guint64) sp [-1].data.i;
3424 sp [-1].type = VAL_I64;
3425 } else if(sp [-1].type == VAL_I64) {
3426 /* defined as NOP */
3438 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3439 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3441 if (!finite(sp [-1].data.f))
3442 THROW_EX (mono_get_exception_arithmetic (), ip);
3445 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3446 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3447 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3456 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3457 CASE (CEE_LDTOKEN) {
3459 MonoClass *handle_class;
3461 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3463 vt_alloc (&handle_class->byval_arg, sp);
3464 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
3468 CASE (CEE_CONV_OVF_I)
3471 /* FIXME: check overflow. */
3474 sp->data.p = (gpointer)(mono_i) sp->data.i;
3477 sp->data.p = (gpointer)(mono_i) sp->data.l;
3482 sp->data.p = (gpointer)(mono_i) sp->data.f;
3487 sp->type = VAL_NATI;
3490 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
3493 /* FIXME: check overflow */
3494 if (sp->type == VAL_I32) {
3495 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3496 THROW_EX (mono_get_exception_overflow (), ip);
3497 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)GET_NATI (sp [0]);
3498 } else if (sp->type == VAL_I64) {
3499 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3500 THROW_EX (mono_get_exception_overflow (), ip);
3501 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3502 } else if (sp->type == VAL_DOUBLE)
3503 sp [-1].data.f += sp [0].data.f;
3505 char *p = sp [-1].data.p;
3506 p += GET_NATI (sp [0]);
3511 CASE (CEE_ADD_OVF_UN)
3513 /* FIXME: check overflow, make unsigned */
3514 if (sp->type == VAL_I32) {
3515 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3516 THROW_EX (mono_get_exception_overflow (), ip);
3517 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3518 } else if (sp->type == VAL_I64) {
3519 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3520 THROW_EX (mono_get_exception_overflow (), ip);
3521 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3522 } else if (sp->type == VAL_DOUBLE)
3523 sp [-1].data.f += sp [0].data.f;
3525 char *p = sp [-1].data.p;
3526 p += GET_NATI (sp [0]);
3534 /* FIXME: check overflow */
3535 if (sp->type == VAL_I32)
3536 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3537 else if (sp->type == VAL_I64)
3538 sp [-1].data.l *= sp [0].data.l;
3539 else if (sp->type == VAL_DOUBLE)
3540 sp [-1].data.f *= sp [0].data.f;
3542 CASE (CEE_MUL_OVF_UN)
3545 /* FIXME: check overflow, make unsigned */
3546 if (sp->type == VAL_I32)
3547 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3548 else if (sp->type == VAL_I64)
3549 sp [-1].data.l *= sp [0].data.l;
3550 else if (sp->type == VAL_DOUBLE)
3551 sp [-1].data.f *= sp [0].data.f;
3554 CASE (CEE_SUB_OVF_UN)
3557 /* FIXME: handle undeflow/unsigned */
3558 /* should probably consider the pointers as unsigned */
3559 if (sp->type == VAL_I32)
3560 sp [-1].data.i -= GET_NATI (sp [0]);
3561 else if (sp->type == VAL_I64)
3562 sp [-1].data.l -= sp [0].data.l;
3563 else if (sp->type == VAL_DOUBLE)
3564 sp [-1].data.f -= sp [0].data.f;
3566 char *p = sp [-1].data.p;
3567 p -= GET_NATI (sp [0]);
3571 CASE (CEE_ENDFINALLY)
3573 ip = finally_ips->data;
3574 finally_ips = g_slist_remove (finally_ips, ip);
3580 * There was no exception, we continue normally at the target address.
3584 CASE (CEE_LEAVE) /* Fall through */
3586 sp = frame->stack; /* empty the stack */
3588 if (*ip == CEE_LEAVE_S) {
3590 ip += (signed char) *ip;
3594 ip += (gint32) read32 (ip);
3599 * We may be either inside a try block or inside an handler.
3600 * In the first case there was no exception and we go on
3601 * executing the finally handlers and after that resume control
3603 * In the second case we need to clear the exception and
3604 * continue directly at the target ip.
3608 goto handle_finally;
3611 frame->ex_handler = NULL;
3615 frame->ex_handler = NULL;
3617 goto handle_finally;
3623 case CEE_MONO_FUNC1: {
3624 MonoMarshalConv conv;
3634 sp->data.vt.klass = NULL;
3637 case MONO_MARSHAL_CONV_STR_LPWSTR:
3638 sp->data.p = mono_string_to_utf16 (sp->data.p);
3640 case MONO_MARSHAL_CONV_LPSTR_STR:
3641 sp->data.p = mono_string_new_wrapper (sp->data.p);
3643 case MONO_MARSHAL_CONV_STR_LPTSTR:
3644 case MONO_MARSHAL_CONV_STR_LPSTR:
3645 sp->data.p = mono_string_to_utf8 (sp->data.p);
3647 case MONO_MARSHAL_CONV_STR_BSTR:
3648 sp->data.p = mono_string_to_bstr (sp->data.p);
3650 case MONO_MARSHAL_CONV_STR_TBSTR:
3651 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3652 sp->data.p = mono_string_to_ansibstr (sp->data.p);
3654 case MONO_MARSHAL_CONV_SB_LPSTR:
3655 sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
3657 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3658 sp->data.p = mono_array_to_savearray (sp->data.p);
3660 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3661 sp->data.p = mono_array_to_lparray (sp->data.p);
3663 case MONO_MARSHAL_CONV_DEL_FTN:
3664 sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
3666 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3667 sp->data.p = mono_marshal_string_array (sp->data.p);
3670 g_assert_not_reached ();
3675 case CEE_MONO_PROC2: {
3676 MonoMarshalConv conv;
3684 case MONO_MARSHAL_CONV_LPSTR_SB:
3685 mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
3687 case MONO_MARSHAL_FREE_ARRAY:
3688 mono_marshal_free_array (sp [0].data.p, sp [1].data.p);
3691 g_assert_not_reached ();
3695 case CEE_MONO_PROC3: {
3696 MonoMarshalConv conv;
3704 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3705 mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.p);
3707 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3708 mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.p);
3711 g_assert_not_reached ();
3715 case CEE_MONO_VTADDR: {
3718 sp->type = VAL_VALUETA;
3722 case CEE_MONO_LDPTR: {
3726 token = read32 (ip);
3730 sp->data.p = mono_method_get_wrapper_data (frame->method, token);
3731 sp->data.vt.klass = NULL;
3735 case CEE_MONO_FREE: {
3739 g_free (sp->data.p);
3742 case CEE_MONO_OBJADDR: {
3749 case CEE_MONO_NEWOBJ: {
3754 token = read32 (ip);
3757 class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
3758 sp->data.p = mono_object_new (domain, class);
3763 g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
3794 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3796 * Note: Exceptions thrown when executing a prefixed opcode need
3797 * to take into account the number of prefix bytes (usually the
3798 * throw point is just (ip - n_prefix_bytes).
3803 case CEE_ARGLIST: ves_abort(); break;
3809 if (sp->type == VAL_I32)
3810 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3811 else if (sp->type == VAL_I64)
3812 result = sp [0].data.l == sp [1].data.l;
3813 else if (sp->type == VAL_DOUBLE) {
3814 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3817 result = sp [0].data.f == sp [1].data.f;
3819 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3821 sp->data.i = result;
3831 if (sp->type == VAL_I32)
3832 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3833 else if (sp->type == VAL_I64)
3834 result = sp [0].data.l > sp [1].data.l;
3835 else if (sp->type == VAL_DOUBLE) {
3836 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3839 result = sp [0].data.f > sp [1].data.f;
3841 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3843 sp->data.i = result;
3853 if (sp->type == VAL_I32)
3854 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3855 else if (sp->type == VAL_I64)
3856 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3857 else if (sp->type == VAL_DOUBLE)
3858 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3860 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3862 sp->data.i = result;
3872 if (sp->type == VAL_I32)
3873 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3874 else if (sp->type == VAL_I64)
3875 result = sp [0].data.l < sp [1].data.l;
3876 else if (sp->type == VAL_DOUBLE) {
3877 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3880 result = sp [0].data.f < sp [1].data.f;
3882 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3884 sp->data.i = result;
3894 if (sp->type == VAL_I32)
3895 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3896 else if (sp->type == VAL_I64)
3897 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3898 else if (sp->type == VAL_DOUBLE)
3899 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3901 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3903 sp->data.i = result;
3909 case CEE_LDVIRTFTN: {
3910 int virtual = *ip == CEE_LDVIRTFTN;
3914 token = read32 (ip);
3917 if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
3918 m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
3920 m = mono_get_method (image, token, NULL);
3923 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3927 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3928 m = get_virtual_method (domain, m, sp);
3930 sp->type = VAL_NATI;
3931 sp->data.p = mono_create_method_pointer (m);
3932 sp->data.vt.klass = NULL;
3936 case CEE_UNUSED56: ves_abort(); break;
3940 arg_pos = read16 (ip);
3942 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
3943 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3955 t = ARG_TYPE (signature, anum);
3956 c = mono_class_from_mono_type (t);
3957 sp->data.vt.klass = c;
3958 sp->data.vt.vt = ARG_POS (anum);
3961 sp->type = VAL_VALUETA;
3971 arg_pos = read16 (ip);
3974 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3981 loc_pos = read16 (ip);
3983 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3984 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3994 loc_pos = read16 (ip);
3996 t = LOCAL_TYPE (header, loc_pos);
3997 c = mono_class_from_mono_type (t);
3998 sp->data.vt.vt = LOCAL_POS (loc_pos);
3999 sp->data.vt.klass = c;
4002 sp->type = VAL_VALUETA;
4012 loc_pos = read16 (ip);
4015 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
4021 if (sp != frame->stack)
4022 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
4024 sp->data.p = alloca (sp->data.i);
4028 case CEE_UNUSED57: ves_abort(); break;
4029 case CEE_ENDFILTER: ves_abort(); break;
4030 case CEE_UNALIGNED_:
4032 unaligned_address = 1;
4036 volatile_address = 1;
4045 token = read32 (ip);
4048 * we ignore the value of token (I think we can as unspecified
4049 * behavior described in Partition II, 3.5).
4052 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
4053 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
4056 case CEE_UNUSED68: ves_abort(); break;
4059 if (!sp [0].data.p || !sp [1].data.p)
4060 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4062 /* FIXME: value and size may be int64... */
4063 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4068 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4070 /* FIXME: value and size may be int64... */
4071 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4073 case CEE_UNUSED69: ves_abort(); break;
4076 * need to clarify what this should actually do:
4077 * start the search from the last found handler in
4078 * this method or continue in the caller or what.
4079 * Also, do we need to run finally/fault handlers after a retrow?
4080 * Well, this implementation will follow the usual search
4081 * for an handler, considering the current ip as throw spot.
4082 * We need to NULL frame->ex_handler for the later code to
4083 * actually run the new found handler.
4085 frame->ex_handler = NULL;
4086 THROW_EX (frame->ex, ip - 1);
4088 case CEE_UNUSED: ves_abort(); break;
4093 token = read32 (ip);
4095 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4096 MonoType *type = mono_type_create_from_typespec (image, token);
4097 sp->data.i = mono_type_size (type, &align);
4098 mono_metadata_free_type (type);
4100 MonoClass *szclass = mono_class_get (image, token);
4101 mono_class_init (szclass);
4102 if (!szclass->valuetype)
4103 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4104 sp->data.i = mono_class_value_size (szclass, &align);
4110 case CEE_REFANYTYPE: ves_abort(); break;
4117 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
4124 g_assert_not_reached ();
4126 * Exception handling code.
4127 * The exception object is stored in frame->ex.
4134 MonoInvocation *inv;
4135 MonoMethodHeader *hd;
4136 MonoExceptionClause *clause;
4142 g_print ("* Handling exception '%s' at IL_%04x\n", mono_object_class (frame->ex)->name, frame->ip - header->code);
4144 if (die_on_exception)
4147 for (inv = frame; inv; inv = inv->parent) {
4148 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4150 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4152 hd = ((MonoMethodNormal*)inv->method)->header;
4153 ip_offset = inv->ip - hd->code;
4154 for (i = 0; i < hd->num_clauses; ++i) {
4155 clause = &hd->clauses [i];
4156 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4157 if (!clause->flags) {
4158 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
4160 * OK, we found an handler, now we need to execute the finally
4161 * and fault blocks before branching to the handler code.
4163 inv->ex_handler = clause;
4166 g_print ("* Found handler at '%s'\n", inv->method->name);
4169 * It seems that if the catch handler is found in the same method,
4170 * it gets executed before the finally handler.
4175 goto handle_finally;
4178 /* FIXME: handle filter clauses */
4185 * If we get here, no handler was found: print a stack trace.
4188 ex_obj = (MonoObject*)frame->ex;
4189 mono_unhandled_exception (ex_obj);
4196 MonoExceptionClause *clause;
4198 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
4202 ip_offset = frame->ip - header->code;
4204 for (i = 0; i < header->num_clauses; ++i) {
4205 clause = &header->clauses [i];
4206 if (clause == frame->ex_handler)
4208 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code))) {
4209 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4210 ip = header->code + clause->handler_offset;
4211 finally_ips = g_slist_append (finally_ips, ip);
4214 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4220 ip = finally_ips->data;
4221 finally_ips = g_slist_remove (finally_ips, ip);
4226 * If an exception is set, we need to execute the fault handler, too,
4227 * otherwise, we continue normally.
4238 MonoExceptionClause *clause;
4240 ip_offset = frame->ip - header->code;
4241 for (i = 0; i < header->num_clauses; ++i) {
4242 clause = &header->clauses [i];
4243 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4244 ip = header->code + clause->handler_offset;
4247 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4253 * If the handler for the exception was found in this method, we jump
4254 * to it right away, otherwise we return and let the caller run
4255 * the finally, fault and catch blocks.
4256 * This same code should be present in the endfault opcode, but it
4257 * is corrently not assigned in the ECMA specs: LAMESPEC.
4259 if (frame->ex_handler) {
4260 ip = header->code + frame->ex_handler->handler_offset;
4263 sp->data.p = frame->ex;
4274 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4276 MonoImage *image = assembly->image;
4277 MonoCLIImageInfo *iinfo;
4279 MonoObject *exc = NULL;
4282 iinfo = image->image_info;
4283 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4285 g_error ("No entry point method found in %s", image->name);
4287 rval = mono_runtime_run_main (method, argc, argv, &exc);
4296 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4297 "Usage is: mint [options] executable args...\n\n", VERSION);
4299 "Runtime Debugging:\n"
4304 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4307 " --traceclassinit\n"
4310 " --debug method_name\n"
4316 " --config filename load the specified config file instead of the default\n"
4317 " --workers n maximum number of worker threads\n"
4324 test_load_class (MonoImage* image)
4326 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4330 for (i = 1; i <= t->rows; ++i) {
4331 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4332 mono_class_init (klass);
4337 static MonoException * segv_exception = NULL;
4340 segv_handler (int signum)
4342 signal (signum, segv_handler);
4343 mono_raise_exception (segv_exception);
4347 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4348 MonoReflectionMethod **method,
4349 gint32 *iloffset, gint32 *native_offset,
4350 MonoString **file, gint32 *line, gint32 *column)
4363 *file = mono_string_new (mono_domain_get (), "unknown");
4369 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4375 main (int argc, char *argv [])
4378 MonoAssembly *assembly;
4379 int retval = 0, i, ocount = 0;
4380 char *file, *error, *config_file = NULL;
4385 for (i = 1; i < argc && argv [i][0] == '-'; i++){
4386 if (strcmp (argv [i], "--trace") == 0)
4388 if (strcmp (argv [i], "--noptr") == 0)
4389 global_no_pointers = 1;
4390 if (strcmp (argv [i], "--traceops") == 0)
4392 if (strcmp (argv [i], "--dieonex") == 0)
4393 die_on_exception = 1;
4394 if (strcmp (argv [i], "--print-vtable") == 0)
4395 mono_print_vtable = TRUE;
4396 if (strcmp (argv [i], "--profile") == 0)
4397 mono_profiler_install_simple ();
4398 if (strcmp (argv [i], "--opcode-count") == 0)
4400 if (strcmp (argv [i], "--config") == 0)
4401 config_file = argv [++i];
4402 if (strcmp (argv [i], "--workers") == 0) {
4403 mono_worker_threads = atoi (argv [++i]);
4404 if (mono_worker_threads < 1)
4405 mono_worker_threads = 1;
4407 if (strcmp (argv [i], "--help") == 0)
4410 if (strcmp (argv [i], "--debug") == 0) {
4411 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
4413 g_error ("Invalid method name '%s'", argv [i]);
4414 db_methods = g_list_append (db_methods, desc);
4424 mono_set_rootdir (argv [0]);
4425 mono_config_parse (config_file);
4427 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
4428 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
4431 mono_add_internal_call ("System.Delegate::CreateDelegate_internal", ves_delegate_createdelegate);
4432 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
4433 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
4435 frame_thread_id = TlsAlloc ();
4436 TlsSetValue (frame_thread_id, NULL);
4438 mono_install_compile_method (mono_create_method_pointer);
4439 mono_install_runtime_invoke (interp_mono_runtime_invoke);
4440 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
4442 mono_install_handler (interp_ex_handler);
4443 mono_install_stack_walk (interp_walk_stack);
4445 InitializeCriticalSection (&metadata_lock);
4446 domain = mono_init (file);
4447 mono_runtime_init (domain, NULL);
4449 assembly = mono_domain_assembly_open (domain, file);
4452 fprintf (stderr, "Can not open image %s\n", file);
4458 test_load_class (assembly->image);
4460 error = mono_verify_corlib ();
4462 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
4465 segv_exception = mono_get_exception_null_reference ();
4466 segv_exception->message = mono_string_new (domain, "Segmentation fault");
4467 signal (SIGSEGV, segv_handler);
4469 retval = ves_exec (domain, assembly, argc - i, argv + i);
4471 mono_profiler_shutdown ();
4473 mono_runtime_cleanup (domain);
4474 mono_domain_unload (domain, TRUE);
4478 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4479 fprintf (stderr, "fcall count: %ld\n", fcall_count);