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/os/util.h>
60 /*#include <mono/cli/types.h>*/
66 #define finite _finite
69 /* If true, then we output the opcodes as we interpret them */
70 static int global_tracing = 0;
71 static int global_no_pointers = 0;
73 static int debug_indent_level = 0;
76 * Pull the list of opcodes
78 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
82 #include "mono/cil/opcode.def"
87 #define GET_NATI(sp) ((sp).data.nati)
88 #define CSIZE(x) (sizeof (x) / 4)
90 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
92 (frame)->parent = (parent_frame); \
93 (frame)->obj = (obj_this); \
94 (frame)->stack_args = (method_args); \
95 (frame)->retval = (method_retval); \
96 (frame)->method = (mono_method); \
97 (frame)->ex_handler = NULL; \
99 (frame)->child = NULL; \
102 void ves_exec_method (MonoInvocation *frame);
104 typedef void (*ICallMethod) (MonoInvocation *frame);
106 static guint32 die_on_exception = 0;
107 static guint32 frame_thread_id = 0;
109 #define DEBUG_INTERP 1
112 static unsigned long opcode_count = 0;
113 static unsigned long fcall_count = 0;
114 static int break_on_method = 0;
115 static GList *db_methods = NULL;
122 for (h = 0; h < debug_indent_level; h++)
127 db_match_method (gpointer data, gpointer user_data)
129 MonoMethod *m = (MonoMethod*)user_data;
130 MonoMethodDesc *desc = data;
132 if (mono_method_desc_full_match (desc, m))
136 #define DEBUG_ENTER() \
138 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
139 if (break_on_method) tracing=2; \
140 break_on_method = 0; \
142 MonoClass *klass = frame->method->klass; \
143 char *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count); \
144 debug_indent_level++; \
146 g_print ("(%d) Entering %s.%s::%s (", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
147 if (signature->hasthis) { \
148 if (global_no_pointers) { \
149 g_print ("this%s ", frame->obj ? "" : "=null"); \
151 g_print ("%p ", frame->obj); } \
153 g_print ("%s)\n", args); \
156 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
157 mono_profiler_method_enter (frame->method);
159 #define DEBUG_LEAVE() \
161 MonoClass *klass = frame->method->klass; \
163 if (signature->ret->type != MONO_TYPE_VOID) \
164 args = dump_stack (frame->retval, frame->retval + 1); \
166 args = g_strdup (""); \
168 g_print ("(%d) Leaving %s.%s::%s", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name); \
169 g_print (" => %s\n", args); \
171 debug_indent_level--; \
173 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
174 mono_profiler_method_leave (frame->method);
178 #define DEBUG_ENTER()
179 #define DEBUG_LEAVE()
184 interp_ex_handler (MonoException *ex) {
185 MonoInvocation *frame = TlsGetValue (frame_thread_id);
187 longjmp (*(jmp_buf*)frame->locals, 1);
191 ves_real_abort (int line, MonoMethod *mh,
192 const unsigned char *ip, stackval *stack, stackval *sp)
194 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
195 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
196 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
197 ip-mm->header->code);
198 g_print ("0x%04x %02x\n",
199 ip-mm->header->code, *ip);
201 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
203 #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);
205 static MonoMethodMessage *
206 arch_method_call_message_new (MonoMethod *method, void *obj, stackval *args, MonoMethod *invoke,
207 MonoDelegate **cb, MonoObject **state)
209 MonoDomain *domain = mono_domain_get ();
210 MonoMethodSignature *sig = method->signature;
211 MonoMethodMessage *msg;
212 int i, count, type, size, align;
213 /*char *cpos = stack;*/
215 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
218 mono_message_init (domain, msg, mono_method_get_object (domain, invoke), NULL);
219 count = sig->param_count - 2;
221 mono_message_init (domain, msg, mono_method_get_object (domain, method), NULL);
222 count = sig->param_count;
225 for (i = 0; i < count; i++) {
230 size = mono_type_stack_size (sig->params [i], &align);
232 /* FIXME: endian issues */
233 if (sig->params [i]->byref)
234 vpos = *((gpointer *)args [i].data.p);
236 vpos = &args [i].data;
238 type = sig->params [i]->type;
239 class = mono_class_from_mono_type (sig->params [i]);
241 if (class->valuetype)
242 arg = mono_value_box (domain, class, vpos);
244 arg = args [i].data.p;
246 mono_array_set (msg->args, gpointer, i, arg);
250 /* the last two arguments of begininvoke */
251 *cb = args [count].data.p;
252 *state = args [count + 1].data.p;
258 interp_create_remoting_trampoline (MonoMethod *method)
264 invoke_remoting_trampoline (MonoInvocation *frame) {
265 MonoMethodMessage *msg;
266 MonoTransparentProxy *this;
267 MonoObject *res, *exc;
271 msg = arch_method_call_message_new (frame->method, frame->obj, frame->stack_args, NULL, NULL, NULL);
273 res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
276 mono_raise_exception ((MonoException *)exc);
278 /*arch_method_return_message_restore (method, &first_arg, res, out_args);*/
282 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
288 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
292 klass = obj->vtable->klass;
293 vtable = (MonoMethod **)obj->vtable->vtable;
295 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
296 return *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
299 g_assert (vtable [m->slot]);
301 return vtable [m->slot];
305 stackval_from_data (MonoType *type, stackval *result, char *data)
308 switch (type->type) {
309 case MONO_TYPE_OBJECT:
310 case MONO_TYPE_CLASS:
311 case MONO_TYPE_STRING:
312 case MONO_TYPE_ARRAY:
313 case MONO_TYPE_SZARRAY:
314 result->type = VAL_OBJ;
317 result->type = VAL_VALUETA;
320 result->data.p = *(gpointer*)data;
321 result->data.vt.klass = mono_class_from_mono_type (type);
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;
352 result->type = VAL_TP;
353 result->data.p = *(gpointer*)data;
356 result->type = VAL_I32;
357 result->data.i = *(guint32*)data;
360 result->type = VAL_DOUBLE;
361 result->data.f = *(float*)data;
365 result->type = VAL_I64;
366 result->data.l = *(gint64*)data;
369 result->type = VAL_DOUBLE;
370 result->data.f = *(double*)data;
372 case MONO_TYPE_STRING:
373 case MONO_TYPE_SZARRAY:
374 case MONO_TYPE_CLASS:
375 case MONO_TYPE_OBJECT:
376 case MONO_TYPE_ARRAY:
377 result->type = VAL_OBJ;
378 result->data.p = *(gpointer*)data;
379 result->data.vt.klass = mono_class_from_mono_type (type);
381 case MONO_TYPE_VALUETYPE:
382 if (type->data.klass->enumtype) {
383 return stackval_from_data (type->data.klass->enum_basetype, result, data);
385 result->type = VAL_VALUET;
386 result->data.vt.klass = type->data.klass;
387 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
391 g_warning ("got type 0x%02x", type->type);
392 g_assert_not_reached ();
397 stackval_to_data (MonoType *type, stackval *val, char *data)
400 gpointer *p = (gpointer*)data;
404 switch (type->type) {
407 guint8 *p = (guint8*)data;
411 case MONO_TYPE_BOOLEAN: {
412 guint8 *p = (guint8*)data;
413 *p = (val->data.i != 0);
418 case MONO_TYPE_CHAR: {
419 guint16 *p = (guint16*)data;
423 #if SIZEOF_VOID_P == 4
429 gint32 *p = (gint32*)data;
433 #if SIZEOF_VOID_P == 8
439 gint64 *p = (gint64*)data;
444 float *p = (float*)data;
449 double *p = (double*)data;
453 case MONO_TYPE_STRING:
454 case MONO_TYPE_SZARRAY:
455 case MONO_TYPE_CLASS:
456 case MONO_TYPE_OBJECT:
457 case MONO_TYPE_ARRAY:
458 case MONO_TYPE_PTR: {
459 gpointer *p = (gpointer*)data;
463 case MONO_TYPE_VALUETYPE:
464 if (type->data.klass->enumtype) {
465 return stackval_to_data (type->data.klass->enum_basetype, val, data);
467 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
471 g_warning ("got type %x", type->type);
472 g_assert_not_reached ();
477 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
480 guint32 *lower_bounds;
483 lengths = alloca (sizeof (guint32) * klass->rank * 2);
484 for (i = 0; i < sig->param_count; ++i) {
485 lengths [i] = values->data.i;
488 if (klass->rank == sig->param_count) {
489 /* Only lengths provided. */
492 /* lower bounds are first. */
493 lower_bounds = lengths;
494 lengths += klass->rank;
496 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
500 ves_array_set (MonoInvocation *frame)
502 stackval *sp = frame->stack_args;
506 gint32 i, t, pos, esize;
512 ac = o->vtable->klass;
514 g_assert (ac->rank >= 1);
517 if (ao->bounds != NULL) {
518 pos -= ao->bounds [0].lower_bound;
519 for (i = 1; i < ac->rank; i++) {
520 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
521 ao->bounds [i].length) {
522 g_warning ("wrong array index");
523 g_assert_not_reached ();
525 pos = pos*ao->bounds [i].length + sp [i].data.i -
526 ao->bounds [i].lower_bound;
530 esize = mono_array_element_size (ac);
531 ea = mono_array_addr_with_size (ao, esize, pos);
533 mt = frame->method->signature->params [ac->rank];
534 stackval_to_data (mt, &sp [ac->rank], ea);
538 ves_array_get (MonoInvocation *frame)
540 stackval *sp = frame->stack_args;
544 gint32 i, pos, esize;
550 ac = o->vtable->klass;
552 g_assert (ac->rank >= 1);
555 if (ao->bounds != NULL) {
556 pos -= ao->bounds [0].lower_bound;
557 for (i = 1; i < ac->rank; i++)
558 pos = pos*ao->bounds [i].length + sp [i].data.i -
559 ao->bounds [i].lower_bound;
562 esize = mono_array_element_size (ac);
563 ea = mono_array_addr_with_size (ao, esize, pos);
565 mt = frame->method->signature->ret;
566 stackval_from_data (mt, frame->retval, ea);
570 ves_array_element_address (MonoInvocation *frame)
572 stackval *sp = frame->stack_args;
576 gint32 i, pos, esize;
581 ac = o->vtable->klass;
583 g_assert (ac->rank >= 1);
586 if (ao->bounds != NULL) {
587 pos -= ao->bounds [0].lower_bound;
588 for (i = 1; i < ac->rank; i++)
589 pos = pos*ao->bounds [i].length + sp [i].data.i -
590 ao->bounds [i].lower_bound;
593 esize = mono_array_element_size (ac);
594 ea = mono_array_addr_with_size (ao, esize, pos);
596 frame->retval->type = VAL_TP;
597 frame->retval->data.p = ea;
601 ves_pinvoke_method (MonoInvocation *frame)
607 TlsSetValue (frame_thread_id, frame->args);
610 if (!frame->method->info)
611 frame->method->info = mono_create_trampoline (frame->method, 0);
612 func = (MonoPIFunc)frame->method->info;
615 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
616 * locals will point to the jmp_buf, while args will point to the previous
617 * MonoInvocation frame: this is needed to make exception searching work across
618 * managed/unmanaged boundaries.
620 frame->locals = (char*)&env;
621 frame->args = (char*)TlsGetValue (frame_thread_id);
622 TlsSetValue (frame_thread_id, frame);
624 func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
625 stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
626 TlsSetValue (frame_thread_id, frame->args);
631 * runtime specifies that the implementation of the method is automatically
632 * provided by the runtime and is primarily used for the methods of delegates.
635 ves_runtime_method (MonoInvocation *frame)
637 const char *name = frame->method->name;
638 MonoObject *obj = (MonoObject*)frame->obj;
639 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
642 mono_class_init (frame->method->klass);
644 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
645 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
647 mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
650 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
651 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
658 code = (guchar*)delegate->delegate.method_ptr;
659 if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
661 INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
662 ves_exec_method (&call);
666 method->addr = mono_create_trampoline (method, 1);
668 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
669 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p,
670 delegate->target, frame->stack_args);
671 stackval_from_data (frame->method->signature->ret, frame->retval,
672 (char*)&frame->retval->data.p);
674 g_assert_not_reached ();
677 delegate = delegate->prev;
681 if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0) && obj &&
682 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
683 MonoMethodMessage *msg;
684 MonoDelegate *async_callback;
687 MonoAsyncResult *ares;
689 im = mono_get_delegate_invoke (frame->method->klass);
690 msg = arch_method_call_message_new (frame->method, frame->obj, frame->stack_args, im, &async_callback, &state);
692 ares = mono_thread_pool_add (delegate, msg, async_callback, state);
693 frame->retval->data.p = ares;
696 if (*name == 'E' && (strcmp (name, "EndInvoke") == 0) && obj &&
697 mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
698 MonoAsyncResult *ares;
699 MonoMethodSignature *sig = frame->method->signature;
700 MonoMethodMessage *msg;
701 MonoObject *res, *exc;
704 msg = arch_method_call_message_new (frame->method, frame->obj, frame->stack_args, NULL, NULL, NULL);
706 ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
709 res = mono_thread_pool_finish (ares, &out_args, &exc);
712 char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
714 tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
716 ((MonoException*)exc)->stack_trace = mono_string_new (mono_object_domain (exc), tmp);
718 mono_raise_exception ((MonoException*)exc);
721 /* restore return value */
722 if (sig->ret->type != MONO_TYPE_VOID) {
724 /*arch_method_return_message_restore (method, &first_arg, res, out_args);*/
728 g_error ("Don't know how to exec runtime method %s.%s::%s",
729 frame->method->klass->name_space, frame->method->klass->name,
730 frame->method->name);
734 dump_stack (stackval *stack, stackval *sp)
737 GString *str = g_string_new ("");
740 return g_string_free (str, FALSE);
744 case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
745 case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
746 case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
748 if (!global_no_pointers)
749 g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
751 g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
754 MonoObject *obj = s->data.p;
755 if (global_no_pointers && obj && obj->vtable) {
756 MonoClass *klass = mono_object_class (obj);
757 if (klass == mono_defaults.string_class) {
758 char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
759 g_string_sprintfa (str, "[str:%s] ", utf8);
762 } else if (klass == mono_defaults.sbyte_class) {
763 g_string_sprintfa (str, "[b:%d] ",
764 *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
766 } else if (klass == mono_defaults.int16_class) {
767 g_string_sprintfa (str, "[b:%d] ",
768 *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
770 } else if (klass == mono_defaults.int32_class) {
771 g_string_sprintfa (str, "[b:%d] ",
772 *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
774 } else if (klass == mono_defaults.byte_class) {
775 g_string_sprintfa (str, "[b:%u] ",
776 *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
778 } else if (klass == mono_defaults.char_class
779 || klass == mono_defaults.uint16_class) {
780 g_string_sprintfa (str, "[b:%u] ",
781 *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
783 } else if (klass == mono_defaults.uint32_class) {
784 g_string_sprintfa (str, "[b:%u] ",
785 *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
787 } else if (klass == mono_defaults.int64_class) {
788 g_string_sprintfa (str, "[b:%lld] ",
789 *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
791 } else if (klass == mono_defaults.uint64_class) {
792 g_string_sprintfa (str, "[b:%llu] ",
793 *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
795 } else if (klass == mono_defaults.double_class) {
796 g_string_sprintfa (str, "[b:%0.5f] ",
797 *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
799 } else if (klass == mono_defaults.single_class) {
800 g_string_sprintfa (str, "[b:%0.5f] ",
801 *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
803 } else if (klass == mono_defaults.boolean_class) {
804 g_string_sprintfa (str, "[b:%s] ",
805 *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
813 if (!global_no_pointers)
814 g_string_sprintfa (str, "[%p] ", s->data.p);
816 g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
821 return g_string_free (str, FALSE);
825 dump_frame (MonoInvocation *inv)
827 GString *str = g_string_new ("");
830 for (i = 0; inv; inv = inv->parent, ++i) {
831 MonoClass *k = inv->method->klass;
834 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
835 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
839 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
841 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
844 opname = mono_opcode_names [codep];
845 codep = inv->ip - hd->code;
847 args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
848 g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
849 k->name_space, k->name, inv->method->name, args);
852 return g_string_free (str, FALSE);
855 static CRITICAL_SECTION metadata_lock;
858 INLINE_STRING_LENGTH = 1,
861 INLINE_TYPE_ELEMENT_TYPE
865 calc_offsets (MonoImage *image, MonoMethod *method)
867 int i, align, size, offset = 0;
868 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
869 MonoMethodSignature *signature = method->signature;
870 int hasthis = signature->hasthis;
871 register const unsigned char *ip, *end;
872 const MonoOpcode *opcode;
876 MonoDomain *domain = mono_domain_get ();
879 mono_profiler_method_jit (method); /* sort of... */
880 offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
881 for (i = 0; i < header->num_locals; ++i) {
882 size = mono_type_size (header->locals [i], &align);
884 offset &= ~(align - 1);
885 offsets [2 + i] = offset;
888 offsets [0] = offset;
891 offset += sizeof (gpointer) - 1;
892 offset &= ~(sizeof (gpointer) - 1);
893 offsets [2 + header->num_locals] = offset;
894 offset += sizeof (gpointer);
896 for (i = 0; i < signature->param_count; ++i) {
897 size = mono_type_size (signature->params [i], &align);
899 offset &= ~(align - 1);
900 offsets [2 + hasthis + header->num_locals + i] = offset;
903 offsets [1] = offset;
905 EnterCriticalSection (&metadata_lock);
906 /* intern the strings in the method. */
908 end = ip + header->code_size;
915 opcode = &mono_opcodes [i];
916 switch (opcode->argument) {
920 case MonoInlineString:
921 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
925 class = mono_class_get (image, read32 (ip + 1));
926 mono_class_init (class);
927 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
928 mono_class_vtable (domain, class);
931 case MonoInlineField:
932 token = read32 (ip + 1);
933 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
934 mono_field_from_memberref (image, token, &class);
936 class = mono_class_get (image,
937 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
939 mono_class_init (class);
940 mono_class_vtable (domain, class);
943 case MonoInlineMethod:
944 m = mono_get_method (image, read32 (ip + 1), NULL);
945 mono_class_init (m->klass);
946 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
947 mono_class_vtable (domain, m->klass);
952 case MonoShortInlineR:
954 case MonoInlineBrTarget:
960 case MonoShortInlineVar:
961 case MonoShortInlineI:
962 case MonoShortInlineBrTarget:
965 case MonoInlineSwitch: {
978 g_assert_not_reached ();
982 method->info = offsets;
985 * We store the inline info in addr, since it's unused for IL methods.
987 if (method->klass == mono_defaults.string_class) {
988 if (strcmp (method->name, "get_Length") == 0)
989 method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
990 } else if (method->klass == mono_defaults.array_class) {
991 if (strcmp (method->name, "get_Length") == 0)
992 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
993 else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
994 method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
995 } else if (method->klass == mono_defaults.monotype_class) {
996 if (strcmp (method->name, "GetElementType") == 0)
997 method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
999 LeaveCriticalSection (&metadata_lock);
1000 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
1003 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
1004 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
1006 #define ARG_POS(n) (args_pointers [(n)])
1007 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
1008 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
1010 #define THROW_EX(exception,ex_ip) \
1012 char *stack_trace; \
1013 frame->ip = (ex_ip); \
1014 stack_trace = dump_frame (frame); \
1015 frame->ex = (MonoException*)(exception); \
1016 frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
1017 g_free (stack_trace); \
1018 goto handle_exception; \
1021 typedef struct _vtallocation vtallocation;
1023 struct _vtallocation {
1026 char data [MONO_ZERO_LEN_ARRAY];
1030 * we don't use vtallocation->next, yet
1032 #define vt_alloc(vtype,sp) \
1033 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
1034 if (!(vtype)->byref) { \
1036 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
1037 if (!vtalloc || vtalloc->size <= size) { \
1038 vtalloc = alloca (sizeof (vtallocation) + size); \
1039 vtalloc->size = size; \
1040 g_assert (size < 10000); \
1042 (sp)->data.vt.vt = vtalloc->data; \
1045 (sp)->data.vt.klass = (vtype)->data.klass; \
1049 #define vt_free(sp) \
1051 if ((sp)->type == VAL_VALUET) { \
1052 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
1057 verify_method (MonoMethod *m)
1059 GSList *errors, *tmp;
1060 MonoVerifyInfo *info;
1062 errors = mono_method_verify (m, MONO_VERIFY_ALL);
1064 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
1065 for (tmp = errors; tmp; tmp = tmp->next) {
1067 g_print ("%s\n", info->message);
1071 mono_free_verify_list (errors);
1074 #define MYGUINT64_MAX 18446744073709551615UL
1075 #define MYGINT64_MAX 9223372036854775807LL
1076 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1078 #define MYGUINT32_MAX 4294967295U
1079 #define MYGINT32_MAX 2147483647
1080 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1082 #define CHECK_ADD_OVERFLOW(a,b) \
1083 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1084 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1086 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1087 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1089 #define CHECK_ADD_OVERFLOW64(a,b) \
1090 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1091 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1093 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1094 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1097 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1099 MonoInvocation frame;
1100 MonoObject *retval = NULL;
1101 MonoMethodSignature *sig = method->signature;
1102 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1103 int i, type, isobject = 0;
1106 stackval *args = alloca (sizeof (stackval) * sig->param_count);
1108 /* FIXME: Set frame for execption handling. */
1110 switch (sig->ret->type) {
1111 case MONO_TYPE_VOID:
1113 case MONO_TYPE_STRING:
1114 case MONO_TYPE_OBJECT:
1115 case MONO_TYPE_CLASS:
1116 case MONO_TYPE_ARRAY:
1117 case MONO_TYPE_SZARRAY:
1120 case MONO_TYPE_VALUETYPE:
1121 retval = mono_object_new (mono_domain_get (), klass);
1122 ret = ((char*)retval) + sizeof (MonoObject);
1123 if (!sig->ret->data.klass->enumtype)
1124 result.data.vt.vt = ret;
1127 retval = mono_object_new (mono_domain_get (), klass);
1128 ret = ((char*)retval) + sizeof (MonoObject);
1132 for (i = 0; i < sig->param_count; ++i) {
1133 if (sig->params [i]->byref) {
1134 args [i].type = VAL_POINTER;
1135 args [i].data.p = params [i];
1138 type = sig->params [i]->type;
1143 case MONO_TYPE_BOOLEAN:
1144 args [i].type = VAL_I32;
1145 args [i].data.i = *(MonoBoolean*)params [i];
1146 args [i].data.vt.klass = NULL;
1150 case MONO_TYPE_CHAR:
1151 args [i].type = VAL_I32;
1152 args [i].data.i = *(gint16*)params [i];
1153 args [i].data.vt.klass = NULL;
1155 #if SIZEOF_VOID_P == 4
1156 case MONO_TYPE_U: /* use VAL_POINTER? */
1161 args [i].type = VAL_I32;
1162 args [i].data.i = *(gint32*)params [i];
1163 args [i].data.vt.klass = NULL;
1165 #if SIZEOF_VOID_P == 8
1171 args [i].type = VAL_I64;
1172 args [i].data.l = *(gint64*)params [i];
1173 args [i].data.vt.klass = NULL;
1175 case MONO_TYPE_VALUETYPE:
1176 if (sig->params [i]->data.klass->enumtype) {
1177 type = sig->params [i]->data.klass->enum_basetype->type;
1180 g_warning ("generic valutype %s not handled in runtime invoke", sig->params [i]->data.klass->name);
1183 case MONO_TYPE_STRING:
1184 case MONO_TYPE_CLASS:
1185 case MONO_TYPE_ARRAY:
1186 case MONO_TYPE_SZARRAY:
1187 case MONO_TYPE_OBJECT:
1188 args [i].type = VAL_OBJ;
1189 args [i].data.p = params [i];
1190 args [i].data.vt.klass = NULL;
1193 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1197 INIT_FRAME(&frame,NULL,obj,args,&result,method);
1198 ves_exec_method (&frame);
1199 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1201 if (isobject || method->string_ctor)
1202 return result.data.p;
1203 stackval_to_data (sig->ret, &result, ret);
1208 * Need to optimize ALU ops when natural int == int32
1210 * IDEA: if we maintain a stack of ip, sp to be checked
1211 * in the return opcode, we could inline simple methods that don't
1212 * use the stack or local variables....
1214 * The {,.S} versions of many opcodes can/should be merged to reduce code
1219 ves_exec_method (MonoInvocation *frame)
1221 MonoDomain *domain = mono_domain_get ();
1222 MonoInvocation child_frame;
1223 MonoMethodHeader *header;
1224 MonoMethodSignature *signature;
1226 GSList *finally_ips = NULL;
1227 const unsigned char *endfinally_ip;
1228 register const unsigned char *ip;
1229 register stackval *sp;
1230 void **args_pointers;
1232 gint il_ins_count = -1;
1233 gint tracing = global_tracing;
1234 unsigned char tail_recursion = 0;
1235 unsigned char unaligned_address = 0;
1236 unsigned char volatile_address = 0;
1237 vtallocation *vtalloc = NULL;
1240 signature = frame->method->signature;
1244 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1245 if (!frame->method->addr) {
1246 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1250 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1251 ves_pinvoke_method (frame);
1253 ICallMethod icall = (ICallMethod)frame->method->addr;
1257 goto handle_exception;
1262 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1263 if (!frame->method->addr) {
1264 if (!mono_lookup_pinvoke_call (frame->method)) {
1265 frame->ex = (MonoException*)mono_get_exception_missing_method ();
1270 ves_pinvoke_method (frame);
1272 goto handle_exception;
1277 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
1278 ves_runtime_method (frame);
1280 goto handle_exception;
1285 /*verify_method (frame->method);*/
1287 header = ((MonoMethodNormal *)frame->method)->header;
1288 image = frame->method->klass->image;
1290 if (!frame->method->info)
1291 calc_offsets (image, frame->method);
1292 offsets = frame->method->info;
1295 * with alloca we get the expected huge performance gain
1296 * stackval *stack = g_new0(stackval, header->max_stack);
1298 g_assert (header->max_stack < 10000);
1299 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
1301 if (header->num_locals) {
1302 g_assert (offsets [0] < 10000);
1303 frame->locals = alloca (offsets [0]);
1305 * yes, we do it unconditionally, because it needs to be done for
1306 * some cases anyway and checking for that would be even slower.
1308 memset (frame->locals, 0, offsets [0]);
1311 * Copy args from stack_args to args.
1313 if (signature->param_count || signature->hasthis) {
1315 int has_this = signature->hasthis;
1317 g_assert (offsets [1] < 10000);
1318 frame->args = alloca (offsets [1]);
1319 g_assert ((signature->param_count + has_this) < 1000);
1320 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1323 this_arg = args_pointers [0] = frame->args;
1324 *this_arg = frame->obj;
1326 for (i = 0; i < signature->param_count; ++i) {
1327 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1328 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this]);
1332 child_frame.parent = frame;
1333 frame->child = &child_frame;
1340 * using while (ip < end) may result in a 15% performance drop,
1341 * but it may be useful for debug
1345 /*g_assert (sp >= stack);*/
1349 char *ins, *discode;
1350 if (sp > frame->stack) {
1351 ins = dump_stack (frame->stack, sp);
1353 ins = g_strdup ("");
1356 discode = mono_disasm_code_one (NULL, frame->method, ip);
1357 discode [strlen (discode) - 1] = 0; /* no \n */
1358 g_print ("(%d) %-29s %s\n", GetCurrentThreadId(), discode, ins);
1362 if (il_ins_count > 0)
1363 if (!(--il_ins_count))
1373 G_BREAKPOINT (); /* this is not portable... */
1378 CASE (CEE_LDARG_3) {
1379 int n = (*ip)-CEE_LDARG_0;
1381 vt_alloc (ARG_TYPE (signature, n), sp);
1382 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
1389 CASE (CEE_LDLOC_3) {
1390 int n = (*ip)-CEE_LDLOC_0;
1392 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1394 sp->data.i = *(gint32*) LOCAL_POS (n);
1398 vt_alloc (LOCAL_TYPE (header, n), sp);
1399 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1407 CASE (CEE_STLOC_3) {
1408 int n = (*ip)-CEE_STLOC_0;
1411 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1412 gint32 *p = (gint32*)LOCAL_POS (n);
1416 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1423 vt_alloc (ARG_TYPE (signature, *ip), sp);
1424 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1428 CASE (CEE_LDARGA_S) {
1433 t = ARG_TYPE (signature, *ip);
1434 c = mono_class_from_mono_type (t);
1435 sp->data.vt.klass = c;
1436 sp->data.vt.vt = ARG_POS (*ip);
1439 sp->type = VAL_VALUETA;
1450 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1456 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1457 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1461 CASE (CEE_LDLOCA_S) {
1466 t = LOCAL_TYPE (header, *ip);
1467 c = mono_class_from_mono_type (t);
1468 sp->data.vt.klass = c;
1469 sp->data.p = LOCAL_POS (*ip);
1472 sp->type = VAL_VALUETA;
1483 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1491 sp->data.vt.klass = NULL;
1494 CASE (CEE_LDC_I4_M1)
1510 sp->data.i = (*ip) - CEE_LDC_I4_0;
1517 sp->data.i = *(const gint8 *)ip;
1524 sp->data.i = read32 (ip);
1531 sp->data.l = read64 (ip);
1538 sp->type = VAL_DOUBLE;
1547 sp->type = VAL_DOUBLE;
1548 readr8(ip, &sp->data.f);
1552 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1554 if (sp [-1].type == VAL_VALUET) {
1555 MonoClass *c = sp [-1].data.vt.klass;
1556 vt_alloc (&c->byval_arg, sp);
1557 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1569 CASE (CEE_JMP) ves_abort(); BREAK;
1570 CASE (CEE_CALLVIRT) /* Fall through */
1571 CASE (CEE_CALLI) /* Fall through */
1573 MonoMethodSignature *csignature;
1575 stackval *endsp = sp;
1577 int virtual = *ip == CEE_CALLVIRT;
1578 int calli = *ip == CEE_CALLI;
1581 * We ignore tail recursion for now.
1588 token = read32 (ip);
1592 unsigned char *code;
1595 if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
1596 child_frame.method = ji->method;
1597 csignature = child_frame.method->signature;
1599 /* fixme: native code ? */
1600 g_assert_not_reached ();
1603 child_frame.method = mono_get_method (image, token, NULL);
1604 if (!child_frame.method)
1605 THROW_EX (mono_get_exception_missing_method (), ip -5);
1606 csignature = child_frame.method->signature;
1608 stackval *this_arg = &sp [-csignature->param_count-1];
1609 if (!this_arg->data.p)
1610 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1611 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1612 if (!child_frame.method)
1613 THROW_EX (mono_get_exception_missing_method (), ip -5);
1616 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1617 /* decrement by the actual number of args */
1618 if (csignature->param_count) {
1619 sp -= csignature->param_count;
1620 child_frame.stack_args = sp;
1622 child_frame.stack_args = NULL;
1624 if (csignature->hasthis) {
1625 g_assert (sp >= frame->stack);
1628 * It may also be a TP from LD(S)FLDA
1629 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1631 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1632 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1634 child_frame.obj = sp->data.p;
1636 child_frame.obj = NULL;
1638 if (csignature->ret->type != MONO_TYPE_VOID) {
1639 vt_alloc (csignature->ret, &retval);
1640 child_frame.retval = &retval;
1642 child_frame.retval = NULL;
1645 child_frame.ex = NULL;
1646 child_frame.ex_handler = NULL;
1648 if (csignature->hasthis && sp->type == VAL_OBJ &&
1649 ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
1650 /* implement remoting */
1651 invoke_remoting_trampoline (&child_frame);
1653 switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
1654 case INLINE_STRING_LENGTH:
1655 retval.type = VAL_I32;
1656 retval.data.i = ((MonoString*)sp->data.p)->length;
1657 /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
1659 case INLINE_ARRAY_LENGTH:
1660 retval.type = VAL_I32;
1661 retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
1663 case INLINE_ARRAY_RANK:
1664 retval.type = VAL_I32;
1665 retval.data.i = mono_object_class (sp->data.p)->rank;
1667 case INLINE_TYPE_ELEMENT_TYPE:
1668 retval.type = VAL_OBJ;
1670 MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
1671 retval.data.vt.klass = NULL;
1672 if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
1673 retval.data.p = mono_type_get_object (domain, c->enum_basetype);
1674 else if (c->element_class)
1675 retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
1677 retval.data.p = NULL;
1681 ves_exec_method (&child_frame);
1685 while (endsp > sp) {
1690 if (child_frame.ex) {
1692 * An exception occurred, need to run finally, fault and catch handlers..
1694 frame->ex = child_frame.ex;
1695 goto handle_finally;
1698 /* need to handle typedbyref ... */
1699 if (csignature->ret->type != MONO_TYPE_VOID) {
1706 if (signature->ret->type != MONO_TYPE_VOID) {
1708 if (sp->type == VAL_VALUET) {
1709 /* the caller has already allocated the memory */
1710 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1713 *frame->retval = *sp;
1716 if (sp > frame->stack)
1717 g_warning ("more values on stack: %d", sp-frame->stack);
1721 CASE (CEE_BR_S) /* Fall through */
1723 if (*ip == CEE_BR) {
1725 ip += (gint32) read32(ip);
1729 ip += (signed char) *ip;
1733 CASE (CEE_BRFALSE) /* Fall through */
1734 CASE (CEE_BRFALSE_S) {
1736 int near_jump = *ip == CEE_BRFALSE_S;
1740 case VAL_I32: result = sp->data.i == 0; break;
1741 case VAL_I64: result = sp->data.l == 0; break;
1742 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1743 default: result = sp->data.p == NULL; break;
1747 ip += (signed char)*ip;
1749 ip += (gint32) read32 (ip);
1751 ip += near_jump ? 1: 4;
1754 CASE (CEE_BRTRUE) /* Fall through */
1755 CASE (CEE_BRTRUE_S) {
1757 int near_jump = *ip == CEE_BRTRUE_S;
1761 case VAL_I32: result = sp->data.i != 0; break;
1762 case VAL_I64: result = sp->data.l != 0; break;
1763 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1764 default: result = sp->data.p != NULL; break;
1768 ip += (signed char)*ip;
1770 ip += (gint32) read32 (ip);
1772 ip += near_jump ? 1: 4;
1775 CASE (CEE_BEQ) /* Fall through */
1778 int near_jump = *ip == CEE_BEQ_S;
1781 if (sp->type == VAL_I32)
1782 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1783 else if (sp->type == VAL_I64)
1784 result = sp [0].data.l == sp [1].data.l;
1785 else if (sp->type == VAL_DOUBLE)
1786 result = sp [0].data.f == sp [1].data.f;
1788 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1791 ip += (signed char)*ip;
1793 ip += (gint32) read32 (ip);
1795 ip += near_jump ? 1: 4;
1798 CASE (CEE_BGE) /* Fall through */
1801 int near_jump = *ip == CEE_BGE_S;
1804 if (sp->type == VAL_I32)
1805 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1806 else if (sp->type == VAL_I64)
1807 result = sp [0].data.l >= sp [1].data.l;
1808 else if (sp->type == VAL_DOUBLE)
1809 result = sp [0].data.f >= sp [1].data.f;
1811 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1814 ip += (signed char)*ip;
1816 ip += (gint32) read32 (ip);
1818 ip += near_jump ? 1: 4;
1821 CASE (CEE_BGT) /* Fall through */
1824 int near_jump = *ip == CEE_BGT_S;
1827 if (sp->type == VAL_I32)
1828 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1829 else if (sp->type == VAL_I64)
1830 result = sp [0].data.l > sp [1].data.l;
1831 else if (sp->type == VAL_DOUBLE)
1832 result = sp [0].data.f > sp [1].data.f;
1834 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1837 ip += (signed char)*ip;
1839 ip += (gint32) read32 (ip);
1841 ip += near_jump ? 1: 4;
1844 CASE (CEE_BLT) /* Fall through */
1847 int near_jump = *ip == CEE_BLT_S;
1850 if (sp->type == VAL_I32)
1851 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1852 else if (sp->type == VAL_I64)
1853 result = sp[0].data.l < sp[1].data.l;
1854 else if (sp->type == VAL_DOUBLE)
1855 result = sp[0].data.f < sp[1].data.f;
1857 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1860 ip += 1 + (signed char)*ip;
1862 ip += 4 + (gint32) read32 (ip);
1865 ip += near_jump ? 1: 4;
1869 CASE (CEE_BLE) /* fall through */
1872 int near_jump = *ip == CEE_BLE_S;
1876 if (sp->type == VAL_I32)
1877 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1878 else if (sp->type == VAL_I64)
1879 result = sp [0].data.l <= sp [1].data.l;
1880 else if (sp->type == VAL_DOUBLE)
1881 result = sp [0].data.f <= sp [1].data.f;
1884 * FIXME: here and in other places GET_NATI on the left side
1885 * _will_ be wrong when we change the macro to work on 64 bits
1888 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1892 ip += (signed char)*ip;
1894 ip += (gint32) read32 (ip);
1896 ip += near_jump ? 1: 4;
1899 CASE (CEE_BNE_UN) /* Fall through */
1900 CASE (CEE_BNE_UN_S) {
1902 int near_jump = *ip == CEE_BNE_UN_S;
1905 if (sp->type == VAL_I32)
1906 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1907 else if (sp->type == VAL_I64)
1908 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1909 else if (sp->type == VAL_DOUBLE)
1910 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1911 (sp [0].data.f != sp [1].data.f);
1913 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1916 ip += (signed char)*ip;
1918 ip += (gint32) read32 (ip);
1920 ip += near_jump ? 1: 4;
1923 CASE (CEE_BGE_UN) /* Fall through */
1924 CASE (CEE_BGE_UN_S) {
1926 int near_jump = *ip == CEE_BGE_UN_S;
1929 if (sp->type == VAL_I32)
1930 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1931 else if (sp->type == VAL_I64)
1932 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1933 else if (sp->type == VAL_DOUBLE)
1934 result = !isless (sp [0].data.f,sp [1].data.f);
1936 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1939 ip += (signed char)*ip;
1941 ip += (gint32) read32 (ip);
1943 ip += near_jump ? 1: 4;
1946 CASE (CEE_BGT_UN) /* Fall through */
1947 CASE (CEE_BGT_UN_S) {
1949 int near_jump = *ip == CEE_BGT_UN_S;
1952 if (sp->type == VAL_I32)
1953 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1954 else if (sp->type == VAL_I64)
1955 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1956 else if (sp->type == VAL_DOUBLE)
1957 result = isgreater (sp [0].data.f, sp [1].data.f);
1959 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1962 ip += (signed char)*ip;
1964 ip += (gint32) read32 (ip);
1966 ip += near_jump ? 1: 4;
1969 CASE (CEE_BLE_UN) /* Fall through */
1970 CASE (CEE_BLE_UN_S) {
1972 int near_jump = *ip == CEE_BLE_UN_S;
1975 if (sp->type == VAL_I32)
1976 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1977 else if (sp->type == VAL_I64)
1978 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1979 else if (sp->type == VAL_DOUBLE)
1980 result = islessequal (sp [0].data.f, sp [1].data.f);
1982 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1985 ip += (signed char)*ip;
1987 ip += (gint32) read32 (ip);
1989 ip += near_jump ? 1: 4;
1992 CASE (CEE_BLT_UN) /* Fall through */
1993 CASE (CEE_BLT_UN_S) {
1995 int near_jump = *ip == CEE_BLT_UN_S;
1998 if (sp->type == VAL_I32)
1999 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
2000 else if (sp->type == VAL_I64)
2001 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
2002 else if (sp->type == VAL_DOUBLE)
2003 result = isunordered (sp [0].data.f, sp [1].data.f) ||
2004 (sp [0].data.f < sp [1].data.f);
2006 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
2009 ip += (signed char)*ip;
2011 ip += (gint32) read32 (ip);
2013 ip += near_jump ? 1: 4;
2018 const unsigned char *st;
2022 st = ip + sizeof (gint32) * n;
2024 if ((guint32)sp->data.i < n) {
2026 ip += sizeof (gint32) * (guint32)sp->data.i;
2027 offset = read32 (ip);
2036 sp[-1].type = VAL_I32;
2037 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2041 sp[-1].type = VAL_I32;
2042 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2046 sp[-1].type = VAL_I32;
2047 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2051 sp[-1].type = VAL_I32;
2052 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2054 CASE (CEE_LDIND_I4) /* Fall through */
2057 sp[-1].type = VAL_I32;
2058 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2062 sp[-1].type = VAL_I64;
2063 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2067 sp[-1].type = VAL_NATI;
2068 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2072 sp[-1].type = VAL_DOUBLE;
2073 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2077 sp[-1].type = VAL_DOUBLE;
2078 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2080 CASE (CEE_LDIND_REF)
2082 sp[-1].type = VAL_OBJ;
2083 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2084 sp[-1].data.vt.klass = NULL;
2086 CASE (CEE_STIND_REF) {
2094 CASE (CEE_STIND_I1) {
2099 *p = (gint8)sp[1].data.i;
2102 CASE (CEE_STIND_I2) {
2107 *p = (gint16)sp[1].data.i;
2110 CASE (CEE_STIND_I4) {
2118 CASE (CEE_STIND_I) {
2123 *p = (mono_i)sp[1].data.p;
2126 CASE (CEE_STIND_I8) {
2134 CASE (CEE_STIND_R4) {
2139 *p = (gfloat)sp[1].data.f;
2142 CASE (CEE_STIND_R8) {
2153 /* should probably consider the pointers as unsigned */
2154 if (sp->type == VAL_I32)
2155 sp [-1].data.i += GET_NATI (sp [0]);
2156 else if (sp->type == VAL_I64)
2157 sp [-1].data.l += sp [0].data.l;
2158 else if (sp->type == VAL_DOUBLE)
2159 sp [-1].data.f += sp [0].data.f;
2161 char *p = sp [-1].data.p;
2162 p += GET_NATI (sp [0]);
2169 /* should probably consider the pointers as unsigned */
2170 if (sp->type == VAL_I32)
2171 sp [-1].data.i -= GET_NATI (sp [0]);
2172 else if (sp->type == VAL_I64)
2173 sp [-1].data.l -= sp [0].data.l;
2174 else if (sp->type == VAL_DOUBLE)
2175 sp [-1].data.f -= sp [0].data.f;
2177 char *p = sp [-1].data.p;
2178 p -= GET_NATI (sp [0]);
2185 if (sp->type == VAL_I32)
2186 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
2187 else if (sp->type == VAL_I64)
2188 sp [-1].data.l *= sp [0].data.l;
2189 else if (sp->type == VAL_DOUBLE)
2190 sp [-1].data.f *= sp [0].data.f;
2195 if (sp->type == VAL_I32) {
2196 if (GET_NATI (sp [0]) == 0)
2197 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2198 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
2199 } else if (sp->type == VAL_I64) {
2200 if (sp [0].data.l == 0)
2201 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2202 sp [-1].data.l /= sp [0].data.l;
2203 } else if (sp->type == VAL_DOUBLE) {
2204 /* set NaN is divisor is 0.0 */
2205 sp [-1].data.f /= sp [0].data.f;
2211 if (sp->type == VAL_I32) {
2213 if (GET_NATI (sp [0]) == 0)
2214 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2215 val = sp [-1].data.i;
2216 val /= (guint32)GET_NATI (sp [0]);
2217 sp [-1].data.i = val;
2218 } else if (sp->type == VAL_I64) {
2220 if (sp [0].data.l == 0)
2221 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2222 val = sp [-1].data.l;
2223 val /= (guint64)sp [0].data.l;
2224 sp [-1].data.l = val;
2225 } else if (sp->type == VAL_NATI) {
2227 if (GET_NATI (sp [0]) == 0)
2228 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2229 val = (mono_u)sp [-1].data.p;
2230 val /= (mono_u)sp [0].data.p;
2231 sp [-1].data.p = (gpointer)val;
2237 if (sp->type == VAL_I32) {
2238 if (GET_NATI (sp [0]) == 0)
2239 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2240 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
2241 } else if (sp->type == VAL_I64) {
2242 if (sp [0].data.l == 0)
2243 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2244 sp [-1].data.l %= sp [0].data.l;
2245 } else if (sp->type == VAL_DOUBLE) {
2246 /* FIXME: what do we actually do here? */
2247 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2249 if (GET_NATI (sp [0]) == 0)
2250 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2251 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
2257 if (sp->type == VAL_I32) {
2258 if (GET_NATI (sp [0]) == 0)
2259 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2260 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
2261 } else if (sp->type == VAL_I64) {
2262 if (sp [0].data.l == 0)
2263 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2264 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
2265 } else if (sp->type == VAL_DOUBLE) {
2266 /* unspecified behaviour according to the spec */
2268 if (GET_NATI (sp [0]) == 0)
2269 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
2270 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
2276 if (sp->type == VAL_I32)
2277 sp [-1].data.i &= GET_NATI (sp [0]);
2278 else if (sp->type == VAL_I64)
2279 sp [-1].data.l &= sp [0].data.l;
2281 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
2286 if (sp->type == VAL_I32)
2287 sp [-1].data.i |= GET_NATI (sp [0]);
2288 else if (sp->type == VAL_I64)
2289 sp [-1].data.l |= sp [0].data.l;
2291 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
2296 if (sp->type == VAL_I32)
2297 sp [-1].data.i ^= GET_NATI (sp [0]);
2298 else if (sp->type == VAL_I64)
2299 sp [-1].data.l ^= sp [0].data.l;
2301 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
2306 if (sp [-1].type == VAL_I32)
2307 sp [-1].data.i <<= GET_NATI (sp [0]);
2308 else if (sp [-1].type == VAL_I64)
2309 sp [-1].data.l <<= GET_NATI (sp [0]);
2311 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
2316 if (sp [-1].type == VAL_I32)
2317 sp [-1].data.i >>= GET_NATI (sp [0]);
2318 else if (sp [-1].type == VAL_I64)
2319 sp [-1].data.l >>= GET_NATI (sp [0]);
2321 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2326 if (sp [-1].type == VAL_I32)
2327 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
2328 else if (sp [-1].type == VAL_I64)
2329 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
2331 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
2336 if (sp->type == VAL_I32)
2337 sp->data.i = - sp->data.i;
2338 else if (sp->type == VAL_I64)
2339 sp->data.l = - sp->data.l;
2340 else if (sp->type == VAL_DOUBLE)
2341 sp->data.f = - sp->data.f;
2342 else if (sp->type == VAL_NATI)
2343 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
2349 if (sp->type == VAL_I32)
2350 sp->data.i = ~ sp->data.i;
2351 else if (sp->type == VAL_I64)
2352 sp->data.l = ~ sp->data.l;
2353 else if (sp->type == VAL_NATI)
2354 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2357 CASE (CEE_CONV_U1) /* fall through */
2358 CASE (CEE_CONV_I1) {
2360 switch (sp [-1].type) {
2362 sp [-1].data.i = (gint8)sp [-1].data.f;
2365 sp [-1].data.i = (gint8)sp [-1].data.l;
2370 sp [-1].data.i = (gint8)sp [-1].data.i;
2373 sp [-1].data.i = (gint8)sp [-1].data.nati;
2376 sp [-1].type = VAL_I32;
2379 CASE (CEE_CONV_U2) /* fall through */
2380 CASE (CEE_CONV_I2) {
2382 switch (sp [-1].type) {
2384 sp [-1].data.i = (gint16)sp [-1].data.f;
2387 sp [-1].data.i = (gint16)sp [-1].data.l;
2392 sp [-1].data.i = (gint16)sp [-1].data.i;
2395 sp [-1].data.i = (gint16)sp [-1].data.nati;
2398 sp [-1].type = VAL_I32;
2401 CASE (CEE_CONV_U4) /* Fall through */
2402 #if SIZEOF_VOID_P == 4
2403 CASE (CEE_CONV_I) /* Fall through */
2404 CASE (CEE_CONV_U) /* Fall through */
2406 CASE (CEE_CONV_I4) {
2408 switch (sp [-1].type) {
2410 sp [-1].data.i = (gint32)sp [-1].data.f;
2413 sp [-1].data.i = (gint32)sp [-1].data.l;
2420 sp [-1].data.i = (gint32)sp [-1].data.p;
2423 sp [-1].type = VAL_I32;
2426 #if SIZEOF_VOID_P == 8
2427 CASE (CEE_CONV_I) /* Fall through */
2431 switch (sp [-1].type) {
2433 sp [-1].data.l = (gint64)sp [-1].data.f;
2440 sp [-1].data.l = (gint64)sp [-1].data.i;
2443 sp [-1].data.l = (gint64)sp [-1].data.nati;
2446 sp [-1].type = VAL_I64;
2448 CASE (CEE_CONV_R4) /* Fall through */
2449 CASE (CEE_CONV_R8) {
2451 switch (sp [-1].type) {
2453 sp [-1].data.f = (double)sp [-1].data.f;
2456 sp [-1].data.f = (double)sp [-1].data.l;
2461 sp [-1].data.f = (double)sp [-1].data.i;
2464 sp [-1].data.f = (double)sp [-1].data.nati;
2467 sp [-1].type = VAL_DOUBLE;
2470 #if SIZEOF_VOID_P == 8
2471 CASE (CEE_CONV_U) /* Fall through */
2476 switch (sp [-1].type){
2478 sp [-1].data.l = (guint64)sp [-1].data.f;
2485 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
2488 sp [-1].data.l = (guint64) sp [-1].data.nati;
2491 sp [-1].type = VAL_I64;
2496 vtklass = mono_class_get (image, read32 (ip));
2499 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2508 token = read32 (ip);
2510 c = mono_class_get (image, token);
2511 addr = sp [-1].data.vt.vt;
2512 vt_alloc (&c->byval_arg, &sp [-1]);
2513 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2521 str_index = mono_metadata_token_index (read32 (ip));
2524 o = (MonoObject*)mono_ldstr (domain, image, str_index);
2527 sp->data.vt.klass = NULL;
2534 MonoClass *newobj_class;
2535 MonoMethodSignature *csig;
2536 stackval valuetype_this;
2537 stackval *endsp = sp;
2544 token = read32 (ip);
2547 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2548 THROW_EX (mono_get_exception_missing_method (), ip -5);
2550 csig = child_frame.method->signature;
2551 newobj_class = child_frame.method->klass;
2552 /*if (profiling_classes) {
2553 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2555 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2559 if (newobj_class->parent == mono_defaults.array_class) {
2560 sp -= csig->param_count;
2561 o = ves_array_create (domain, newobj_class, csig, sp);
2562 goto array_constructed;
2566 * First arg is the object.
2568 if (newobj_class->valuetype) {
2570 vt_alloc (&newobj_class->byval_arg, &valuetype_this);
2571 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2572 zero = valuetype_this.data.vt.vt;
2573 child_frame.obj = valuetype_this.data.vt.vt;
2575 memset (&valuetype_this, 0, sizeof (stackval));
2576 zero = &valuetype_this;
2577 child_frame.obj = &valuetype_this;
2579 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero);
2581 if (newobj_class != mono_defaults.string_class) {
2582 o = mono_object_new (domain, newobj_class);
2583 child_frame.obj = o;
2585 child_frame.retval = &retval;
2589 if (csig->param_count) {
2590 sp -= csig->param_count;
2591 child_frame.stack_args = sp;
2593 child_frame.stack_args = NULL;
2596 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2598 child_frame.ex = NULL;
2599 child_frame.ex_handler = NULL;
2601 ves_exec_method (&child_frame);
2603 while (endsp > sp) {
2608 if (child_frame.ex) {
2610 * An exception occurred, need to run finally, fault and catch handlers..
2612 frame->ex = child_frame.ex;
2613 goto handle_finally;
2616 * a constructor returns void, but we need to return the object we created
2619 if (newobj_class->valuetype && !newobj_class->enumtype) {
2620 *sp = valuetype_this;
2621 } else if (newobj_class == mono_defaults.string_class) {
2626 sp->data.vt.klass = newobj_class;
2631 CASE (CEE_CASTCLASS) /* Fall through */
2635 MonoClass *c , *oclass;
2637 int do_isinst = *ip == CEE_ISINST;
2638 gboolean found = FALSE;
2641 token = read32 (ip);
2642 c = mono_class_get (image, token);
2644 g_assert (sp [-1].type == VAL_OBJ);
2646 if ((o = sp [-1].data.p)) {
2651 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2652 if ((c->interface_id <= oclass->max_interface_id) &&
2653 vt->interface_offsets [c->interface_id])
2656 if (oclass == mono_defaults.transparent_proxy_class) {
2657 /* fixme: add check for IRemotingTypeInfo */
2658 MonoRealProxy *rp = ((MonoTransparentProxy *)o)->rp;
2660 type = rp->class_to_proxy->type;
2661 oclass = mono_class_from_mono_type (type);
2663 /* handle array casts */
2664 if (oclass->rank && oclass->rank == c->rank) {
2665 if ((oclass->element_class->baseval - c->element_class->baseval) <= c->element_class->diffval) {
2666 sp [-1].data.vt.klass = c;
2669 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2670 sp [-1].data.vt.klass = c;
2677 sp [-1].data.p = NULL;
2678 sp [-1].data.vt.klass = NULL;
2680 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2686 CASE (CEE_CONV_R_UN)
2687 switch (sp [-1].type) {
2691 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2696 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2699 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2702 sp [-1].type = VAL_DOUBLE;
2705 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2712 token = read32 (ip);
2714 c = mono_class_get (image, token);
2718 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2720 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2721 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2723 sp [-1].type = VAL_MP;
2724 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2731 frame->ex_handler = NULL;
2733 sp->data.p = mono_get_exception_null_reference ();
2734 THROW_EX (sp->data.p, ip);
2736 CASE (CEE_LDFLDA) /* Fall through */
2739 MonoClassField *field;
2740 guint32 token, offset;
2741 int load_addr = *ip == CEE_LDFLDA;
2743 if (!sp [-1].data.p)
2744 THROW_EX (mono_get_exception_null_reference (), ip);
2747 token = read32 (ip);
2750 if (sp [-1].type == VAL_OBJ) {
2751 obj = sp [-1].data.p;
2752 /* if we access a field from our parent and the parent was
2753 * defined in another assembly, we get a memberref.
2755 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2756 field = mono_field_from_memberref (image, token, NULL);
2758 field = mono_class_get_field (obj->vtable->klass, token);
2759 offset = field->offset;
2760 } else { /* valuetype */
2761 /*g_assert (sp [-1].type == VAL_VALUETA); */
2762 obj = sp [-1].data.vt.vt;
2763 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2764 offset = field->offset - sizeof (MonoObject);
2767 sp [-1].type = VAL_TP;
2768 sp [-1].data.p = (char*)obj + offset;
2769 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2771 vt_alloc (field->type, &sp [-1]);
2772 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2779 MonoClassField *field;
2780 guint32 token, offset;
2785 THROW_EX (mono_get_exception_null_reference (), ip);
2788 token = read32 (ip);
2791 if (sp [0].type == VAL_OBJ) {
2792 obj = sp [0].data.p;
2793 /* if we access a field from our parent and the parent was
2794 * defined in another assembly, we get a memberref.
2796 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
2797 field = mono_field_from_memberref (image, token, NULL);
2799 field = mono_class_get_field (obj->vtable->klass, token);
2800 offset = field->offset;
2801 } else { /* valuetype */
2802 /*g_assert (sp->type == VAL_VALUETA); */
2803 obj = sp [0].data.vt.vt;
2804 field = mono_class_get_field (sp [0].data.vt.klass, token);
2805 offset = field->offset - sizeof (MonoObject);
2808 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2812 CASE (CEE_LDSFLD) /* Fall through */
2813 CASE (CEE_LDSFLDA) {
2816 MonoClassField *field;
2818 int load_addr = *ip == CEE_LDSFLDA;
2822 token = read32 (ip);
2825 /* need to handle fieldrefs */
2826 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2827 field = mono_field_from_memberref (image, token, &klass);
2829 klass = mono_class_get (image,
2830 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2831 field = mono_class_get_field (klass, token);
2835 vt = mono_class_vtable (domain, klass);
2836 addr = (char*)(vt->data) + field->offset;
2841 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2843 vt_alloc (field->type, sp);
2844 stackval_from_data (field->type, sp, addr);
2852 MonoClassField *field;
2857 token = read32 (ip);
2861 /* need to handle fieldrefs */
2862 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2863 field = mono_field_from_memberref (image, token, &klass);
2865 klass = mono_class_get (image,
2866 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2867 field = mono_class_get_field (klass, token);
2871 vt = mono_class_vtable (domain, klass);
2872 addr = (char*)(vt->data) + field->offset;
2874 stackval_to_data (field->type, sp, addr);
2881 vtklass = mono_class_get (image, read32 (ip));
2884 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2887 #if SIZEOF_VOID_P == 8
2888 CASE (CEE_CONV_OVF_I_UN)
2890 CASE (CEE_CONV_OVF_I8_UN) {
2891 switch (sp [-1].type) {
2893 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2894 THROW_EX (mono_get_exception_overflow (), ip);
2895 sp [-1].data.l = (guint64)sp [-1].data.f;
2902 /* Can't overflow */
2903 sp [-1].data.l = (guint64)sp [-1].data.i;
2906 sp [-1].data.l = (guint64)sp [-1].data.nati;
2909 sp [-1].type = VAL_I64;
2913 #if SIZEOF_VOID_P == 8
2914 CASE (CEE_CONV_OVF_U_UN)
2916 CASE (CEE_CONV_OVF_U8_UN) {
2917 switch (sp [-1].type) {
2919 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
2920 THROW_EX (mono_get_exception_overflow (), ip);
2921 sp [-1].data.l = (guint64)sp [-1].data.f;
2929 /* Can't overflow */
2930 sp [-1].data.l = (guint64)sp [-1].data.i;
2933 /* Can't overflow */
2934 sp [-1].data.l = (guint64)sp [-1].data.nati;
2937 sp [-1].type = VAL_I64;
2941 #if SIZEOF_VOID_P == 4
2942 CASE (CEE_CONV_OVF_I_UN)
2943 CASE (CEE_CONV_OVF_U_UN)
2945 CASE (CEE_CONV_OVF_I1_UN)
2946 CASE (CEE_CONV_OVF_I2_UN)
2947 CASE (CEE_CONV_OVF_I4_UN)
2948 CASE (CEE_CONV_OVF_U1_UN)
2949 CASE (CEE_CONV_OVF_U2_UN)
2950 CASE (CEE_CONV_OVF_U4_UN) {
2952 switch (sp [-1].type) {
2954 value = (guint64)sp [-1].data.f;
2957 value = (guint64)sp [-1].data.l;
2962 value = (guint64)sp [-1].data.i;
2965 value = (guint64)sp [-1].data.nati;
2969 case CEE_CONV_OVF_I1_UN:
2971 THROW_EX (mono_get_exception_overflow (), ip);
2972 sp [-1].data.i = value;
2973 sp [-1].type = VAL_I32;
2975 case CEE_CONV_OVF_I2_UN:
2977 THROW_EX (mono_get_exception_overflow (), ip);
2978 sp [-1].data.i = value;
2979 sp [-1].type = VAL_I32;
2981 #if SIZEOF_VOID_P == 4
2982 case CEE_CONV_OVF_I_UN: /* Fall through */
2984 case CEE_CONV_OVF_I4_UN:
2985 if (value > 2147483647)
2986 THROW_EX (mono_get_exception_overflow (), ip);
2987 sp [-1].data.i = value;
2988 sp [-1].type = VAL_I32;
2990 case CEE_CONV_OVF_U1_UN:
2992 THROW_EX (mono_get_exception_overflow (), ip);
2993 sp [-1].data.i = value;
2994 sp [-1].type = VAL_I32;
2996 case CEE_CONV_OVF_U2_UN:
2998 THROW_EX (mono_get_exception_overflow (), ip);
2999 sp [-1].data.i = value;
3000 sp [-1].type = VAL_I32;
3002 #if SIZEOF_VOID_P == 4
3003 case CEE_CONV_OVF_U_UN: /* Fall through */
3005 case CEE_CONV_OVF_U4_UN:
3006 if (value > 4294967295U)
3007 THROW_EX (mono_get_exception_overflow (), ip);
3008 sp [-1].data.i = value;
3009 sp [-1].type = VAL_I32;
3012 g_assert_not_reached ();
3022 token = read32 (ip);
3024 class = mono_class_get (image, token);
3025 g_assert (class != NULL);
3027 sp [-1].type = VAL_OBJ;
3028 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
3029 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
3031 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3032 stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1]);
3034 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
3036 /* need to vt_free (sp); */
3048 token = read32 (ip);
3049 class = mono_class_get (image, token);
3050 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
3053 sp [-1].type = VAL_OBJ;
3055 /*if (profiling_classes) {
3056 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3058 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3068 g_assert (sp [-1].type == VAL_OBJ);
3072 THROW_EX (mono_get_exception_null_reference (), ip - 1);
3074 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3076 sp [-1].type = VAL_I32;
3077 sp [-1].data.i = mono_array_length (o);
3081 CASE (CEE_LDELEMA) {
3083 guint32 esize, token;
3086 token = read32 (ip);
3090 g_assert (sp [0].type == VAL_OBJ);
3093 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3095 if (sp [1].data.nati >= mono_array_length (o))
3096 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
3098 /* check the array element corresponds to token */
3099 esize = mono_array_element_size (o->obj.vtable->klass);
3102 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
3103 sp->data.vt.klass = o->obj.vtable->klass->element_class;
3108 CASE (CEE_LDELEM_I1) /* fall through */
3109 CASE (CEE_LDELEM_U1) /* fall through */
3110 CASE (CEE_LDELEM_I2) /* fall through */
3111 CASE (CEE_LDELEM_U2) /* fall through */
3112 CASE (CEE_LDELEM_I4) /* fall through */
3113 CASE (CEE_LDELEM_U4) /* fall through */
3114 CASE (CEE_LDELEM_I8) /* fall through */
3115 CASE (CEE_LDELEM_I) /* fall through */
3116 CASE (CEE_LDELEM_R4) /* fall through */
3117 CASE (CEE_LDELEM_R8) /* fall through */
3118 CASE (CEE_LDELEM_REF) {
3124 g_assert (sp [0].type == VAL_OBJ);
3127 THROW_EX (mono_get_exception_null_reference (), ip);
3129 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
3131 aindex = sp [1].data.nati;
3132 if (aindex >= mono_array_length (o))
3133 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3136 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3140 sp [0].data.i = mono_array_get (o, gint8, aindex);
3141 sp [0].type = VAL_I32;
3144 sp [0].data.i = mono_array_get (o, guint8, aindex);
3145 sp [0].type = VAL_I32;
3148 sp [0].data.i = mono_array_get (o, gint16, aindex);
3149 sp [0].type = VAL_I32;
3152 sp [0].data.i = mono_array_get (o, guint16, aindex);
3153 sp [0].type = VAL_I32;
3156 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3157 sp [0].type = VAL_NATI;
3160 sp [0].data.i = mono_array_get (o, gint32, aindex);
3161 sp [0].type = VAL_I32;
3164 sp [0].data.i = mono_array_get (o, guint32, aindex);
3165 sp [0].type = VAL_I32;
3168 sp [0].data.l = mono_array_get (o, guint64, aindex);
3169 sp [0].type = VAL_I64;
3172 sp [0].data.f = mono_array_get (o, float, aindex);
3173 sp [0].type = VAL_DOUBLE;
3176 sp [0].data.f = mono_array_get (o, double, aindex);
3177 sp [0].type = VAL_DOUBLE;
3179 case CEE_LDELEM_REF:
3180 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3181 sp [0].data.vt.klass = NULL;
3182 sp [0].type = VAL_OBJ;
3192 CASE (CEE_STELEM_I) /* fall through */
3193 CASE (CEE_STELEM_I1) /* fall through */
3194 CASE (CEE_STELEM_I2) /* fall through */
3195 CASE (CEE_STELEM_I4) /* fall through */
3196 CASE (CEE_STELEM_I8) /* fall through */
3197 CASE (CEE_STELEM_R4) /* fall through */
3198 CASE (CEE_STELEM_R8) /* fall through */
3199 CASE (CEE_STELEM_REF) {
3206 g_assert (sp [0].type == VAL_OBJ);
3209 THROW_EX (mono_get_exception_null_reference (), ip);
3211 ac = o->obj.vtable->klass;
3212 g_assert (MONO_CLASS_IS_ARRAY (ac));
3214 aindex = sp [1].data.nati;
3215 if (aindex >= mono_array_length (o))
3216 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3219 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3223 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
3226 mono_array_set (o, gint8, aindex, sp [2].data.i);
3229 mono_array_set (o, gint16, aindex, sp [2].data.i);
3232 mono_array_set (o, gint32, aindex, sp [2].data.i);
3235 mono_array_set (o, gint64, aindex, sp [2].data.l);
3238 mono_array_set (o, float, aindex, sp [2].data.f);
3241 mono_array_set (o, double, aindex, sp [2].data.f);
3243 case CEE_STELEM_REF:
3244 g_assert (sp [2].type == VAL_OBJ);
3245 mono_array_set (o, gpointer, aindex, sp [2].data.p);
3269 CASE (CEE_UNUSED17) ves_abort(); BREAK;
3270 CASE (CEE_CONV_OVF_I1)
3271 if (sp [-1].type == VAL_I32) {
3272 if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
3273 THROW_EX (mono_get_exception_overflow (), ip);
3274 sp [-1].data.i = (gint8)sp [-1].data.i;
3275 } else if (sp [-1].type == VAL_I64) {
3276 if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
3277 THROW_EX (mono_get_exception_overflow (), ip);
3278 sp [-1].data.i = (gint8)sp [-1].data.l;
3284 CASE (CEE_CONV_OVF_U1)
3285 if (sp [-1].type == VAL_I32) {
3286 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3287 THROW_EX (mono_get_exception_overflow (), ip);
3288 sp [-1].data.i = (gint8)sp [-1].data.i;
3289 } else if (sp [-1].type == VAL_I64) {
3290 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3291 THROW_EX (mono_get_exception_overflow (), ip);
3292 sp [-1].data.i = (gint8)sp [-1].data.l;
3298 CASE (CEE_CONV_OVF_I2)
3299 CASE (CEE_CONV_OVF_U2)
3301 /* FIXME: handle other cases */
3302 if (sp [-1].type == VAL_I32) {
3303 /* defined as NOP */
3308 CASE (CEE_CONV_OVF_I4)
3309 /* FIXME: handle other cases */
3310 if (sp [-1].type == VAL_I32) {
3311 /* defined as NOP */
3312 } else if(sp [-1].type == VAL_I64) {
3313 sp [-1].data.i = (gint32)sp [-1].data.l;
3314 sp [-1].type = VAL_I32;
3320 CASE (CEE_CONV_OVF_U4)
3321 /* FIXME: handle other cases */
3322 if (sp [-1].type == VAL_I32) {
3323 /* defined as NOP */
3324 } else if(sp [-1].type == VAL_I64) {
3325 sp [-1].data.i = (guint32)sp [-1].data.l;
3326 sp [-1].type = VAL_I32;
3332 CASE (CEE_CONV_OVF_I8)
3333 /* FIXME: handle other cases */
3334 if (sp [-1].type == VAL_I32) {
3335 sp [-1].data.l = (guint64)sp [-1].data.i;
3336 sp [-1].type = VAL_I64;
3337 } else if(sp [-1].type == VAL_I64) {
3338 /* defined as NOP */
3344 CASE (CEE_CONV_OVF_U8)
3345 /* FIXME: handle other cases */
3346 if (sp [-1].type == VAL_I32) {
3347 sp [-1].data.l = (guint64) sp [-1].data.i;
3348 sp [-1].type = VAL_I64;
3349 } else if(sp [-1].type == VAL_I64) {
3350 /* defined as NOP */
3362 CASE (CEE_UNUSED23) ves_abort(); BREAK;
3363 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
3365 if (!finite(sp [-1].data.f))
3366 THROW_EX (mono_get_exception_arithmetic (), ip);
3369 CASE (CEE_UNUSED24) ves_abort(); BREAK;
3370 CASE (CEE_UNUSED25) ves_abort(); BREAK;
3371 CASE (CEE_MKREFANY) ves_abort(); BREAK;
3380 CASE (CEE_UNUSED67) ves_abort(); BREAK;
3381 CASE (CEE_LDTOKEN) {
3383 MonoClass *handle_class;
3385 handle = mono_ldtoken (image, read32 (ip), &handle_class);
3387 vt_alloc (&handle_class->byval_arg, sp);
3388 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
3392 CASE (CEE_CONV_OVF_I)
3395 /* FIXME: check overflow. */
3398 sp->data.p = (gpointer)(mono_i) sp->data.i;
3401 sp->data.p = (gpointer)(mono_i) sp->data.l;
3406 sp->data.p = (gpointer)(mono_i) sp->data.f;
3411 sp->type = VAL_NATI;
3414 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
3417 /* FIXME: check overflow */
3418 if (sp->type == VAL_I32) {
3419 if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
3420 THROW_EX (mono_get_exception_overflow (), ip);
3421 sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)GET_NATI (sp [0]);
3422 } else if (sp->type == VAL_I64) {
3423 if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
3424 THROW_EX (mono_get_exception_overflow (), ip);
3425 sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
3426 } else if (sp->type == VAL_DOUBLE)
3427 sp [-1].data.f += sp [0].data.f;
3429 char *p = sp [-1].data.p;
3430 p += GET_NATI (sp [0]);
3435 CASE (CEE_ADD_OVF_UN)
3437 /* FIXME: check overflow, make unsigned */
3438 if (sp->type == VAL_I32) {
3439 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
3440 THROW_EX (mono_get_exception_overflow (), ip);
3441 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
3442 } else if (sp->type == VAL_I64) {
3443 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
3444 THROW_EX (mono_get_exception_overflow (), ip);
3445 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
3446 } else if (sp->type == VAL_DOUBLE)
3447 sp [-1].data.f += sp [0].data.f;
3449 char *p = sp [-1].data.p;
3450 p += GET_NATI (sp [0]);
3458 /* FIXME: check overflow */
3459 if (sp->type == VAL_I32)
3460 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3461 else if (sp->type == VAL_I64)
3462 sp [-1].data.l *= sp [0].data.l;
3463 else if (sp->type == VAL_DOUBLE)
3464 sp [-1].data.f *= sp [0].data.f;
3466 CASE (CEE_MUL_OVF_UN)
3469 /* FIXME: check overflow, make unsigned */
3470 if (sp->type == VAL_I32)
3471 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3472 else if (sp->type == VAL_I64)
3473 sp [-1].data.l *= sp [0].data.l;
3474 else if (sp->type == VAL_DOUBLE)
3475 sp [-1].data.f *= sp [0].data.f;
3478 CASE (CEE_SUB_OVF_UN)
3481 /* FIXME: handle undeflow/unsigned */
3482 /* should probably consider the pointers as unsigned */
3483 if (sp->type == VAL_I32)
3484 sp [-1].data.i -= GET_NATI (sp [0]);
3485 else if (sp->type == VAL_I64)
3486 sp [-1].data.l -= sp [0].data.l;
3487 else if (sp->type == VAL_DOUBLE)
3488 sp [-1].data.f -= sp [0].data.f;
3490 char *p = sp [-1].data.p;
3491 p -= GET_NATI (sp [0]);
3495 CASE (CEE_ENDFINALLY)
3497 ip = finally_ips->data;
3498 finally_ips = g_slist_remove (finally_ips, ip);
3504 * There was no exception, we continue normally at the target address.
3508 CASE (CEE_LEAVE) /* Fall through */
3510 sp = frame->stack; /* empty the stack */
3512 if (*ip == CEE_LEAVE_S) {
3514 ip += (signed char) *ip;
3518 ip += (gint32) read32 (ip);
3523 * We may be either inside a try block or inside an handler.
3524 * In the first case there was no exception and we go on
3525 * executing the finally handlers and after that resume control
3527 * In the second case we need to clear the exception and
3528 * continue directly at the target ip.
3532 goto handle_finally;
3535 frame->ex_handler = NULL;
3539 frame->ex_handler = NULL;
3541 goto handle_finally;
3573 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3575 * Note: Exceptions thrown when executing a prefixed opcode need
3576 * to take into account the number of prefix bytes (usually the
3577 * throw point is just (ip - n_prefix_bytes).
3582 case CEE_ARGLIST: ves_abort(); break;
3588 if (sp->type == VAL_I32)
3589 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3590 else if (sp->type == VAL_I64)
3591 result = sp [0].data.l == sp [1].data.l;
3592 else if (sp->type == VAL_DOUBLE) {
3593 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3596 result = sp [0].data.f == sp [1].data.f;
3598 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3600 sp->data.i = result;
3610 if (sp->type == VAL_I32)
3611 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3612 else if (sp->type == VAL_I64)
3613 result = sp [0].data.l > sp [1].data.l;
3614 else if (sp->type == VAL_DOUBLE) {
3615 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3618 result = sp [0].data.f > sp [1].data.f;
3620 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3622 sp->data.i = result;
3632 if (sp->type == VAL_I32)
3633 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3634 else if (sp->type == VAL_I64)
3635 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3636 else if (sp->type == VAL_DOUBLE)
3637 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3639 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3641 sp->data.i = result;
3651 if (sp->type == VAL_I32)
3652 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3653 else if (sp->type == VAL_I64)
3654 result = sp [0].data.l < sp [1].data.l;
3655 else if (sp->type == VAL_DOUBLE) {
3656 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3659 result = sp [0].data.f < sp [1].data.f;
3661 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3663 sp->data.i = result;
3673 if (sp->type == VAL_I32)
3674 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3675 else if (sp->type == VAL_I64)
3676 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3677 else if (sp->type == VAL_DOUBLE)
3678 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3680 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3682 sp->data.i = result;
3688 case CEE_LDVIRTFTN: {
3689 int virtual = *ip == CEE_LDVIRTFTN;
3693 token = read32 (ip);
3695 m = mono_get_method (image, token, NULL);
3697 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3701 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3702 m = get_virtual_method (domain, m, sp);
3704 sp->type = VAL_NATI;
3705 sp->data.p = mono_create_method_pointer (m);
3706 sp->data.vt.klass = NULL;
3710 case CEE_UNUSED56: ves_abort(); break;
3714 arg_pos = read16 (ip);
3716 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
3717 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3729 t = ARG_TYPE (signature, anum);
3730 c = mono_class_from_mono_type (t);
3731 sp->data.vt.klass = c;
3732 sp->data.vt.vt = ARG_POS (anum);
3735 sp->type = VAL_VALUETA;
3745 arg_pos = read16 (ip);
3748 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3755 loc_pos = read16 (ip);
3757 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3758 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3768 loc_pos = read16 (ip);
3770 t = LOCAL_TYPE (header, loc_pos);
3771 c = mono_class_from_mono_type (t);
3772 sp->data.vt.vt = LOCAL_POS (loc_pos);
3773 sp->data.vt.klass = c;
3776 sp->type = VAL_VALUETA;
3786 loc_pos = read16 (ip);
3789 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3794 if (sp != frame->stack)
3795 THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
3797 sp->data.p = alloca (sp->data.i);
3800 case CEE_UNUSED57: ves_abort(); break;
3801 case CEE_ENDFILTER: ves_abort(); break;
3802 case CEE_UNALIGNED_:
3804 unaligned_address = 1;
3808 volatile_address = 1;
3817 token = read32 (ip);
3820 * we ignore the value of token (I think we can as unspecified
3821 * behavior described in Partition II, 3.5).
3824 g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
3825 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3828 case CEE_UNUSED68: ves_abort(); break;
3831 if (!sp [0].data.p || !sp [1].data.p)
3832 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3834 /* FIXME: value and size may be int64... */
3835 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3840 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3842 /* FIXME: value and size may be int64... */
3843 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3845 case CEE_UNUSED69: ves_abort(); break;
3848 * need to clarify what this should actually do:
3849 * start the search from the last found handler in
3850 * this method or continue in the caller or what.
3851 * Also, do we need to run finally/fault handlers after a retrow?
3852 * Well, this implementation will follow the usual search
3853 * for an handler, considering the current ip as throw spot.
3854 * We need to NULL frame->ex_handler for the later code to
3855 * actually run the new found handler.
3857 frame->ex_handler = NULL;
3858 THROW_EX (frame->ex, ip - 1);
3860 case CEE_UNUSED: ves_abort(); break;
3865 token = read32 (ip);
3867 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
3868 MonoType *type = mono_type_create_from_typespec (image, token);
3869 sp->data.i = mono_type_size (type, &align);
3870 mono_metadata_free_type (type);
3872 MonoClass *szclass = mono_class_get (image, token);
3873 mono_class_init (szclass);
3874 if (!szclass->valuetype)
3875 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
3876 sp->data.i = mono_class_value_size (szclass, &align);
3882 case CEE_REFANYTYPE: ves_abort(); break;
3889 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3896 g_assert_not_reached ();
3898 * Exception handling code.
3899 * The exception object is stored in frame->ex.
3906 MonoInvocation *inv;
3907 MonoMethodHeader *hd;
3908 MonoExceptionClause *clause;
3914 g_print ("* Handling exception '%s' at IL_%04x\n", mono_object_class (frame->ex)->name, frame->ip - header->code);
3916 if (die_on_exception)
3919 for (inv = frame; inv; inv = inv->parent) {
3920 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
3922 if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
3924 hd = ((MonoMethodNormal*)inv->method)->header;
3925 ip_offset = inv->ip - hd->code;
3926 for (i = 0; i < hd->num_clauses; ++i) {
3927 clause = &hd->clauses [i];
3928 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3929 if (!clause->flags) {
3930 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3932 * OK, we found an handler, now we need to execute the finally
3933 * and fault blocks before branching to the handler code.
3935 inv->ex_handler = clause;
3938 g_print ("* Found handler at '%s'\n", inv->method->name);
3941 * It seems that if the catch handler is found in the same method,
3942 * it gets executed before the finally handler.
3947 goto handle_finally;
3950 /* FIXME: handle filter clauses */
3957 * If we get here, no handler was found: print a stack trace.
3960 ex_obj = (MonoObject*)frame->ex;
3961 mono_unhandled_exception (ex_obj);
3968 MonoExceptionClause *clause;
3970 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3974 ip_offset = frame->ip - header->code;
3976 for (i = 0; i < header->num_clauses; ++i) {
3977 clause = &header->clauses [i];
3978 if (clause == frame->ex_handler)
3980 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code))) {
3981 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3982 ip = header->code + clause->handler_offset;
3983 finally_ips = g_slist_append (finally_ips, ip);
3986 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
3992 ip = finally_ips->data;
3993 finally_ips = g_slist_remove (finally_ips, ip);
3998 * If an exception is set, we need to execute the fault handler, too,
3999 * otherwise, we continue normally.
4010 MonoExceptionClause *clause;
4012 ip_offset = frame->ip - header->code;
4013 for (i = 0; i < header->num_clauses; ++i) {
4014 clause = &header->clauses [i];
4015 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4016 ip = header->code + clause->handler_offset;
4019 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4025 * If the handler for the exception was found in this method, we jump
4026 * to it right away, otherwise we return and let the caller run
4027 * the finally, fault and catch blocks.
4028 * This same code should be present in the endfault opcode, but it
4029 * is corrently not assigned in the ECMA specs: LAMESPEC.
4031 if (frame->ex_handler) {
4032 ip = header->code + frame->ex_handler->handler_offset;
4035 sp->data.p = frame->ex;
4046 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4048 MonoImage *image = assembly->image;
4049 MonoCLIImageInfo *iinfo;
4051 MonoObject *exc = NULL;
4054 iinfo = image->image_info;
4055 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
4057 g_error ("No entry point method found in %s", image->name);
4059 rval = mono_runtime_run_main (method, argc, argv, &exc);
4068 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4069 "Usage is: mint [options] executable args...\n\n", VERSION);
4071 "Runtime Debugging:\n"
4076 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4079 " --traceclassinit\n"
4082 " --debug method_name\n"
4088 " --config filename load the specified config file instead of the default\n"
4089 " --workers n maximum number of worker threads\n"
4096 test_load_class (MonoImage* image)
4098 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
4102 for (i = 1; i <= t->rows; ++i) {
4103 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
4104 mono_class_init (klass);
4109 static MonoException * segv_exception = NULL;
4112 segv_handler (int signum)
4114 signal (signum, segv_handler);
4115 mono_raise_exception (segv_exception);
4119 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4120 MonoReflectionMethod **method,
4121 gint32 *iloffset, gint32 *native_offset,
4122 MonoString **file, gint32 *line, gint32 *column)
4135 *file = mono_string_new (mono_domain_get (), "unknown");
4141 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4147 main (int argc, char *argv [])
4150 MonoAssembly *assembly;
4151 int retval = 0, i, ocount = 0;
4152 char *file, *error, *config_file = NULL;
4157 for (i = 1; i < argc && argv [i][0] == '-'; i++){
4158 if (strcmp (argv [i], "--trace") == 0)
4160 if (strcmp (argv [i], "--noptr") == 0)
4161 global_no_pointers = 1;
4162 if (strcmp (argv [i], "--traceops") == 0)
4164 if (strcmp (argv [i], "--dieonex") == 0)
4165 die_on_exception = 1;
4166 if (strcmp (argv [i], "--print-vtable") == 0)
4167 mono_print_vtable = TRUE;
4168 if (strcmp (argv [i], "--profile") == 0)
4169 mono_profiler_install_simple ();
4170 if (strcmp (argv [i], "--opcode-count") == 0)
4172 if (strcmp (argv [i], "--config") == 0)
4173 config_file = argv [++i];
4174 if (strcmp (argv [i], "--workers") == 0) {
4175 mono_worker_threads = atoi (argv [++i]);
4176 if (mono_worker_threads < 1)
4177 mono_worker_threads = 1;
4179 if (strcmp (argv [i], "--help") == 0)
4182 if (strcmp (argv [i], "--debug") == 0) {
4183 MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
4185 g_error ("Invalid method name '%s'", argv [i]);
4186 db_methods = g_list_append (db_methods, desc);
4196 mono_set_rootdir (argv [0]);
4197 mono_config_parse (config_file);
4199 g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
4200 g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
4203 mono_add_internal_call ("System.Array::Set", ves_array_set);
4204 mono_add_internal_call ("System.Array::Get", ves_array_get);
4205 mono_add_internal_call ("System.Array::Address", ves_array_element_address);
4206 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
4207 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
4209 frame_thread_id = TlsAlloc ();
4210 TlsSetValue (frame_thread_id, NULL);
4212 mono_install_runtime_invoke (interp_mono_runtime_invoke);
4213 mono_install_remoting_trampoline (interp_create_remoting_trampoline);
4215 mono_install_handler (interp_ex_handler);
4217 InitializeCriticalSection (&metadata_lock);
4218 domain = mono_init (file);
4219 mono_runtime_init (domain, NULL);
4221 assembly = mono_domain_assembly_open (domain, file);
4224 fprintf (stderr, "Can not open image %s\n", file);
4230 test_load_class (assembly->image);
4232 error = mono_verify_corlib ();
4234 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
4237 segv_exception = mono_get_exception_null_reference ();
4238 segv_exception->message = mono_string_new (domain, "Segmentation fault");
4239 signal (SIGSEGV, segv_handler);
4241 retval = ves_exec (domain, assembly, argc - i, argv + i);
4243 mono_profiler_shutdown ();
4245 mono_runtime_cleanup (domain);
4246 mono_domain_unload (domain, TRUE);
4250 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4251 fprintf (stderr, "fcall count: %ld\n", fcall_count);