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 Ximian, Inc.
26 # define alloca __builtin_alloca
30 /* trim excessive headers */
31 #include <mono/metadata/image.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/cil-coff.h>
34 #include <mono/metadata/mono-endian.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/blob.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/loader.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/reflection.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/verify.h>
44 #include <mono/metadata/opcodes.h>
45 #include <mono/io-layer/io-layer.h>
46 #include <mono/metadata/socket-io.h>
47 /*#include <mono/cli/types.h>*/
53 #define finite _finite
65 /* If true, then we output the opcodes as we interpret them */
66 static int tracing = 0;
68 static int debug_indent_level = 0;
70 static GHashTable *profiling = NULL;
71 static GHashTable *profiling_classes = NULL;
74 * Pull the list of opcodes
76 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
80 #include "mono/cil/opcode.def"
85 #define GET_NATI(sp) ((sp).data.nati)
86 #define CSIZE(x) (sizeof (x) / 4)
88 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
90 (frame)->parent = (parent_frame); \
91 (frame)->obj = (obj_this); \
92 (frame)->stack_args = (method_args); \
93 (frame)->retval = (method_retval); \
94 (frame)->method = (mono_method); \
95 (frame)->ex_handler = NULL; \
97 (frame)->child = NULL; \
100 void ves_exec_method (MonoInvocation *frame);
102 typedef void (*ICallMethod) (MonoInvocation *frame);
104 static guint32 die_on_exception = 0;
105 static guint32 frame_thread_id = 0;
108 interp_ex_handler (MonoException *ex) {
109 MonoInvocation *frame = TlsGetValue (frame_thread_id);
111 longjmp (*(jmp_buf*)frame->locals, 1);
115 runtime_object_init (MonoObject *obj)
119 MonoMethod *method = NULL;
120 MonoClass *klass = obj->vtable->klass;
122 for (i = 0; i < klass->method.count; ++i) {
123 if (!strcmp (".ctor", klass->methods [i]->name) &&
124 klass->methods [i]->signature->param_count == 0) {
125 method = klass->methods [i];
133 INIT_FRAME (&call, NULL, obj, NULL, NULL, method);
135 ves_exec_method (&call);
140 ves_real_abort (int line, MonoMethod *mh,
141 const unsigned char *ip, stackval *stack, stackval *sp)
143 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
144 fprintf (stderr, "Execution aborted in method: %s\n", mh->name);
145 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
146 ip-mm->header->code);
147 g_print ("0x%04x %02x\n",
148 ip-mm->header->code, *ip);
150 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
152 #define ves_abort() do {ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp); THROW_EX (mono_get_exception_execution_engine (), ip);} while (0);
155 * runtime_class_init:
156 * @klass: klass that needs to be initialized
158 * This routine calls the class constructor for @class.
161 runtime_class_init (MonoClass *klass)
167 for (i = 0; i < klass->method.count; ++i) {
168 method = klass->methods [i];
169 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
170 (strcmp (".cctor", method->name) == 0)) {
171 INIT_FRAME (&call, NULL, NULL, NULL, NULL, method);
172 ves_exec_method (&call);
176 /* No class constructor found */
180 get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
186 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
189 g_assert (m->klass->inited);
192 klass = obj->vtable->klass;
193 vtable = (MonoMethod **)obj->vtable->vtable;
195 if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
196 return *(MonoMethod**)(obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
199 g_assert (vtable [m->slot]);
201 return vtable [m->slot];
205 stackval_from_data (MonoType *type, stackval *result, const char *data)
208 switch (type->type) {
209 case MONO_TYPE_OBJECT:
210 case MONO_TYPE_CLASS:
211 case MONO_TYPE_STRING:
212 case MONO_TYPE_ARRAY:
213 case MONO_TYPE_SZARRAY:
214 result->type = VAL_OBJ;
217 result->type = VAL_VALUETA;
220 result->data.p = *(gpointer*)data;
221 result->data.vt.klass = mono_class_from_mono_type (type);
224 switch (type->type) {
228 result->type = VAL_I32;
229 result->data.i = *(gint8*)data;
232 case MONO_TYPE_BOOLEAN:
233 result->type = VAL_I32;
234 result->data.i = *(guint8*)data;
237 result->type = VAL_I32;
238 result->data.i = *(gint16*)data;
242 result->type = VAL_I32;
243 result->data.i = *(guint16*)data;
246 result->type = VAL_I32;
247 result->data.i = *(gint32*)data;
252 result->type = VAL_TP;
253 result->data.p = *(gpointer*)data;
256 result->type = VAL_I32;
257 result->data.i = *(guint32*)data;
260 result->type = VAL_DOUBLE;
261 result->data.f = *(float*)data;
265 result->type = VAL_I64;
266 result->data.l = *(gint64*)data;
269 result->type = VAL_DOUBLE;
270 result->data.f = *(double*)data;
272 case MONO_TYPE_STRING:
273 case MONO_TYPE_SZARRAY:
274 case MONO_TYPE_CLASS:
275 case MONO_TYPE_OBJECT:
276 case MONO_TYPE_ARRAY:
277 result->type = VAL_OBJ;
278 result->data.p = *(gpointer*)data;
279 result->data.vt.klass = mono_class_from_mono_type (type);
281 case MONO_TYPE_VALUETYPE:
282 if (type->data.klass->enumtype) {
283 return stackval_from_data (type->data.klass->enum_basetype, result, data);
285 result->type = VAL_VALUET;
286 result->data.vt.klass = type->data.klass;
287 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
291 g_warning ("got type 0x%02x", type->type);
292 g_assert_not_reached ();
297 stackval_to_data (MonoType *type, stackval *val, char *data)
300 gpointer *p = (gpointer*)data;
304 switch (type->type) {
307 guint8 *p = (guint8*)data;
311 case MONO_TYPE_BOOLEAN: {
312 guint8 *p = (guint8*)data;
313 *p = (val->data.i != 0);
318 case MONO_TYPE_CHAR: {
319 guint16 *p = (guint16*)data;
323 #if SIZEOF_VOID_P == 4
329 gint32 *p = (gint32*)data;
333 #if SIZEOF_VOID_P == 8
339 gint64 *p = (gint64*)data;
344 float *p = (float*)data;
349 double *p = (double*)data;
353 case MONO_TYPE_STRING:
354 case MONO_TYPE_SZARRAY:
355 case MONO_TYPE_CLASS:
356 case MONO_TYPE_OBJECT:
357 case MONO_TYPE_ARRAY:
358 case MONO_TYPE_PTR: {
359 gpointer *p = (gpointer*)data;
363 case MONO_TYPE_VALUETYPE:
364 if (type->data.klass->enumtype) {
365 return stackval_to_data (type->data.klass->enum_basetype, val, data);
367 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
371 g_warning ("got type %x", type->type);
372 g_assert_not_reached ();
377 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
380 guint32 *lower_bounds;
383 lengths = alloca (sizeof (guint32) * klass->rank * 2);
384 for (i = 0; i < sig->param_count; ++i) {
385 lengths [i] = values->data.i;
388 if (klass->rank == sig->param_count) {
389 /* Only lengths provided. */
392 /* lower bounds are first. */
393 lower_bounds = lengths;
394 lengths += klass->rank;
396 return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
400 ves_array_set (MonoInvocation *frame)
402 stackval *sp = frame->stack_args;
406 gint32 i, t, pos, esize;
412 ac = o->vtable->klass;
414 g_assert (ac->rank >= 1);
416 pos = sp [0].data.i - ao->bounds [0].lower_bound;
417 for (i = 1; i < ac->rank; i++) {
418 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
419 ao->bounds [i].length) {
420 g_warning ("wrong array index");
421 g_assert_not_reached ();
423 pos = pos*ao->bounds [i].length + sp [i].data.i -
424 ao->bounds [i].lower_bound;
427 esize = mono_array_element_size (ac);
428 ea = mono_array_addr_with_size (ao, esize, pos);
430 mt = frame->method->signature->params [ac->rank];
431 stackval_to_data (mt, &sp [ac->rank], ea);
435 ves_array_get (MonoInvocation *frame)
437 stackval *sp = frame->stack_args;
441 gint32 i, pos, esize;
447 ac = o->vtable->klass;
449 g_assert (ac->rank >= 1);
451 pos = sp [0].data.i - ao->bounds [0].lower_bound;
452 for (i = 1; i < ac->rank; i++)
453 pos = pos*ao->bounds [i].length + sp [i].data.i -
454 ao->bounds [i].lower_bound;
456 esize = mono_array_element_size (ac);
457 ea = mono_array_addr_with_size (ao, esize, pos);
459 mt = frame->method->signature->ret;
460 stackval_from_data (mt, frame->retval, ea);
464 ves_array_element_address (MonoInvocation *frame)
466 stackval *sp = frame->stack_args;
470 gint32 i, pos, esize;
475 ac = o->vtable->klass;
477 g_assert (ac->rank >= 1);
479 pos = sp [0].data.i - ao->bounds [0].lower_bound;
480 for (i = 1; i < ac->rank; i++)
481 pos = pos*ao->bounds [i].length + sp [i].data.i -
482 ao->bounds [i].lower_bound;
484 esize = mono_array_element_size (ac);
485 ea = mono_array_addr_with_size (ao, esize, pos);
487 frame->retval->type = VAL_TP;
488 frame->retval->data.p = ea;
492 ves_pinvoke_method (MonoInvocation *frame)
499 if (!frame->method->info)
500 frame->method->info = mono_create_trampoline (frame->method, 0);
501 func = (MonoPIFunc)frame->method->info;
504 * frame->locals and args are unused for P/Invoke methods, so we reuse them.
505 * locals will point to the jmp_buf, while args will point to the previous
506 * MonoInvocation frame: this is needed to make exception searching work across
507 * managed/unmanaged boundaries.
509 frame->locals = (char*)&env;
510 frame->args = (char*)TlsGetValue (frame_thread_id);
511 TlsSetValue (frame_thread_id, frame);
513 func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
514 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
519 * runtime specifies that the implementation of the method is automatically
520 * provided by the runtime and is primarily used for the methods of delegates.
523 ves_runtime_method (MonoInvocation *frame)
525 const char *name = frame->method->name;
526 MonoObject *obj = (MonoObject*)frame->obj;
527 MonoDelegate *delegate = (MonoDelegate*)frame->obj;
529 mono_class_init (mono_defaults.delegate_class);
531 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
532 mono_object_isinst (obj, mono_defaults.delegate_class)) {
533 delegate->target = frame->stack_args[0].data.p;
534 delegate->method_ptr = frame->stack_args[1].data.p;
537 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
538 mono_object_isinst (obj, mono_defaults.delegate_class)) {
543 code = (guchar*)delegate->method_ptr;
544 method = mono_method_pointer_get (code);
545 /* FIXME: check for NULL method */
547 method->addr = mono_create_trampoline (method, 1);
549 /* FIXME: need to handle exceptions across managed/unmanaged boundaries */
550 func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, delegate->target, frame->stack_args);
551 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
554 g_error ("Don't know how to exec runtime method %s.%s::%s",
555 frame->method->klass->name_space, frame->method->klass->name,
556 frame->method->name);
560 dump_stack (stackval *stack, stackval *sp)
569 case VAL_I32: printf ("[%d] ", s->data.i); break;
570 case VAL_I64: printf ("[%lld] ", s->data.l); break;
571 case VAL_DOUBLE: printf ("[%0.5f] ", s->data.f); break;
572 case VAL_VALUET: printf ("[vt: %p] ", s->data.vt.vt); break;
575 MonoObject *obj = s->data.p;
576 if (obj && obj->klass == mono_defaults.string_class) {
577 char *str = mono_string_to_utf8 ((MonoString*)obj);
578 printf ("\"%s\" ", str);
584 default: printf ("[%p] ", s->data.p); break;
591 dump_frame (MonoInvocation *inv)
594 for (i = 0; inv; inv = inv->parent, ++i) {
595 MonoClass *k = inv->method->klass;
598 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
599 inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
603 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
605 codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
608 opname = mono_opcode_names [codep];
609 codep = inv->ip - hd->code;
611 g_print ("#%d: 0x%05x %-10s in %s.%s::%s (", i, codep, opname,
612 k->name_space, k->name, inv->method->name);
613 dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
618 #define DEBUG_INTERP 1
621 static unsigned long opcode_count = 0;
622 static unsigned long fcall_count = 0;
623 static int break_on_method = 0;
624 static GList *db_methods = NULL;
631 for (h = 0; h < debug_indent_level; h++)
636 db_match_method (gpointer data, gpointer user_data)
638 MonoMethod *m = (MonoMethod*)user_data;
639 char *startname, *startclass;
641 if (strcmp((char*)data, m->name) == 0) {
645 startname = strrchr ((char*)data, ':');
648 if (strcmp(startname + 1, m->name) != 0)
650 startclass = (char*)data;
651 if (memcmp (startclass, m->klass->name, startname-startclass) == 0)
653 /* ignore namespace */
657 calc_offsets (MonoMethodHeader *header, MonoMethodSignature *signature)
659 int i, align, size, offset = 0;
660 int hasthis = signature->hasthis;
661 guint32 *offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
663 for (i = 0; i < header->num_locals; ++i) {
664 size = mono_type_size (header->locals [i], &align);
666 offset &= ~(align - 1);
667 offsets [2 + i] = offset;
670 offsets [0] = offset;
673 offset += sizeof (gpointer) - 1;
674 offset &= ~(sizeof (gpointer) - 1);
675 offsets [2 + header->num_locals] = offset;
676 offset += sizeof (gpointer);
678 for (i = 0; i < signature->param_count; ++i) {
679 size = mono_type_size (signature->params [i], &align);
681 offset &= ~(align - 1);
682 offsets [2 + hasthis + header->num_locals + i] = offset;
685 offsets [1] = offset;
689 #define DEBUG_ENTER() \
691 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method); \
692 if (break_on_method) G_BREAKPOINT (); \
693 break_on_method = 0; \
695 MonoClass *klass = frame->method->klass; \
696 debug_indent_level++; \
698 g_print ("Entering %s.%s::%s (", klass->name_space, klass->name, frame->method->name); \
699 dump_stack (frame->stack_args, frame->stack_args+frame->method->signature->param_count); \
703 if (!(profile_info = g_hash_table_lookup (profiling, frame->method))) { \
704 profile_info = g_new0 (MethodProfile, 1); \
705 profile_info->u.timer = g_timer_new (); \
706 g_hash_table_insert (profiling, frame->method, profile_info); \
708 profile_info->count++; \
709 g_timer_start (profile_info->u.timer); \
712 #define DEBUG_LEAVE() \
714 MonoClass *klass = frame->method->klass; \
716 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
717 debug_indent_level--; \
720 g_timer_stop (profile_info->u.timer); \
721 profile_info->total += g_timer_elapsed (profile_info->u.timer, NULL); \
726 #define DEBUG_ENTER()
727 #define DEBUG_LEAVE()
731 #define LOCAL_POS(n) (frame->locals + offsets [2 + (n)])
732 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
734 #define ARG_POS(n) (args_pointers [(n)])
735 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
736 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
738 #define THROW_EX(exception,ex_ip) \
740 frame->ip = (ex_ip); \
741 frame->ex = (MonoException*)(exception); \
742 goto handle_exception; \
745 typedef struct _vtallocation vtallocation;
747 struct _vtallocation {
750 char data [MONO_ZERO_LEN_ARRAY];
754 * we don't use vtallocation->next, yet
756 #define vt_alloc(vtype,sp) \
757 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
758 if (!(vtype)->byref) { \
760 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
761 if (!vtalloc || vtalloc->size < size) { \
762 vtalloc = alloca (sizeof (vtallocation) + size); \
763 vtalloc->size = size; \
765 (sp)->data.vt.vt = vtalloc->data; \
768 (sp)->data.vt.klass = (vtype)->data.klass; \
772 #define vt_free(sp) \
774 if ((sp)->type == VAL_VALUET) { \
775 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
780 verify_method (MonoMethod *m)
782 GSList *errors, *tmp;
783 MonoVerifyInfo *info;
785 errors = mono_method_verify (m, MONO_VERIFY_ALL);
787 g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
788 for (tmp = errors; tmp; tmp = tmp->next) {
790 g_print ("%s\n", info->message);
794 mono_free_verify_list (errors);
797 #define CHECK_ADD_OVERFLOW(a,b) \
798 (gint32)(b) >= 0 ? (gint32)(INT_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
799 : (gint32)(INT_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
801 #define CHECK_ADD_OVERFLOW_UN(a,b) \
802 (guint32)(UINT_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
804 #define CHECK_ADD_OVERFLOW64(a,b) \
805 (gint64)(b) >= 0 ? (gint64)(LLONG_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
806 : (gint64)(LLONG_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
809 #define GUINT64_MAX 18446744073709551615UL
812 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
813 (guint64)(GUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
816 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params)
818 MonoInvocation frame;
820 MonoMethodSignature *sig = method->signature;
823 stackval *args = alloca (sizeof (stackval) * sig->param_count);
825 /* FIXME: Set frame for execption handling. */
827 /* allocate ret object. */
828 if (sig->ret->type == MONO_TYPE_VOID) {
832 MonoClass *klass = mono_class_from_mono_type (sig->ret);
833 if (klass->valuetype) {
834 retval = mono_object_new (mono_domain_get (), klass);
835 ret = ((char*)retval) + sizeof (MonoObject);
840 for (i = 0; i < sig->param_count; ++i) {
841 if (sig->params [i]->byref) {
842 args [i].type = VAL_POINTER;
843 args [i].data.p = params [i];
846 type = sig->params [i]->type;
851 case MONO_TYPE_BOOLEAN:
852 args [i].type = VAL_I32;
853 args [i].data.i = *(MonoBoolean*)params [i];
854 args [i].data.vt.klass = NULL;
859 args [i].type = VAL_I32;
860 args [i].data.i = *(gint16*)params [i];
861 args [i].data.vt.klass = NULL;
863 #if SIZEOF_VOID_P == 4
864 case MONO_TYPE_U: /* use VAL_POINTER? */
869 args [i].type = VAL_I32;
870 args [i].data.i = *(gint32*)params [i];
871 args [i].data.vt.klass = NULL;
873 #if SIZEOF_VOID_P == 8
879 args [i].type = VAL_I64;
880 args [i].data.l = *(gint64*)params [i];
881 args [i].data.vt.klass = NULL;
883 case MONO_TYPE_VALUETYPE:
884 if (sig->params [i]->data.klass->enumtype) {
885 type = sig->params [i]->data.klass->enum_basetype->type;
888 g_warning ("generic valutype %s not handled in runtime invoke", sig->params [i]->data.klass->name);
891 case MONO_TYPE_STRING:
892 args [i].type = VAL_OBJ;
893 args [i].data.p = params [i];
894 args [i].data.vt.klass = NULL;
897 g_error ("type 0x%x not handled in invoke", sig->params [i]->type);
901 INIT_FRAME(&frame,NULL,obj,args,ret,method);
902 ves_exec_method (&frame);
907 * Need to optimize ALU ops when natural int == int32
909 * IDEA: if we maintain a stack of ip, sp to be checked
910 * in the return opcode, we could inline simple methods that don't
911 * use the stack or local variables....
913 * The {,.S} versions of many opcodes can/should be merged to reduce code
918 ves_exec_method (MonoInvocation *frame)
920 MonoDomain *domain = mono_domain_get ();
921 MonoInvocation child_frame;
922 MonoMethodHeader *header;
923 MonoMethodSignature *signature;
925 const unsigned char *endfinally_ip;
926 register const unsigned char *ip;
927 register stackval *sp;
928 void **args_pointers;
930 unsigned char tail_recursion = 0;
931 unsigned char unaligned_address = 0;
932 unsigned char volatile_address = 0;
933 vtallocation *vtalloc = NULL;
934 MethodProfile *profile_info;
937 mono_class_init (frame->method->klass);
941 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
942 if (!frame->method->addr) {
943 frame->ex = (MonoException*)mono_get_exception_missing_method ();
947 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
948 ves_pinvoke_method (frame);
950 ICallMethod icall = (ICallMethod)frame->method->addr;
954 goto handle_exception;
959 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
960 if (!frame->method->addr) {
961 frame->ex = (MonoException*)mono_get_exception_missing_method ();
965 ves_pinvoke_method (frame);
967 goto handle_exception;
972 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
973 ves_runtime_method (frame);
975 goto handle_exception;
980 /*verify_method (frame->method);*/
982 header = ((MonoMethodNormal *)frame->method)->header;
983 signature = frame->method->signature;
984 image = frame->method->klass->image;
987 * with alloca we get the expected huge performance gain
988 * stackval *stack = g_new0(stackval, header->max_stack);
991 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
993 if (!frame->method->info)
994 frame->method->info = calc_offsets (header, signature);
995 offsets = frame->method->info;
997 if (header->num_locals) {
998 frame->locals = alloca (offsets [0]);
1000 * yes, we do it unconditionally, because it needs to be done for
1001 * some cases anyway and checking for that would be even slower.
1003 memset (frame->locals, 0, offsets [0]);
1006 * Copy args from stack_args to args.
1008 if (signature->param_count || signature->hasthis) {
1010 int has_this = signature->hasthis;
1012 frame->args = alloca (offsets [1]);
1013 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
1016 this_arg = args_pointers [0] = frame->args;
1017 *this_arg = frame->obj;
1019 for (i = 0; i < signature->param_count; ++i) {
1020 args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
1021 stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this]);
1025 child_frame.parent = frame;
1026 frame->child = &child_frame;
1033 * using while (ip < end) may result in a 15% performance drop,
1034 * but it may be useful for debug
1038 /*g_assert (sp >= stack);*/
1043 g_print ("stack: ");
1044 dump_stack (frame->stack, sp);
1047 g_print ("0x%04x: %s\n", ip-header->code,
1048 *ip == 0xfe ? mono_opcode_names [256 + ip [1]] : mono_opcode_names [*ip]);
1058 G_BREAKPOINT (); /* this is not portable... */
1063 CASE (CEE_LDARG_3) {
1064 int n = (*ip)-CEE_LDARG_0;
1066 vt_alloc (ARG_TYPE (signature, n), sp);
1067 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
1074 CASE (CEE_LDLOC_3) {
1075 int n = (*ip)-CEE_LDLOC_0;
1077 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1079 sp->data.i = *(gint32*) LOCAL_POS (n);
1083 vt_alloc (LOCAL_TYPE (header, n), sp);
1084 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1092 CASE (CEE_STLOC_3) {
1093 int n = (*ip)-CEE_STLOC_0;
1096 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
1097 gint32 *p = (gint32*)LOCAL_POS (n);
1101 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
1108 vt_alloc (ARG_TYPE (signature, *ip), sp);
1109 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1113 CASE (CEE_LDARGA_S) {
1118 t = ARG_TYPE (signature, *ip);
1119 c = mono_class_from_mono_type (t);
1120 sp->data.vt.klass = c;
1121 sp->data.vt.vt = ARG_POS (*ip);
1124 sp->type = VAL_VALUETA;
1135 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
1141 vt_alloc (LOCAL_TYPE (header, *ip), sp);
1142 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1146 CASE (CEE_LDLOCA_S) {
1151 t = LOCAL_TYPE (header, *ip);
1152 c = mono_class_from_mono_type (t);
1153 sp->data.vt.klass = c;
1154 sp->data.p = LOCAL_POS (*ip);
1157 sp->type = VAL_VALUETA;
1168 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1176 sp->data.vt.klass = NULL;
1179 CASE (CEE_LDC_I4_M1)
1195 sp->data.i = (*ip) - CEE_LDC_I4_0;
1202 sp->data.i = *(gint8 *)ip;
1209 sp->data.i = read32 (ip);
1216 sp->data.l = read64 (ip);
1223 sp->type = VAL_DOUBLE;
1232 sp->type = VAL_DOUBLE;
1233 readr8(ip, &sp->data.f);
1237 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1239 if (sp [-1].type == VAL_VALUET) {
1240 MonoClass *c = sp [-1].data.vt.klass;
1241 vt_alloc (&c->byval_arg, sp);
1242 stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt);
1254 CASE (CEE_JMP) ves_abort(); BREAK;
1255 CASE (CEE_CALLVIRT) /* Fall through */
1256 CASE (CEE_CALLI) /* Fall through */
1258 MonoMethodSignature *csignature;
1260 stackval *endsp = sp;
1262 int virtual = *ip == CEE_CALLVIRT;
1263 int calli = *ip == CEE_CALLI;
1266 * We ignore tail recursion for now.
1273 token = read32 (ip);
1276 unsigned char *code;
1279 child_frame.method = mono_method_pointer_get (code);
1280 /* check for NULL with native code */
1281 csignature = child_frame.method->signature;
1283 child_frame.method = mono_get_method (image, token, NULL);
1284 if (!child_frame.method)
1285 THROW_EX (mono_get_exception_missing_method (), ip -5);
1286 csignature = child_frame.method->signature;
1288 stackval *this_arg = &sp [-csignature->param_count-1];
1289 if (!this_arg->data.p)
1290 THROW_EX (mono_get_exception_null_reference(), ip - 5);
1291 child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
1292 if (!child_frame.method)
1293 THROW_EX (mono_get_exception_missing_method (), ip -5);
1296 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1297 /* decrement by the actual number of args */
1298 if (csignature->param_count) {
1299 sp -= csignature->param_count;
1300 child_frame.stack_args = sp;
1302 child_frame.stack_args = NULL;
1304 if (csignature->hasthis) {
1305 g_assert (sp >= frame->stack);
1308 * It may also be a TP from LD(S)FLDA
1309 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1311 if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
1312 child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
1314 child_frame.obj = sp->data.p;
1316 child_frame.obj = NULL;
1318 if (csignature->ret->type != MONO_TYPE_VOID) {
1319 vt_alloc (csignature->ret, &retval);
1320 child_frame.retval = &retval;
1322 child_frame.retval = NULL;
1325 child_frame.ex = NULL;
1326 child_frame.ex_handler = NULL;
1328 ves_exec_method (&child_frame);
1330 while (endsp > sp) {
1335 if (child_frame.ex) {
1337 * An exception occurred, need to run finally, fault and catch handlers..
1339 frame->ex = child_frame.ex;
1340 goto handle_finally;
1343 /* need to handle typedbyref ... */
1344 if (csignature->ret->type != MONO_TYPE_VOID) {
1351 if (signature->ret->type != MONO_TYPE_VOID) {
1353 if (sp->type == VAL_VALUET) {
1354 /* the caller has already allocated the memory */
1355 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1358 *frame->retval = *sp;
1361 if (sp > frame->stack)
1362 g_warning ("more values on stack: %d", sp-frame->stack);
1366 CASE (CEE_BR_S) /* Fall through */
1368 if (*ip == CEE_BR) {
1370 ip += (gint32) read32(ip);
1374 ip += (signed char) *ip;
1378 CASE (CEE_BRFALSE) /* Fall through */
1379 CASE (CEE_BRFALSE_S) {
1381 int near_jump = *ip == CEE_BRFALSE_S;
1385 case VAL_I32: result = sp->data.i == 0; break;
1386 case VAL_I64: result = sp->data.l == 0; break;
1387 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1388 default: result = sp->data.p == NULL; break;
1392 ip += (signed char)*ip;
1394 ip += (gint32) read32 (ip);
1396 ip += near_jump ? 1: 4;
1399 CASE (CEE_BRTRUE) /* Fall through */
1400 CASE (CEE_BRTRUE_S) {
1402 int near_jump = *ip == CEE_BRTRUE_S;
1406 case VAL_I32: result = sp->data.i != 0; break;
1407 case VAL_I64: result = sp->data.l != 0; break;
1408 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1409 default: result = sp->data.p != NULL; break;
1413 ip += (signed char)*ip;
1415 ip += (gint32) read32 (ip);
1417 ip += near_jump ? 1: 4;
1420 CASE (CEE_BEQ) /* Fall through */
1423 int near_jump = *ip == CEE_BEQ_S;
1426 if (sp->type == VAL_I32)
1427 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1428 else if (sp->type == VAL_I64)
1429 result = sp [0].data.l == sp [1].data.l;
1430 else if (sp->type == VAL_DOUBLE)
1431 result = sp [0].data.f == sp [1].data.f;
1433 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1436 ip += (signed char)*ip;
1438 ip += (gint32) read32 (ip);
1440 ip += near_jump ? 1: 4;
1443 CASE (CEE_BGE) /* Fall through */
1446 int near_jump = *ip == CEE_BGE_S;
1449 if (sp->type == VAL_I32)
1450 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1451 else if (sp->type == VAL_I64)
1452 result = sp [0].data.l >= sp [1].data.l;
1453 else if (sp->type == VAL_DOUBLE)
1454 result = sp [0].data.f >= sp [1].data.f;
1456 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1459 ip += (signed char)*ip;
1461 ip += (gint32) read32 (ip);
1463 ip += near_jump ? 1: 4;
1466 CASE (CEE_BGT) /* Fall through */
1469 int near_jump = *ip == CEE_BGT_S;
1472 if (sp->type == VAL_I32)
1473 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1474 else if (sp->type == VAL_I64)
1475 result = sp [0].data.l > sp [1].data.l;
1476 else if (sp->type == VAL_DOUBLE)
1477 result = sp [0].data.f > sp [1].data.f;
1479 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1482 ip += (signed char)*ip;
1484 ip += (gint32) read32 (ip);
1486 ip += near_jump ? 1: 4;
1489 CASE (CEE_BLT) /* Fall through */
1492 int near_jump = *ip == CEE_BLT_S;
1495 if (sp->type == VAL_I32)
1496 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1497 else if (sp->type == VAL_I64)
1498 result = sp[0].data.l < sp[1].data.l;
1499 else if (sp->type == VAL_DOUBLE)
1500 result = sp[0].data.f < sp[1].data.f;
1502 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1505 ip += 1 + (signed char)*ip;
1507 ip += 4 + (gint32) read32 (ip);
1510 ip += near_jump ? 1: 4;
1514 CASE (CEE_BLE) /* fall through */
1517 int near_jump = *ip == CEE_BLE_S;
1521 if (sp->type == VAL_I32)
1522 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1523 else if (sp->type == VAL_I64)
1524 result = sp [0].data.l <= sp [1].data.l;
1525 else if (sp->type == VAL_DOUBLE)
1526 result = sp [0].data.f <= sp [1].data.f;
1529 * FIXME: here and in other places GET_NATI on the left side
1530 * _will_ be wrong when we change the macro to work on 64 bits
1533 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1537 ip += (signed char)*ip;
1539 ip += (gint32) read32 (ip);
1541 ip += near_jump ? 1: 4;
1544 CASE (CEE_BNE_UN) /* Fall through */
1545 CASE (CEE_BNE_UN_S) {
1547 int near_jump = *ip == CEE_BNE_UN_S;
1550 if (sp->type == VAL_I32)
1551 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1552 else if (sp->type == VAL_I64)
1553 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1554 else if (sp->type == VAL_DOUBLE)
1555 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1556 (sp [0].data.f != sp [1].data.f);
1558 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1561 ip += (signed char)*ip;
1563 ip += (gint32) read32 (ip);
1565 ip += near_jump ? 1: 4;
1568 CASE (CEE_BGE_UN) /* Fall through */
1569 CASE (CEE_BGE_UN_S) {
1571 int near_jump = *ip == CEE_BGE_UN_S;
1574 if (sp->type == VAL_I32)
1575 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1576 else if (sp->type == VAL_I64)
1577 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1578 else if (sp->type == VAL_DOUBLE)
1579 result = !isless (sp [0].data.f,sp [1].data.f);
1581 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1584 ip += (signed char)*ip;
1586 ip += (gint32) read32 (ip);
1588 ip += near_jump ? 1: 4;
1591 CASE (CEE_BGT_UN) /* Fall through */
1592 CASE (CEE_BGT_UN_S) {
1594 int near_jump = *ip == CEE_BGT_UN_S;
1597 if (sp->type == VAL_I32)
1598 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1599 else if (sp->type == VAL_I64)
1600 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1601 else if (sp->type == VAL_DOUBLE)
1602 result = isgreater (sp [0].data.f, sp [1].data.f);
1604 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1607 ip += (signed char)*ip;
1609 ip += (gint32) read32 (ip);
1611 ip += near_jump ? 1: 4;
1614 CASE (CEE_BLE_UN) /* Fall through */
1615 CASE (CEE_BLE_UN_S) {
1617 int near_jump = *ip == CEE_BLE_UN_S;
1620 if (sp->type == VAL_I32)
1621 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1622 else if (sp->type == VAL_I64)
1623 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1624 else if (sp->type == VAL_DOUBLE)
1625 result = islessequal (sp [0].data.f, sp [1].data.f);
1627 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1630 ip += (signed char)*ip;
1632 ip += (gint32) read32 (ip);
1634 ip += near_jump ? 1: 4;
1637 CASE (CEE_BLT_UN) /* Fall through */
1638 CASE (CEE_BLT_UN_S) {
1640 int near_jump = *ip == CEE_BLT_UN_S;
1643 if (sp->type == VAL_I32)
1644 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1645 else if (sp->type == VAL_I64)
1646 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1647 else if (sp->type == VAL_DOUBLE)
1648 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1649 (sp [0].data.f < sp [1].data.f);
1651 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1654 ip += (signed char)*ip;
1656 ip += (gint32) read32 (ip);
1658 ip += near_jump ? 1: 4;
1663 const unsigned char *st;
1667 st = ip + sizeof (gint32) * n;
1669 if ((guint32)sp->data.i < n) {
1671 ip += sizeof (gint32) * (guint32)sp->data.i;
1672 offset = read32 (ip);
1681 sp[-1].type = VAL_I32;
1682 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1686 sp[-1].type = VAL_I32;
1687 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1691 sp[-1].type = VAL_I32;
1692 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1696 sp[-1].type = VAL_I32;
1697 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1699 CASE (CEE_LDIND_I4) /* Fall through */
1702 sp[-1].type = VAL_I32;
1703 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1707 sp[-1].type = VAL_I64;
1708 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1712 sp[-1].type = VAL_NATI;
1713 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1717 sp[-1].type = VAL_DOUBLE;
1718 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
1722 sp[-1].type = VAL_DOUBLE;
1723 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
1725 CASE (CEE_LDIND_REF)
1727 sp[-1].type = VAL_OBJ;
1728 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1729 sp[-1].data.vt.klass = NULL;
1731 CASE (CEE_STIND_REF) {
1739 CASE (CEE_STIND_I1) {
1744 *p = (gint8)sp[1].data.i;
1747 CASE (CEE_STIND_I2) {
1752 *p = (gint16)sp[1].data.i;
1755 CASE (CEE_STIND_I4) {
1763 CASE (CEE_STIND_I) {
1768 *p = (mono_i)sp[1].data.p;
1771 CASE (CEE_STIND_I8) {
1779 CASE (CEE_STIND_R4) {
1784 *p = (gfloat)sp[1].data.f;
1787 CASE (CEE_STIND_R8) {
1798 /* should probably consider the pointers as unsigned */
1799 if (sp->type == VAL_I32)
1800 sp [-1].data.i += GET_NATI (sp [0]);
1801 else if (sp->type == VAL_I64)
1802 sp [-1].data.l += sp [0].data.l;
1803 else if (sp->type == VAL_DOUBLE)
1804 sp [-1].data.f += sp [0].data.f;
1806 char *p = sp [-1].data.p;
1807 p += GET_NATI (sp [0]);
1814 /* should probably consider the pointers as unsigned */
1815 if (sp->type == VAL_I32)
1816 sp [-1].data.i -= GET_NATI (sp [0]);
1817 else if (sp->type == VAL_I64)
1818 sp [-1].data.l -= sp [0].data.l;
1819 else if (sp->type == VAL_DOUBLE)
1820 sp [-1].data.f -= sp [0].data.f;
1822 char *p = sp [-1].data.p;
1823 p -= GET_NATI (sp [0]);
1830 if (sp->type == VAL_I32)
1831 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
1832 else if (sp->type == VAL_I64)
1833 sp [-1].data.l *= sp [0].data.l;
1834 else if (sp->type == VAL_DOUBLE)
1835 sp [-1].data.f *= sp [0].data.f;
1840 if (sp->type == VAL_I32) {
1841 if (GET_NATI (sp [0]) == 0)
1842 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1843 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
1844 } else if (sp->type == VAL_I64) {
1845 if (sp [0].data.l == 0)
1846 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1847 sp [-1].data.l /= sp [0].data.l;
1848 } else if (sp->type == VAL_DOUBLE) {
1849 /* set NaN is divisor is 0.0 */
1850 sp [-1].data.f /= sp [0].data.f;
1856 if (sp->type == VAL_I32) {
1858 if (GET_NATI (sp [0]) == 0)
1859 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1860 val = sp [-1].data.i;
1861 val /= (guint32)GET_NATI (sp [0]);
1862 sp [-1].data.i = val;
1863 } else if (sp->type == VAL_I64) {
1865 if (sp [0].data.l == 0)
1866 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1867 val = sp [-1].data.l;
1868 val /= (guint64)sp [0].data.l;
1869 sp [-1].data.l = val;
1870 } else if (sp->type == VAL_NATI) {
1872 if (GET_NATI (sp [0]) == 0)
1873 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1874 val = (mono_u)sp [-1].data.p;
1875 val /= (guint64)sp [0].data.p;
1876 sp [-1].data.p = (gpointer)val;
1882 if (sp->type == VAL_I32) {
1883 if (GET_NATI (sp [0]) == 0)
1884 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1885 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
1886 } else if (sp->type == VAL_I64) {
1887 if (sp [0].data.l == 0)
1888 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1889 sp [-1].data.l %= sp [0].data.l;
1890 } else if (sp->type == VAL_DOUBLE) {
1891 /* FIXME: what do we actually do here? */
1892 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
1894 if (GET_NATI (sp [0]) == 0)
1895 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1896 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
1902 if (sp->type == VAL_I32) {
1903 if (GET_NATI (sp [0]) == 0)
1904 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1905 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
1906 } else if (sp->type == VAL_I64) {
1907 if (sp [0].data.l == 0)
1908 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1909 (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
1910 } else if (sp->type == VAL_DOUBLE) {
1911 /* unspecified behaviour according to the spec */
1913 if (GET_NATI (sp [0]) == 0)
1914 THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
1915 (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
1921 if (sp->type == VAL_I32)
1922 sp [-1].data.i &= GET_NATI (sp [0]);
1923 else if (sp->type == VAL_I64)
1924 sp [-1].data.l &= sp [0].data.l;
1926 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1931 if (sp->type == VAL_I32)
1932 sp [-1].data.i |= GET_NATI (sp [0]);
1933 else if (sp->type == VAL_I64)
1934 sp [-1].data.l |= sp [0].data.l;
1936 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1941 if (sp->type == VAL_I32)
1942 sp [-1].data.i ^= GET_NATI (sp [0]);
1943 else if (sp->type == VAL_I64)
1944 sp [-1].data.l ^= sp [0].data.l;
1946 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1951 if (sp [-1].type == VAL_I32)
1952 sp [-1].data.i <<= GET_NATI (sp [0]);
1953 else if (sp [-1].type == VAL_I64)
1954 sp [-1].data.l <<= GET_NATI (sp [0]);
1956 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1961 if (sp [-1].type == VAL_I32)
1962 sp [-1].data.i >>= GET_NATI (sp [0]);
1963 else if (sp [-1].type == VAL_I64)
1964 sp [-1].data.l >>= GET_NATI (sp [0]);
1966 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1971 if (sp [-1].type == VAL_I32)
1972 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
1973 else if (sp [-1].type == VAL_I64)
1974 (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
1976 (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1981 if (sp->type == VAL_I32)
1982 sp->data.i = - sp->data.i;
1983 else if (sp->type == VAL_I64)
1984 sp->data.l = - sp->data.l;
1985 else if (sp->type == VAL_DOUBLE)
1986 sp->data.f = - sp->data.f;
1987 else if (sp->type == VAL_NATI)
1988 sp->data.p = (gpointer)(- (mono_i)sp->data.p);
1994 if (sp->type == VAL_I32)
1995 sp->data.i = ~ sp->data.i;
1996 else if (sp->type == VAL_I64)
1997 sp->data.l = ~ sp->data.l;
1998 else if (sp->type == VAL_NATI)
1999 sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
2002 CASE (CEE_CONV_U1) /* fall through */
2003 CASE (CEE_CONV_I1) {
2005 switch (sp [-1].type) {
2007 sp [-1].data.i = (gint8)sp [-1].data.f;
2010 sp [-1].data.i = (gint8)sp [-1].data.l;
2015 sp [-1].data.i = (gint8)sp [-1].data.i;
2018 sp [-1].data.i = (gint8)sp [-1].data.nati;
2021 sp [-1].type = VAL_I32;
2024 CASE (CEE_CONV_U2) /* fall through */
2025 CASE (CEE_CONV_I2) {
2027 switch (sp [-1].type) {
2029 sp [-1].data.i = (gint16)sp [-1].data.f;
2032 sp [-1].data.i = (gint16)sp [-1].data.l;
2037 sp [-1].data.i = (gint16)sp [-1].data.i;
2040 sp [-1].data.i = (gint16)sp [-1].data.nati;
2043 sp [-1].type = VAL_I32;
2046 CASE (CEE_CONV_U4) /* Fall through */
2047 #if SIZEOF_VOID_P == 4
2048 CASE (CEE_CONV_I) /* Fall through */
2049 CASE (CEE_CONV_U) /* Fall through */
2051 CASE (CEE_CONV_I4) {
2053 switch (sp [-1].type) {
2055 sp [-1].data.i = (gint32)sp [-1].data.f;
2058 sp [-1].data.i = (gint32)sp [-1].data.l;
2065 sp [-1].data.i = (gint32)sp [-1].data.p;
2068 sp [-1].type = VAL_I32;
2071 #if SIZEOF_VOID_P == 8
2072 CASE (CEE_CONV_I) /* Fall through */
2076 switch (sp [-1].type) {
2078 sp [-1].data.l = (gint64)sp [-1].data.f;
2085 sp [-1].data.l = (gint64)sp [-1].data.i;
2088 sp [-1].data.l = (gint64)sp [-1].data.nati;
2091 sp [-1].type = VAL_I64;
2093 CASE (CEE_CONV_R4) /* Fall through */
2094 CASE (CEE_CONV_R8) {
2096 switch (sp [-1].type) {
2098 sp [-1].data.f = (double)sp [-1].data.f;
2101 sp [-1].data.f = (double)sp [-1].data.l;
2106 sp [-1].data.f = (double)sp [-1].data.i;
2109 sp [-1].data.f = (double)sp [-1].data.nati;
2112 sp [-1].type = VAL_DOUBLE;
2115 #if SIZEOF_VOID_P == 8
2116 CASE (CEE_CONV_U) /* Fall through */
2121 switch (sp [-1].type){
2123 sp [-1].data.l = (guint64)sp [-1].data.f;
2130 sp [-1].data.l = (guint64) sp [-1].data.i;
2133 sp [-1].data.l = (guint64) sp [-1].data.nati;
2136 sp [-1].type = VAL_I64;
2141 vtklass = mono_class_get (image, read32 (ip));
2144 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
2153 token = read32 (ip);
2155 c = mono_class_get (image, token);
2156 addr = sp [-1].data.vt.vt;
2157 vt_alloc (&c->byval_arg, &sp [-1]);
2158 stackval_from_data (&c->byval_arg, &sp [-1], addr);
2166 index = mono_metadata_token_index (read32 (ip));
2169 o = (MonoObject*)mono_ldstr (domain, image, index);
2172 sp->data.vt.klass = NULL;
2179 MonoClass *newobj_class;
2180 MonoMethodSignature *csig;
2181 stackval valuetype_this;
2182 stackval *endsp = sp;
2188 token = read32 (ip);
2191 if (!(child_frame.method = mono_get_method (image, token, NULL)))
2192 THROW_EX (mono_get_exception_missing_method (), ip -5);
2194 csig = child_frame.method->signature;
2195 newobj_class = child_frame.method->klass;
2196 if (profiling_classes) {
2197 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2199 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2203 if (newobj_class->parent == mono_defaults.array_class) {
2204 sp -= csig->param_count;
2205 o = ves_array_create (domain, newobj_class, csig, sp);
2206 goto array_constructed;
2210 * First arg is the object.
2212 if (newobj_class->valuetype) {
2214 vt_alloc (&newobj_class->byval_arg, &valuetype_this);
2215 if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
2216 zero = valuetype_this.data.vt.vt;
2217 child_frame.obj = valuetype_this.data.vt.vt;
2219 memset (&valuetype_this, 0, sizeof (stackval));
2220 zero = &valuetype_this;
2221 child_frame.obj = &valuetype_this;
2223 stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero);
2225 o = mono_object_new (domain, newobj_class);
2226 child_frame.obj = o;
2229 if (csig->param_count) {
2230 sp -= csig->param_count;
2231 child_frame.stack_args = sp;
2233 child_frame.stack_args = NULL;
2236 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2238 child_frame.ex = NULL;
2239 child_frame.ex_handler = NULL;
2241 ves_exec_method (&child_frame);
2243 while (endsp > sp) {
2248 if (child_frame.ex) {
2250 * An exception occurred, need to run finally, fault and catch handlers..
2252 frame->ex = child_frame.ex;
2253 goto handle_finally;
2256 * a constructor returns void, but we need to return the object we created
2259 if (newobj_class->valuetype && !newobj_class->enumtype) {
2260 *sp = valuetype_this;
2264 sp->data.vt.klass = newobj_class;
2269 CASE (CEE_CASTCLASS) /* Fall through */
2273 MonoClass *c , *oclass;
2275 int do_isinst = *ip == CEE_ISINST;
2276 gboolean found = FALSE;
2279 token = read32 (ip);
2280 c = mono_class_get (image, token);
2282 mono_class_init (c);
2284 g_assert (sp [-1].type == VAL_OBJ);
2286 if ((o = sp [-1].data.p)) {
2291 if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
2292 if ((c->interface_id <= oclass->max_interface_id) &&
2293 vt->interface_offsets [c->interface_id])
2296 /* handle array casts */
2297 if (oclass->rank && oclass->rank == c->rank) {
2298 if ((oclass->element_class->baseval - c->element_class->baseval) <= c->element_class->diffval) {
2299 sp [-1].data.vt.klass = c;
2302 } else if ((oclass->baseval - c->baseval) <= c->diffval) {
2303 sp [-1].data.vt.klass = c;
2310 sp [-1].data.p = NULL;
2311 sp [-1].data.vt.klass = NULL;
2313 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2319 CASE (CEE_CONV_R_UN)
2320 switch (sp [-1].type) {
2324 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2329 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2332 sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
2335 sp [-1].type = VAL_DOUBLE;
2338 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2345 token = read32 (ip);
2347 c = mono_class_get (image, token);
2348 mono_class_init (c);
2352 THROW_EX (mono_get_exception_null_reference(), ip - 1);
2354 if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
2355 THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
2357 sp [-1].type = VAL_MP;
2358 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2365 THROW_EX (sp->data.p, ip);
2367 CASE (CEE_LDFLDA) /* Fall through */
2370 MonoClassField *field;
2371 guint32 token, offset;
2372 int load_addr = *ip == CEE_LDFLDA;
2374 if (!sp [-1].data.p)
2375 THROW_EX (mono_get_exception_null_reference (), ip);
2378 token = read32 (ip);
2381 if (sp [-1].type == VAL_OBJ) {
2382 obj = sp [-1].data.p;
2383 field = mono_class_get_field (obj->vtable->klass, token);
2384 offset = field->offset;
2385 } else { /* valuetype */
2386 /*g_assert (sp [-1].type == VAL_VALUETA); */
2387 obj = sp [-1].data.vt.vt;
2388 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2389 offset = field->offset - sizeof (MonoObject);
2392 sp [-1].type = VAL_TP;
2393 sp [-1].data.p = (char*)obj + offset;
2394 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2396 vt_alloc (field->type, &sp [-1]);
2397 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2404 MonoClassField *field;
2405 guint32 token, offset;
2408 token = read32 (ip);
2413 if (sp [0].type == VAL_OBJ) {
2414 obj = sp [0].data.p;
2415 field = mono_class_get_field (obj->vtable->klass, token);
2416 offset = field->offset;
2417 } else { /* valuetype */
2418 /*g_assert (sp->type == VAL_VALUETA); */
2419 obj = sp [0].data.vt.vt;
2420 field = mono_class_get_field (sp [0].data.vt.klass, token);
2421 offset = field->offset - sizeof (MonoObject);
2424 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2428 CASE (CEE_LDSFLD) /* Fall through */
2429 CASE (CEE_LDSFLDA) {
2432 MonoClassField *field;
2434 int load_addr = *ip == CEE_LDSFLDA;
2438 token = read32 (ip);
2441 /* need to handle fieldrefs */
2442 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2443 field = mono_field_from_memberref (image, token, &klass);
2444 mono_class_init (klass);
2446 klass = mono_class_get (image,
2447 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2448 mono_class_init (klass);
2449 field = mono_class_get_field (klass, token);
2453 vt = mono_class_vtable (domain, klass);
2454 addr = (char*)(vt->data) + field->offset;
2459 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2461 vt_alloc (field->type, sp);
2462 stackval_from_data (field->type, sp, addr);
2470 MonoClassField *field;
2475 token = read32 (ip);
2479 /* need to handle fieldrefs */
2480 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
2481 field = mono_field_from_memberref (image, token, &klass);
2482 mono_class_init (klass);
2484 klass = mono_class_get (image,
2485 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2486 mono_class_init (klass);
2487 field = mono_class_get_field (klass, token);
2491 vt = mono_class_vtable (domain, klass);
2492 addr = (char*)(vt->data) + field->offset;
2494 stackval_to_data (field->type, sp, addr);
2501 vtklass = mono_class_get (image, read32 (ip));
2504 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2507 #if SIZEOF_VOID_P == 8
2508 CASE (CEE_CONV_OVF_I_UN)
2510 CASE (CEE_CONV_OVF_I8_UN) {
2511 switch (sp [-1].type) {
2513 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2514 THROW_EX (mono_get_exception_overflow (), ip);
2515 sp [-1].data.l = (guint64)sp [-1].data.f;
2518 if (sp [-1].data.l < 0)
2519 THROW_EX (mono_get_exception_overflow (), ip);
2524 /* Can't overflow */
2525 sp [-1].data.l = (guint64)sp [-1].data.i;
2528 if ((gint64)sp [-1].data.nati < 0)
2529 THROW_EX (mono_get_exception_overflow (), ip);
2530 sp [-1].data.l = (guint64)sp [-1].data.nati;
2533 sp [-1].type = VAL_I64;
2537 #if SIZEOF_VOID_P == 8
2538 CASE (CEE_CONV_OVF_U_UN)
2540 CASE (CEE_CONV_OVF_U8_UN) {
2541 switch (sp [-1].type) {
2543 if (sp [-1].data.f < 0 || sp [-1].data.f > GUINT64_MAX)
2544 THROW_EX (mono_get_exception_overflow (), ip);
2545 sp [-1].data.l = (guint64)sp [-1].data.f;
2553 /* Can't overflow */
2554 sp [-1].data.l = (guint64)sp [-1].data.i;
2557 /* Can't overflow */
2558 sp [-1].data.l = (guint64)sp [-1].data.nati;
2561 sp [-1].type = VAL_I64;
2565 #if SIZEOF_VOID_P == 4
2566 CASE (CEE_CONV_OVF_I_UN)
2567 CASE (CEE_CONV_OVF_U_UN)
2569 CASE (CEE_CONV_OVF_I1_UN)
2570 CASE (CEE_CONV_OVF_I2_UN)
2571 CASE (CEE_CONV_OVF_I4_UN)
2572 CASE (CEE_CONV_OVF_U1_UN)
2573 CASE (CEE_CONV_OVF_U2_UN)
2574 CASE (CEE_CONV_OVF_U4_UN) {
2576 switch (sp [-1].type) {
2578 value = (guint64)sp [-1].data.f;
2581 value = (guint64)sp [-1].data.l;
2586 value = (guint64)sp [-1].data.i;
2589 value = (guint64)sp [-1].data.nati;
2593 case CEE_CONV_OVF_I1_UN:
2595 THROW_EX (mono_get_exception_overflow (), ip);
2596 sp [-1].data.i = value;
2597 sp [-1].type = VAL_I32;
2599 case CEE_CONV_OVF_I2_UN:
2601 THROW_EX (mono_get_exception_overflow (), ip);
2602 sp [-1].data.i = value;
2603 sp [-1].type = VAL_I32;
2605 #if SIZEOF_VOID_P == 4
2606 case CEE_CONV_OVF_I_UN: /* Fall through */
2608 case CEE_CONV_OVF_I4_UN:
2609 if (value > 2147483647)
2610 THROW_EX (mono_get_exception_overflow (), ip);
2611 sp [-1].data.i = value;
2612 sp [-1].type = VAL_I32;
2614 case CEE_CONV_OVF_U1_UN:
2616 THROW_EX (mono_get_exception_overflow (), ip);
2617 sp [-1].data.i = value;
2618 sp [-1].type = VAL_I32;
2620 case CEE_CONV_OVF_U2_UN:
2622 THROW_EX (mono_get_exception_overflow (), ip);
2623 sp [-1].data.i = value;
2624 sp [-1].type = VAL_I32;
2626 #if SIZEOF_VOID_P == 4
2627 case CEE_CONV_OVF_U_UN: /* Fall through */
2629 case CEE_CONV_OVF_U4_UN:
2630 if (value > 4294967295U)
2631 THROW_EX (mono_get_exception_overflow (), ip);
2632 sp [-1].data.i = value;
2633 sp [-1].type = VAL_I32;
2636 g_assert_not_reached ();
2646 token = read32 (ip);
2648 class = mono_class_get (image, token);
2649 mono_class_init (class);
2650 g_assert (class != NULL);
2652 sp [-1].type = VAL_OBJ;
2653 if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype)
2654 sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
2656 sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
2657 /* need to vt_free (sp); */
2669 token = read32 (ip);
2670 class = mono_class_get (image, token);
2671 o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
2674 sp [-1].type = VAL_OBJ;
2676 if (profiling_classes) {
2677 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
2679 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
2689 g_assert (sp [-1].type == VAL_OBJ);
2693 THROW_EX (mono_get_exception_null_reference (), ip - 1);
2695 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2697 sp [-1].type = VAL_I32;
2698 sp [-1].data.i = mono_array_length (o);
2702 CASE (CEE_LDELEMA) {
2704 guint32 esize, token;
2707 token = read32 (ip);
2711 g_assert (sp [0].type == VAL_OBJ);
2714 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2716 if (sp [1].data.nati >= mono_array_length (o))
2717 THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
2719 /* check the array element corresponds to token */
2720 esize = mono_array_element_size (o->obj.vtable->klass);
2723 sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
2724 sp->data.vt.klass = o->obj.vtable->klass->element_class;
2729 CASE (CEE_LDELEM_I1) /* fall through */
2730 CASE (CEE_LDELEM_U1) /* fall through */
2731 CASE (CEE_LDELEM_I2) /* fall through */
2732 CASE (CEE_LDELEM_U2) /* fall through */
2733 CASE (CEE_LDELEM_I4) /* fall through */
2734 CASE (CEE_LDELEM_U4) /* fall through */
2735 CASE (CEE_LDELEM_I8) /* fall through */
2736 CASE (CEE_LDELEM_I) /* fall through */
2737 CASE (CEE_LDELEM_R4) /* fall through */
2738 CASE (CEE_LDELEM_R8) /* fall through */
2739 CASE (CEE_LDELEM_REF) {
2745 g_assert (sp [0].type == VAL_OBJ);
2748 THROW_EX (mono_get_exception_null_reference (), ip);
2750 g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
2752 aindex = sp [1].data.nati;
2753 if (aindex >= mono_array_length (o))
2754 THROW_EX (mono_get_exception_index_out_of_range (), ip);
2757 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
2761 sp [0].data.i = mono_array_get (o, gint8, aindex);
2762 sp [0].type = VAL_I32;
2765 sp [0].data.i = mono_array_get (o, guint8, aindex);
2766 sp [0].type = VAL_I32;
2769 sp [0].data.i = mono_array_get (o, gint16, aindex);
2770 sp [0].type = VAL_I32;
2773 sp [0].data.i = mono_array_get (o, guint16, aindex);
2774 sp [0].type = VAL_I32;
2777 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
2778 sp [0].type = VAL_NATI;
2781 sp [0].data.i = mono_array_get (o, gint32, aindex);
2782 sp [0].type = VAL_I32;
2785 sp [0].data.i = mono_array_get (o, guint32, aindex);
2786 sp [0].type = VAL_I32;
2789 sp [0].data.l = mono_array_get (o, gint64, aindex);
2790 sp [0].type = VAL_I64;
2793 sp [0].data.f = mono_array_get (o, float, aindex);
2794 sp [0].type = VAL_DOUBLE;
2797 sp [0].data.f = mono_array_get (o, double, aindex);
2798 sp [0].type = VAL_DOUBLE;
2800 case CEE_LDELEM_REF:
2801 sp [0].data.p = mono_array_get (o, gpointer, aindex);
2802 sp [0].data.vt.klass = NULL;
2803 sp [0].type = VAL_OBJ;
2813 CASE (CEE_STELEM_I) /* fall through */
2814 CASE (CEE_STELEM_I1) /* fall through */
2815 CASE (CEE_STELEM_I2) /* fall through */
2816 CASE (CEE_STELEM_I4) /* fall through */
2817 CASE (CEE_STELEM_I8) /* fall through */
2818 CASE (CEE_STELEM_R4) /* fall through */
2819 CASE (CEE_STELEM_R8) /* fall through */
2820 CASE (CEE_STELEM_REF) {
2827 g_assert (sp [0].type == VAL_OBJ);
2830 THROW_EX (mono_get_exception_null_reference (), ip);
2832 ac = o->obj.vtable->klass;
2833 g_assert (MONO_CLASS_IS_ARRAY (ac));
2835 aindex = sp [1].data.nati;
2836 if (aindex >= mono_array_length (o))
2837 THROW_EX (mono_get_exception_index_out_of_range (), ip);
2840 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
2844 mono_array_set (o, mono_i, aindex, sp [2].data.nati);
2847 mono_array_set (o, gint8, aindex, sp [2].data.i);
2850 mono_array_set (o, gint16, aindex, sp [2].data.i);
2853 mono_array_set (o, gint32, aindex, sp [2].data.i);
2856 mono_array_set (o, gint64, aindex, sp [2].data.l);
2859 mono_array_set (o, float, aindex, sp [2].data.f);
2862 mono_array_set (o, double, aindex, sp [2].data.f);
2864 case CEE_STELEM_REF:
2865 g_assert (sp [2].type == VAL_OBJ);
2866 mono_array_set (o, gpointer, aindex, sp [2].data.p);
2890 CASE (CEE_UNUSED17) ves_abort(); BREAK;
2891 CASE (CEE_CONV_OVF_I1)
2892 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
2893 CASE (CEE_CONV_OVF_I2)
2894 CASE (CEE_CONV_OVF_U2)
2896 /* FIXME: handle other cases */
2897 if (sp [-1].type == VAL_I32) {
2898 /* defined as NOP */
2903 CASE (CEE_CONV_OVF_I4)
2905 /* FIXME: handle other cases */
2906 if (sp [-1].type == VAL_I32) {
2907 /* defined as NOP */
2908 } else if(sp [-1].type == VAL_I64) {
2909 sp [-1].data.i = (gint32)sp [-1].data.l;
2915 CASE (CEE_CONV_OVF_U4)
2917 /* FIXME: handle other cases */
2918 if (sp [-1].type == VAL_I32) {
2919 /* defined as NOP */
2924 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2925 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
2932 CASE (CEE_UNUSED23) ves_abort(); BREAK;
2933 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
2935 if (!finite(sp [-1].data.f))
2936 THROW_EX (mono_get_exception_arithmetic (), ip);
2939 CASE (CEE_UNUSED24) ves_abort(); BREAK;
2940 CASE (CEE_UNUSED25) ves_abort(); BREAK;
2941 CASE (CEE_MKREFANY) ves_abort(); BREAK;
2950 CASE (CEE_UNUSED67) ves_abort(); BREAK;
2951 CASE (CEE_LDTOKEN) {
2953 MonoClass *handle_class;
2955 handle = mono_ldtoken (image, read32 (ip), &handle_class);
2957 vt_alloc (&handle_class->byval_arg, sp);
2958 stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle);
2962 CASE (CEE_CONV_OVF_I)
2965 /* FIXME: check overflow. */
2968 sp->data.p = (gpointer)(mono_i) sp->data.i;
2971 sp->data.p = (gpointer)(mono_i) sp->data.l;
2976 sp->data.p = (gpointer)(mono_i) sp->data.f;
2981 sp->type = VAL_NATI;
2984 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
2986 CASE (CEE_ADD_OVF_UN)
2988 /* FIXME: check overflow, make unsigned */
2989 if (sp->type == VAL_I32) {
2990 if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
2991 THROW_EX (mono_get_exception_overflow (), ip);
2992 sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
2993 } else if (sp->type == VAL_I64) {
2994 if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
2995 THROW_EX (mono_get_exception_overflow (), ip);
2996 sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
2997 } else if (sp->type == VAL_DOUBLE)
2998 sp [-1].data.f += sp [0].data.f;
3000 char *p = sp [-1].data.p;
3001 p += GET_NATI (sp [0]);
3009 /* FIXME: check overflow */
3010 if (sp->type == VAL_I32)
3011 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3012 else if (sp->type == VAL_I64)
3013 sp [-1].data.l *= sp [0].data.l;
3014 else if (sp->type == VAL_DOUBLE)
3015 sp [-1].data.f *= sp [0].data.f;
3017 CASE (CEE_MUL_OVF_UN)
3020 /* FIXME: check overflow, make unsigned */
3021 if (sp->type == VAL_I32)
3022 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
3023 else if (sp->type == VAL_I64)
3024 sp [-1].data.l *= sp [0].data.l;
3025 else if (sp->type == VAL_DOUBLE)
3026 sp [-1].data.f *= sp [0].data.f;
3029 CASE (CEE_SUB_OVF_UN)
3032 /* FIXME: handle undeflow/unsigned */
3033 /* should probably consider the pointers as unsigned */
3034 if (sp->type == VAL_I32)
3035 sp [-1].data.i -= GET_NATI (sp [0]);
3036 else if (sp->type == VAL_I64)
3037 sp [-1].data.l -= sp [0].data.l;
3038 else if (sp->type == VAL_DOUBLE)
3039 sp [-1].data.f -= sp [0].data.f;
3041 char *p = sp [-1].data.p;
3042 p -= GET_NATI (sp [0]);
3046 CASE (CEE_ENDFINALLY)
3050 * There was no exception, we continue normally at the target address.
3054 CASE (CEE_LEAVE) /* Fall through */
3056 sp = frame->stack; /* empty the stack */
3058 if (*ip == CEE_LEAVE_S) {
3060 ip += (signed char) *ip;
3064 ip += (gint32) read32 (ip);
3069 * We may be either inside a try block or inside an handler.
3070 * In the first case there was no exception and we go on
3071 * executing the finally handlers and after that resume control
3073 * In the second case we need to clear the exception and
3074 * continue directly at the target ip.
3078 goto handle_finally;
3081 frame->ex_handler = NULL;
3085 frame->ex_handler = NULL;
3087 goto handle_finally;
3118 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
3120 * Note: Exceptions thrown when executing a prefixed opcode need
3121 * to take into account the number of prefix bytes (usually the
3122 * throw point is just (ip - n_prefix_bytes).
3127 case CEE_ARGLIST: ves_abort(); break;
3133 if (sp->type == VAL_I32)
3134 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
3135 else if (sp->type == VAL_I64)
3136 result = sp [0].data.l == sp [1].data.l;
3137 else if (sp->type == VAL_DOUBLE) {
3138 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3141 result = sp [0].data.f == sp [1].data.f;
3143 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
3145 sp->data.i = result;
3155 if (sp->type == VAL_I32)
3156 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
3157 else if (sp->type == VAL_I64)
3158 result = sp [0].data.l > sp [1].data.l;
3159 else if (sp->type == VAL_DOUBLE) {
3160 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3163 result = sp [0].data.f > sp [1].data.f;
3165 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
3167 sp->data.i = result;
3177 if (sp->type == VAL_I32)
3178 result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
3179 else if (sp->type == VAL_I64)
3180 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
3181 else if (sp->type == VAL_DOUBLE)
3182 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3184 result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
3186 sp->data.i = result;
3196 if (sp->type == VAL_I32)
3197 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
3198 else if (sp->type == VAL_I64)
3199 result = sp [0].data.l < sp [1].data.l;
3200 else if (sp->type == VAL_DOUBLE) {
3201 if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
3204 result = sp [0].data.f < sp [1].data.f;
3206 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
3208 sp->data.i = result;
3218 if (sp->type == VAL_I32)
3219 result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
3220 else if (sp->type == VAL_I64)
3221 result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
3222 else if (sp->type == VAL_DOUBLE)
3223 result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
3225 result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
3227 sp->data.i = result;
3233 case CEE_LDVIRTFTN: {
3234 int virtual = *ip == CEE_LDVIRTFTN;
3238 token = read32 (ip);
3240 m = mono_get_method (image, token, NULL);
3242 THROW_EX (mono_get_exception_missing_method (), ip - 5);
3246 THROW_EX (mono_get_exception_null_reference (), ip - 5);
3247 m = get_virtual_method (domain, m, sp);
3249 sp->type = VAL_NATI;
3250 sp->data.p = mono_create_method_pointer (m);
3251 sp->data.vt.klass = NULL;
3255 case CEE_UNUSED56: ves_abort(); break;
3259 arg_pos = read16 (ip);
3261 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
3262 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3274 t = ARG_TYPE (signature, anum);
3275 c = mono_class_from_mono_type (t);
3276 sp->data.vt.klass = c;
3277 sp->data.vt.vt = ARG_POS (anum);
3280 sp->type = VAL_VALUETA;
3291 arg_pos = read16 (ip);
3294 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
3301 loc_pos = read16 (ip);
3303 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
3304 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3314 loc_pos = read16 (ip);
3316 t = LOCAL_TYPE (header, loc_pos);
3317 c = mono_class_from_mono_type (t);
3318 sp->data.vt.vt = LOCAL_POS (loc_pos);
3319 sp->data.vt.klass = c;
3322 sp->type = VAL_VALUETA;
3332 loc_pos = read16 (ip);
3335 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
3340 if (sp != frame->stack)
3341 THROW_EX (mono_get_exception_execution_engine (), ip - 1);
3343 sp->data.p = alloca (sp->data.i);
3346 case CEE_UNUSED57: ves_abort(); break;
3347 case CEE_ENDFILTER: ves_abort(); break;
3348 case CEE_UNALIGNED_:
3350 unaligned_address = 1;
3354 volatile_address = 1;
3363 token = read32 (ip);
3366 * we ignore the value of token (I think we can as unspecified
3367 * behavior described in Partition II, 3.5).
3370 g_assert (sp->type == VAL_VALUETA);
3371 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
3374 case CEE_UNUSED68: ves_abort(); break;
3377 if (!sp [0].data.p || !sp [1].data.p)
3378 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3380 /* FIXME: value and size may be int64... */
3381 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3386 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3388 /* FIXME: value and size may be int64... */
3389 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3391 case CEE_UNUSED69: ves_abort(); break;
3394 * need to clarify what this should actually do:
3395 * start the search from the last found handler in
3396 * this method or continue in the caller or what.
3397 * Also, do we need to run finally/fault handlers after a retrow?
3398 * Well, this implementation will follow the usual search
3399 * for an handler, considering the current ip as throw spot.
3400 * We need to NULL frame->ex_handler for the later code to
3401 * actually run the new found handler.
3403 frame->ex_handler = NULL;
3404 THROW_EX (frame->ex, ip - 1);
3406 case CEE_UNUSED: ves_abort(); break;
3412 token = read32 (ip);
3414 type = mono_type_create_from_typespec (image, token);
3416 sp->data.i = mono_type_size (type, &align);
3417 mono_metadata_free_type (type);
3421 case CEE_REFANYTYPE: ves_abort(); break;
3428 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
3435 g_assert_not_reached ();
3437 * Exception handling code.
3438 * The exception object is stored in frame->ex.
3445 MonoInvocation *inv;
3446 MonoMethodHeader *hd;
3447 MonoExceptionClause *clause;
3451 if (die_on_exception)
3454 for (inv = frame; inv; inv = inv->parent) {
3455 if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
3457 hd = ((MonoMethodNormal*)inv->method)->header;
3458 ip_offset = inv->ip - hd->code;
3459 for (i = 0; i < hd->num_clauses; ++i) {
3460 clause = &hd->clauses [i];
3461 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3462 if (!clause->flags) {
3463 if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
3465 * OK, we found an handler, now we need to execute the finally
3466 * and fault blocks before branching to the handler code.
3468 inv->ex_handler = clause;
3470 * It seems that if the catch handler is found in the same method,
3471 * it gets executed before the finally handler.
3476 goto handle_finally;
3479 /* FIXME: handle filter clauses */
3486 * If we get here, no handler was found: print a stack trace.
3489 ex_obj = (MonoObject*)frame->ex;
3490 message = frame->ex->message? mono_string_to_utf8 (frame->ex->message): NULL;
3491 g_print ("Unhandled exception %s.%s %s.\n", ex_obj->vtable->klass->name_space, ex_obj->vtable->klass->name,
3492 message?message:"");
3501 MonoExceptionClause *clause;
3503 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3507 ip_offset = frame->ip - header->code;
3509 for (i = 0; i < header->num_clauses; ++i) {
3510 clause = &header->clauses [i];
3511 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3512 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3513 ip = header->code + clause->handler_offset;
3521 * If an exception is set, we need to execute the fault handler, too,
3522 * otherwise, we continue normally.
3533 MonoExceptionClause *clause;
3535 ip_offset = frame->ip - header->code;
3536 for (i = 0; i < header->num_clauses; ++i) {
3537 clause = &header->clauses [i];
3538 if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
3539 ip = header->code + clause->handler_offset;
3544 * If the handler for the exception was found in this method, we jump
3545 * to it right away, otherwise we return and let the caller run
3546 * the finally, fault and catch blocks.
3547 * This same code should be present in the endfault opcode, but it
3548 * is corrently not assigned in the ECMA specs: LAMESPEC.
3550 if (frame->ex_handler) {
3551 ip = header->code + frame->ex_handler->handler_offset;
3554 sp->data.p = frame->ex;
3565 runtime_exec_main (MonoMethod *method, MonoArray *args)
3568 stackval argv_array;
3569 MonoInvocation call;
3571 argv_array.type = VAL_OBJ;
3572 argv_array.data.p = args;
3573 argv_array.data.vt.klass = NULL;
3576 INIT_FRAME (&call, NULL, NULL, &argv_array, &result, method);
3578 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
3580 ves_exec_method (&call);
3582 return result.data.i;
3587 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
3589 MonoArray *args = NULL;
3590 MonoImage *image = assembly->image;
3591 MonoCLIImageInfo *iinfo;
3595 iinfo = image->image_info;
3596 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3598 g_error ("No entry point method found in %s", image->name);
3600 if (method->signature->param_count) {
3601 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3602 for (i = 0; i < argc; ++i) {
3603 MonoString *arg = mono_string_new (domain, argv [i]);
3604 mono_array_set (args, gpointer, i, mono_string_intern (arg));
3608 return mono_runtime_exec_main (method, args);
3615 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3616 "Usage is: mint [options] executable args...\n", VERSION);
3618 "Valid Options are:\n"
3622 "--debug method_name\n"
3624 "--opcode-count\n");
3630 test_load_class (MonoImage* image)
3632 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3636 for (i = 1; i <= t->rows; ++i) {
3637 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3638 mono_class_init (klass);
3654 typebuilder_fields[] = {
3655 {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
3656 {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
3657 {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
3658 {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
3659 {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
3660 {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
3661 {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
3662 {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
3663 {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
3668 modulebuilder_fields[] = {
3669 {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
3670 {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
3675 assemblybuilder_fields[] = {
3676 {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
3677 {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
3678 {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
3683 ctorbuilder_fields[] = {
3684 {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
3685 {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
3686 {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
3687 {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
3688 {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
3689 {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
3690 {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
3695 methodbuilder_fields[] = {
3696 {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
3697 {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
3698 {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
3699 {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
3700 {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
3701 {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
3702 {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
3703 {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
3704 {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
3705 {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
3706 {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
3707 {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
3708 {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
3709 {"ncharset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
3710 {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
3711 {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
3716 fieldbuilder_fields[] = {
3717 {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
3718 {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
3719 {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
3720 {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
3721 {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
3722 {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
3727 propertybuilder_fields[] = {
3728 {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
3729 {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
3730 {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
3731 {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
3732 {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
3733 {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
3734 {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
3735 {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
3740 ilgenerator_fields[] = {
3741 {"code", G_STRUCT_OFFSET (MonoReflectionILGen, code)},
3742 {"mbuilder", G_STRUCT_OFFSET (MonoReflectionILGen, mbuilder)},
3743 {"code_len", G_STRUCT_OFFSET (MonoReflectionILGen, code_len)},
3744 {"max_stack", G_STRUCT_OFFSET (MonoReflectionILGen, max_stack)},
3745 {"cur_stack", G_STRUCT_OFFSET (MonoReflectionILGen, cur_stack)},
3746 {"locals", G_STRUCT_OFFSET (MonoReflectionILGen, locals)},
3747 {"ex_handlers", G_STRUCT_OFFSET (MonoReflectionILGen, ex_handlers)},
3752 emit_classes_to_check [] = {
3753 {"TypeBuilder", typebuilder_fields},
3754 {"ModuleBuilder", modulebuilder_fields},
3755 {"AssemblyBuilder", assemblybuilder_fields},
3756 {"ConstructorBuilder", ctorbuilder_fields},
3757 {"MethodBuilder", methodbuilder_fields},
3758 {"FieldBuilder", fieldbuilder_fields},
3759 {"PropertyBuilder", propertybuilder_fields},
3760 {"ILGenerator", ilgenerator_fields},
3765 delegate_fields[] = {
3766 {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
3767 {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
3768 {"method", G_STRUCT_OFFSET (MonoDelegate, method)},
3769 {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
3774 system_classes_to_check [] = {
3775 {"Delegate", delegate_fields},
3784 static NameSpaceDesc
3785 namespaces_to_check[] = {
3786 {"System.Reflection.Emit", emit_classes_to_check},
3787 {"System", system_classes_to_check},
3792 check_corlib (MonoImage *corlib)
3795 MonoClassField *field;
3798 NameSpaceDesc *ndesc;
3800 for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
3801 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
3802 klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
3804 g_error ("Cannot find class %s", cdesc->name);
3805 mono_class_init (klass);
3806 for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
3807 field = mono_class_get_field_from_name (klass, fdesc->name);
3808 if (!field || (field->offset != fdesc->offset))
3809 g_error ("field `%s' mismatch in class %s (%ld != %ld)", fdesc->name, cdesc->name, (long) fdesc->offset, (long) (field?field->offset:-1));
3816 compare_profile (MethodProfile *profa, MethodProfile *profb)
3818 return (gint)((profb->total - profa->total)*1000);
3822 build_profile (MonoMethod *m, MethodProfile *prof, GList **funcs)
3824 g_timer_destroy (prof->u.timer);
3826 *funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_profile);
3830 output_profile (GList *funcs)
3837 g_print ("Method name\t\t\t\t\tTotal (ms) Calls Per call (ms)\n");
3838 for (tmp = funcs; tmp; tmp = tmp->next) {
3840 if (!(gint)(p->total*1000))
3842 g_snprintf (buf, sizeof (buf), "%s.%s::%s(%d)",
3843 p->u.method->klass->name_space, p->u.method->klass->name,
3844 p->u.method->name, p->u.method->signature->param_count);
3845 printf ("%-52s %7d %7ld %7d\n", buf,
3846 (gint)(p->total*1000), p->count, (gint)((p->total*1000)/p->count));
3856 compare_newobj_profile (NewobjProfile *profa, NewobjProfile *profb)
3858 return (gint)profb->count - (gint)profa->count;
3862 build_newobj_profile (MonoClass *class, gpointer count, GList **funcs)
3864 NewobjProfile *prof = g_new (NewobjProfile, 1);
3865 prof->klass = class;
3866 prof->count = GPOINTER_TO_UINT (count);
3867 *funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_newobj_profile);
3871 output_newobj_profile (GList *proflist)
3880 g_print ("\n%-52s %9s\n", "Objects created:", "count");
3881 for (tmp = proflist; tmp; tmp = tmp->next) {
3884 if (strcmp (klass->name, "Array") == 0) {
3886 klass = klass->element_class;
3890 g_snprintf (buf, sizeof (buf), "%s.%s%s",
3891 klass->name_space, klass->name, isarray);
3892 g_print ("%-52s %9d\n", buf, p->count);
3896 static MonoException * segv_exception = NULL;
3899 segv_handler (int signum)
3901 signal (signum, segv_handler);
3902 mono_raise_exception (segv_exception);
3906 main (int argc, char *argv [])
3909 MonoAssembly *assembly;
3910 GList *profile = NULL;
3911 int retval = 0, i, ocount = 0;
3917 for (i = 1; i < argc && argv [i][0] == '-'; i++){
3918 if (strcmp (argv [i], "--trace") == 0)
3920 if (strcmp (argv [i], "--traceops") == 0)
3922 if (strcmp (argv [i], "--dieonex") == 0)
3923 die_on_exception = 1;
3924 if (strcmp (argv [i], "--print-vtable") == 0)
3925 mono_print_vtable = TRUE;
3926 if (strcmp (argv [i], "--profile") == 0) {
3927 profiling = g_hash_table_new (g_direct_hash, g_direct_equal);
3928 profiling_classes = g_hash_table_new (g_direct_hash, g_direct_equal);
3930 if (strcmp (argv [i], "--opcode-count") == 0)
3932 if (strcmp (argv [i], "--help") == 0)
3935 if (strcmp (argv [i], "--debug") == 0)
3936 db_methods = g_list_append (db_methods, argv [++i]);
3946 mono_add_internal_call ("__array_Set", ves_array_set);
3947 mono_add_internal_call ("__array_Get", ves_array_get);
3948 mono_add_internal_call ("__array_Address", ves_array_element_address);
3950 frame_thread_id = TlsAlloc ();
3951 TlsSetValue (frame_thread_id, NULL);
3953 mono_install_runtime_class_init (runtime_class_init);
3954 mono_install_runtime_object_init (runtime_object_init);
3955 mono_install_runtime_exec_main (runtime_exec_main);
3956 mono_install_runtime_invoke (interp_mono_runtime_invoke);
3958 mono_install_handler (interp_ex_handler);
3960 domain = mono_init (file);
3961 mono_thread_init (domain);
3962 mono_network_init ();
3964 assembly = mono_domain_assembly_open (domain, file);
3967 fprintf (stderr, "Can not open image %s\n", file);
3973 test_load_class (assembly->image);
3975 check_corlib (mono_defaults.corlib);
3976 segv_exception = mono_get_exception_null_reference ();
3977 segv_exception->message = mono_string_new (domain, "Segmentation fault");
3978 signal (SIGSEGV, segv_handler);
3980 * skip the program name from the args.
3983 retval = ves_exec (domain, assembly, argc - i, argv + i);
3986 g_hash_table_foreach (profiling, (GHFunc)build_profile, &profile);
3987 output_profile (profile);
3988 g_list_free (profile);
3991 g_hash_table_foreach (profiling_classes, (GHFunc)build_newobj_profile, &profile);
3992 output_newobj_profile (profile);
3993 g_list_free (profile);
3996 mono_network_cleanup ();
3997 mono_thread_cleanup ();
3999 mono_domain_unload (domain, TRUE);
4003 fprintf (stderr, "opcode count: %ld\n", opcode_count);
4004 fprintf (stderr, "fcall count: %ld\n", fcall_count);