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.
23 # define alloca __builtin_alloca
27 /* trim excessive headers */
28 #include <mono/metadata/image.h>
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/cil-coff.h>
31 #include <mono/metadata/endian.h>
32 #include <mono/metadata/tabledefs.h>
33 #include <mono/metadata/blob.h>
34 #include <mono/metadata/tokentype.h>
35 #include <mono/metadata/loader.h>
36 #include <mono/arch/x86/x86-codegen.h>
37 /*#include <mono/cli/types.h>*/
42 /* If true, then we output the opcodes as we interpret them */
43 static int tracing = 0;
45 static int debug_indent_level = 0;
48 * Pull the list of opcodes
50 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
54 #include "mono/cil/opcode.def"
60 * Pull the opcode names
62 #define OPDEF(a,b,c,d,e,f,g,h,i,j) b,
63 static char *opcode_names[] = {
64 #include "mono/cil/opcode.def"
68 #define GET_NATI(sp) ((sp).data.nati)
69 #define CSIZE(x) (sizeof (x) / 4)
71 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method) \
73 (frame)->parent = (parent_frame); \
74 (frame)->obj = (obj_this); \
75 (frame)->stack_args = (method_args); \
76 (frame)->retval = (method_retval); \
77 (frame)->method = (mono_method); \
78 (frame)->ex_handler = NULL; \
80 (frame)->child = NULL; \
83 void ves_exec_method (MonoInvocation *frame);
85 typedef void (*ICallMethod) (MonoInvocation *frame);
88 ves_real_abort (int line, MonoMethod *mh,
89 const unsigned char *ip, stackval *stack, stackval *sp)
91 MonoMethodNormal *mm = (MonoMethodNormal *)mh;
92 fprintf (stderr, "Execution aborted in method: %s\n", mh->name);
93 fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
95 g_print ("0x%04x %02x\n",
96 ip-mm->header->code, *ip);
98 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
101 #define ves_abort() ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp)
105 * @klass: klass that needs to be initialized
107 * This routine calls the class constructor for @class if it needs it.
110 init_class (MonoClass *klass)
116 if (!klass->metadata_inited)
117 mono_class_metadata_init (klass);
121 if (klass->parent && !klass->parent->inited)
122 init_class (klass->parent);
126 klass->data = g_malloc0 (klass->class_size);
128 for (i = 0; i < klass->method.count; ++i) {
129 method = klass->methods [i];
130 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) {
131 INIT_FRAME (&call, NULL, NULL, NULL, NULL, method);
133 ves_exec_method (&call);
137 /* No class constructor found */
142 * @image: image where the object is being referenced
143 * @token: method token to invoke
145 * This routine creates a new object based on the class where the
146 * constructor lives.x
149 newobj (MonoImage *image, guint32 token)
151 MonoObject *result = NULL;
153 switch (mono_metadata_token_code (token)){
154 case MONO_TOKEN_METHOD_DEF: {
157 idx = mono_metadata_typedef_from_method (image, token);
159 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_DEF | idx);
162 case MONO_TOKEN_MEMBER_REF: {
163 guint32 member_cols [MONO_MEMBERREF_SIZE];
164 guint32 mpr_token, table, idx;
166 mono_metadata_decode_row (
167 &image->tables [MONO_TABLE_MEMBERREF],
168 mono_metadata_token_index (token) - 1,
169 member_cols, CSIZE (member_cols));
170 mpr_token = member_cols [MONO_MEMBERREF_CLASS];
171 table = mpr_token & 7;
172 idx = mpr_token >> 3;
174 if (strcmp (mono_metadata_string_heap (image, member_cols[1]), ".ctor"))
175 g_error ("Unhandled: call to non constructor");
178 case 0: /* TypeDef */
179 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_DEF | idx);
181 case 1: /* TypeRef */
182 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_REF | idx);
184 case 2: /* ModuleRef */
185 g_error ("Unhandled: ModuleRef");
187 case 3: /* MethodDef */
188 g_error ("Unhandled: MethodDef");
190 case 4: /* TypeSpec */
191 result = mono_new_object_from_token (image, MONO_TOKEN_TYPE_SPEC | idx);
196 g_warning ("dont know how to handle token %08x\n", token);
197 g_assert_not_reached ();
201 init_class (result->klass);
205 #undef DEBUG_VM_DISPATCH
208 get_virtual_method (MonoImage *image, guint32 token, stackval *args)
216 switch (mono_metadata_token_table (token)) {
217 case MONO_TABLE_METHOD:
218 case MONO_TABLE_MEMBERREF:
219 m = mono_get_method (image, token, NULL);
220 objs = &args [-(m->signature->param_count + 1)];
222 klass = objs->data.vt.klass ? objs->data.vt.klass: obj->klass;
223 #ifdef DEBUG_VM_DISPATCH
224 g_print ("%s%smethod lookup %s.%s::%s (cast class %s; real class %s)\n",
225 m->flags & METHOD_ATTRIBUTE_VIRTUAL ? "virtual ": "",
226 m->flags & METHOD_ATTRIBUTE_FINAL ? "final ": "",
227 m->klass->name_space, m->klass->name, m->name, klass->name, obj->klass->name);
229 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
231 if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
233 for (; klass && klass != m->klass; klass = klass->parent) {
234 for (i = 0; i < klass->method.count; ++i) {
235 if (!klass->methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
237 if (!strcmp(m->name, klass->methods [i]->name) && mono_metadata_signature_equal (m->signature, klass->methods [i]->signature)) {
238 #ifdef DEBUG_VM_DISPATCH
239 g_print ("\tfound %s%s.%s::%s\n", klass->methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL ? "virtual ": "",
240 klass->name_space, klass->name, klass->methods [i]->name);
242 return klass->methods [i];
248 g_error ("got virtual method: 0x%x\n", token);
253 get_named_exception (const char *name)
257 MonoMethod *method = NULL;
261 klass = mono_class_from_name (mono_defaults.corlib, "System", name);
263 o = mono_new_object (klass);
264 g_assert (o != NULL);
266 for (i = 0; i < klass->method.count; ++i) {
267 if (!strcmp (".ctor", klass->methods [i]->name) &&
268 klass->methods [i]->signature->param_count == 0) {
269 method = klass->methods [i];
277 INIT_FRAME (&call, NULL, o, NULL, NULL, method);
279 ves_exec_method (&call);
284 get_exception_divide_by_zero ()
286 static MonoObject *ex = NULL;
289 ex = get_named_exception ("DivideByZeroException");
294 get_exception_security ()
296 static MonoObject *ex = NULL;
299 ex = get_named_exception ("SecurityException");
304 get_exception_arithmetic ()
306 static MonoObject *ex = NULL;
309 ex = get_named_exception ("ArithmeticException");
314 get_exception_overflow ()
316 static MonoObject *ex = NULL;
319 ex = get_named_exception ("OverflowException");
324 get_exception_null_reference ()
326 static MonoObject *ex = NULL;
329 ex = get_named_exception ("NullReferenceException");
334 get_exception_execution_engine ()
336 static MonoObject *ex = NULL;
339 ex = get_named_exception ("ExecutionEngineException");
344 get_exception_invalid_cast ()
346 static MonoObject *ex = NULL;
349 ex = get_named_exception ("InvalidCastException");
354 get_exception_index_out_of_range ()
356 static MonoObject *ex = NULL;
359 ex = get_named_exception ("IndexOutOfRangeException");
364 get_exception_array_type_mismatch ()
366 static MonoObject *ex = NULL;
369 ex = get_named_exception ("ArrayTypeMismatchException");
374 stackval_from_data (MonoType *type, stackval *result, const char *data)
377 if (type->type == MONO_TYPE_VALUETYPE)
378 result->type = VAL_VALUETA;
380 result->type = VAL_OBJ;
381 result->data.p = *(gpointer*)data;
382 result->data.vt.klass = mono_class_from_mono_type (type);
385 switch (type->type) {
389 result->type = VAL_I32;
390 result->data.i = *(gint8*)data;
393 case MONO_TYPE_BOOLEAN:
394 result->type = VAL_I32;
395 result->data.i = *(guint8*)data;
398 result->type = VAL_I32;
399 result->data.i = *(gint16*)data;
403 result->type = VAL_I32;
404 result->data.i = *(guint16*)data;
407 result->type = VAL_I32;
408 result->data.i = *(gint32*)data;
412 result->type = VAL_TP;
413 result->data.p = *(gpointer*)data;
416 result->type = VAL_I32;
417 result->data.i = *(guint32*)data;
420 result->type = VAL_DOUBLE;
421 result->data.f = *(float*)data;
424 result->type = VAL_I64;
425 result->data.l = *(gint64*)data;
428 result->type = VAL_DOUBLE;
429 result->data.f = *(double*)data;
431 case MONO_TYPE_STRING:
432 case MONO_TYPE_SZARRAY:
433 case MONO_TYPE_CLASS:
434 case MONO_TYPE_OBJECT:
435 case MONO_TYPE_ARRAY:
437 result->type = VAL_OBJ;
438 result->data.p = *(gpointer*)data;
439 result->data.vt.klass = mono_class_from_mono_type (type);
441 case MONO_TYPE_VALUETYPE:
442 if (type->data.klass->enumtype) {
443 result->type = VAL_I32;
444 result->data.i = *(guint32*)data;
445 result->data.vt.klass = mono_class_from_mono_type (type);
447 result->type = VAL_VALUET;
448 result->data.vt.klass = type->data.klass;
449 memcpy (result->data.vt.vt, data, mono_class_value_size (type->data.klass, NULL));
453 g_warning ("got type 0x%02x", type->type);
454 g_assert_not_reached ();
459 stackval_to_data (MonoType *type, stackval *val, char *data)
462 *(gpointer*)data = val->data.p;
465 switch (type->type) {
468 *(guint8*)data = val->data.i;
470 case MONO_TYPE_BOOLEAN:
471 *(guint8*)data = (val->data.i != 0);
476 *(guint16*)data = val->data.i;
478 #if SIZEOF_VOID_P == 4
484 *(gint32*)data = val->data.i;
486 #if SIZEOF_VOID_P == 8
491 *(gint64*)data = val->data.l;
494 *(float*)data = val->data.f;
497 *(double*)data = val->data.f;
499 case MONO_TYPE_STRING:
500 case MONO_TYPE_SZARRAY:
501 case MONO_TYPE_CLASS:
502 case MONO_TYPE_OBJECT:
503 case MONO_TYPE_ARRAY:
505 *(gpointer*)data = val->data.p;
507 case MONO_TYPE_VALUETYPE:
508 if (type->data.klass->enumtype) {
509 *(gint32*)data = val->data.i;
511 memcpy (data, val->data.vt.vt, mono_class_value_size (type->data.klass, NULL));
515 g_warning ("got type %x", type->type);
516 g_assert_not_reached ();
521 ves_array_set (MonoInvocation *frame)
523 stackval *sp = frame->stack_args;
527 gint32 i, t, pos, esize;
532 ao = (MonoArrayObject *)o;
533 ac = (MonoArrayClass *)o->klass;
535 g_assert (ac->rank >= 1);
537 pos = sp [0].data.i - ao->bounds [0].lower_bound;
538 for (i = 1; i < ac->rank; i++) {
539 if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >=
540 ao->bounds [i].length) {
541 g_warning ("wrong array index");
542 g_assert_not_reached ();
544 pos = pos*ao->bounds [i].length + sp [i].data.i -
545 ao->bounds [i].lower_bound;
548 esize = mono_array_element_size (ac);
549 ea = ao->vector + (pos * esize);
551 mt = frame->method->signature->params [ac->rank];
552 stackval_to_data (mt, &sp [ac->rank], ea);
556 ves_array_get (MonoInvocation *frame)
558 stackval *sp = frame->stack_args;
562 gint32 i, pos, esize;
567 ao = (MonoArrayObject *)o;
568 ac = (MonoArrayClass *)o->klass;
570 g_assert (ac->rank >= 1);
572 pos = sp [0].data.i - ao->bounds [0].lower_bound;
573 for (i = 1; i < ac->rank; i++)
574 pos = pos*ao->bounds [i].length + sp [i].data.i -
575 ao->bounds [i].lower_bound;
577 esize = mono_array_element_size (ac);
578 ea = ao->vector + (pos * esize);
580 mt = frame->method->signature->ret;
581 stackval_from_data (mt, frame->retval, ea);
585 ves_pinvoke_method (MonoInvocation *frame)
587 MonoPIFunc func = mono_create_trampoline (frame->method);
588 func (frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
589 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
594 * This is a hack, you don't want to see the code in this function. Go away.
596 * We need a way to easily find the offset in an object of a field we may be
597 * interested in: it's needed here and in several other code where the C#
598 * implementation is highly tied to the internals (Array and String are other good
602 * runtime specifies that the implementation of the method is automatically
603 * provided by the runtime and is primarily used for the methods of delegates.
606 ves_runtime_method (MonoInvocation *frame)
608 const char *name = frame->method->name;
609 MonoObject *obj = frame->obj;
610 static guint target_offset = 0;
611 static guint method_offset = 0;
613 if (!target_offset) {
614 MonoClassField *field;
616 field = mono_class_get_field_from_name (mono_defaults.delegate_class, "target");
617 target_offset = field->offset;
618 field = mono_class_get_field_from_name (mono_defaults.delegate_class, "method_ptr");
619 method_offset = field->offset;
622 if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
623 mono_object_isinst (obj, mono_defaults.delegate_class)) {
624 *(gpointer*)(((char*)obj) + target_offset) = frame->stack_args[0].data.p;
625 *(gpointer*)(((char*)obj) + method_offset) = frame->stack_args[1].data.p;
628 if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
629 mono_object_isinst (obj, mono_defaults.delegate_class)) {
630 MonoPIFunc func = mono_create_trampoline (frame->method);
631 void* faddr = *(gpointer*)(((char*)obj) + method_offset);
632 func (faddr, &frame->retval->data.p, frame->obj, frame->stack_args);
633 stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
637 g_error ("Don't know how to exec runtime method %s.%s::%s",
638 frame->method->klass->name_space, frame->method->klass->name,
639 frame->method->name);
643 dump_stack (stackval *stack, stackval *sp)
652 case VAL_I32: g_print ("[%d] ", s->data.i); break;
653 case VAL_I64: g_print ("[%lld] ", s->data.l); break;
654 case VAL_DOUBLE: g_print ("[%0.5f] ", s->data.f); break;
655 case VAL_VALUET: g_print ("[vt: %p] ", s->data.vt.vt); break;
656 default: g_print ("[%p] ", s->data.p); break;
662 #define DEBUG_INTERP 1
665 static unsigned long opcode_count = 0;
666 static unsigned long fcall_count = 0;
667 static int break_on_method = 0;
668 GList *db_methods = NULL;
675 for (h = 0; h < debug_indent_level; h++)
680 db_match_method (gpointer data, gpointer user_data)
683 * Make this function smarter (accept Class:method...)
685 if (strcmp((char*)data, (char*)user_data) == 0)
689 #define DEBUG_ENTER() \
691 g_list_foreach (db_methods, db_match_method, (gpointer)frame->method->name); \
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\n", klass->name_space, klass->name, frame->method->name); \
700 #define DEBUG_LEAVE() \
702 MonoClass *klass = frame->method->klass; \
704 g_print ("Leaving %s.%s::%s\n", klass->name_space, klass->name, frame->method->name); \
705 debug_indent_level--; \
710 #define DEBUG_ENTER()
711 #define DEBUG_LEAVE()
715 #define LOCAL_POS(n) (locals_pointers [(n)])
716 #define LOCAL_TYPE(header, n) ((header)->locals [(n)])
718 #define ARG_POS(n) (args_pointers [(n)])
719 #define ARG_TYPE(sig, n) ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
720 (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
722 #define THROW_EX(exception,ex_ip) \
724 frame->ip = (ex_ip); \
725 frame->ex = (exception); \
726 goto handle_exception; \
729 typedef struct _vtallocation vtallocation;
731 struct _vtallocation {
734 char data [MONO_ZERO_LEN_ARRAY];
738 * we don't use vtallocation->next, yet
740 #define vt_alloc(vtype,sp) \
741 if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) { \
742 if (!(vtype)->byref) { \
744 guint32 size = mono_class_value_size ((vtype)->data.klass, &align); \
745 if (!vtalloc || vtalloc->size < size) { \
746 vtalloc = alloca (sizeof (vtallocation) + size); \
747 vtalloc->size = size; \
749 (sp)->data.vt.vt = vtalloc->data; \
752 (sp)->data.vt.klass = (vtype)->data.klass; \
756 #define vt_free(sp) \
758 if ((sp)->type == VAL_VALUET) { \
759 vtalloc = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data)); \
764 * Need to optimize ALU ops when natural int == int32
766 * IDEA: if we maintain a stack of ip, sp to be checked
767 * in the return opcode, we could inline simple methods that don't
768 * use the stack or local variables....
770 * The {,.S} versions of many opcodes can/should be merged to reduce code
775 ves_exec_method (MonoInvocation *frame)
777 MonoInvocation child_frame;
778 MonoMethodHeader *header;
779 MonoMethodSignature *signature;
781 const unsigned char *endfinally_ip;
782 register const unsigned char *ip;
783 register stackval *sp;
784 void **locals_pointers;
785 void **args_pointers;
786 unsigned char tail_recursion = 0;
787 unsigned char unaligned_address = 0;
788 unsigned char volatile_address = 0;
789 vtallocation *vtalloc = NULL;
792 if (!frame->method->klass->inited)
793 init_class (frame->method->klass);
797 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
798 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
799 ves_pinvoke_method (frame);
801 ICallMethod icall = frame->method->addr;
808 if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
809 ves_pinvoke_method (frame);
814 if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
815 ves_runtime_method (frame);
820 header = ((MonoMethodNormal *)frame->method)->header;
821 signature = frame->method->signature;
822 image = frame->method->klass->image;
825 * with alloca we get the expected huge performance gain
826 * stackval *stack = g_new0(stackval, header->max_stack);
829 sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
831 if (header->num_locals) {
832 int i, align, size, offset = 0;
834 frame->locals = alloca (header->locals_size);
835 locals_pointers = alloca (sizeof(void*) * header->num_locals);
837 * yes, we do it unconditionally, because it needs to be done for
838 * some cases anyway and checking for that would be even slower.
840 memset (frame->locals, 0, header->locals_size);
841 for (i = 0; i < header->num_locals; ++i) {
842 locals_pointers [i] = frame->locals + offset;
843 size = mono_type_size (header->locals [i], &align);
845 offset &= ~(align - 1);
850 * Copy args from stack_args to args.
852 if (signature->params_size) {
853 int i, align, size, offset = 0;
854 int has_this = signature->hasthis;
856 frame->args = alloca (signature->params_size);
857 args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
859 args_pointers [0] = frame->args;
860 *(gpointer*) frame->args = frame->obj;
861 offset += sizeof (gpointer);
863 for (i = 0; i < signature->param_count; ++i) {
864 args_pointers [i + has_this] = frame->args + offset;
865 stackval_to_data (signature->params [i], frame->stack_args + i, frame->args + offset);
866 size = mono_type_size (signature->params [i], &align);
868 offset &= ~(align - 1);
873 child_frame.parent = frame;
874 frame->child = &child_frame;
881 * using while (ip < end) may result in a 15% performance drop,
882 * but it may be useful for debug
886 /*g_assert (sp >= stack);*/
892 dump_stack (frame->stack, sp);
895 g_print ("0x%04x: %s\n", ip-header->code,
896 *ip == 0xfe ? opcode_names [256 + ip [1]] : opcode_names [*ip]);
906 G_BREAKPOINT (); /* this is not portable... */
912 int n = (*ip)-CEE_LDARG_0;
914 vt_alloc (ARG_TYPE (signature, n), sp);
915 stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n));
923 int n = (*ip)-CEE_LDLOC_0;
925 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
927 sp->data.i = *(gint32*) LOCAL_POS (n);
929 vt_alloc (LOCAL_TYPE (header, n), sp);
930 stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
939 int n = (*ip)-CEE_STLOC_0;
942 if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
943 *(gint32*)LOCAL_POS (n) = sp->data.i;
945 stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n));
952 vt_alloc (ARG_TYPE (signature, *ip), sp);
953 stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
957 CASE (CEE_LDARGA_S) {
962 t = ARG_TYPE (signature, *ip);
963 c = mono_class_from_mono_type (t);
964 sp->data.vt.klass = c;
965 sp->data.vt.vt = ARG_POS (*ip);
968 sp->type = VAL_VALUETA;
979 stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip));
985 vt_alloc (LOCAL_TYPE (header, *ip), sp);
986 stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
990 CASE (CEE_LDLOCA_S) {
995 t = LOCAL_TYPE (header, *ip);
996 c = mono_class_from_mono_type (t);
997 sp->data.vt.klass = c;
998 sp->data.p = LOCAL_POS (*ip);
1001 sp->type = VAL_VALUETA;
1012 stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip));
1020 sp->data.vt.klass = NULL;
1023 CASE (CEE_LDC_I4_M1)
1039 sp->data.i = (*ip) - CEE_LDC_I4_0;
1046 sp->data.i = *ip; /* FIXME: signed? */
1053 sp->data.i = read32 (ip);
1060 sp->data.i = read64 (ip);
1067 sp->type = VAL_DOUBLE;
1076 sp->type = VAL_DOUBLE;
1077 readr8(ip, &sp->data.f);
1081 CASE (CEE_UNUSED99) ves_abort (); BREAK;
1083 if (sp [-1].type == VAL_VALUET) {
1085 char *addr = sp [-1].data.vt.vt;
1086 MonoType t = sp [-1].data.vt.klass->this_arg;
1089 stackval_from_data (&t, sp, addr);
1101 CASE (CEE_JMP) ves_abort(); BREAK;
1102 CASE (CEE_CALLVIRT) /* Fall through */
1103 CASE (CEE_CALLI) /* Fall through */
1105 MonoMethodSignature *csignature;
1107 stackval *endsp = sp;
1109 int virtual = *ip == CEE_CALLVIRT;
1110 int calli = *ip == CEE_CALLI;
1113 * We ignore tail recursion for now.
1120 token = read32 (ip);
1123 unsigned char *code;
1126 /* check the signature we put in mono_create_method_pointer () */
1127 g_assert (code [2] == 'M' && code [3] == 'o');
1128 child_frame.method = *(gpointer*)(code + sizeof (gpointer));
1131 child_frame.method = get_virtual_method (image, token, sp);
1133 child_frame.method = mono_get_method (image, token, NULL);
1135 csignature = child_frame.method->signature;
1136 g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
1137 /* decrement by the actual number of args */
1138 if (csignature->param_count) {
1139 sp -= csignature->param_count;
1140 child_frame.stack_args = sp;
1142 child_frame.stack_args = NULL;
1144 if (csignature->hasthis) {
1145 g_assert (sp >= frame->stack);
1147 g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
1148 child_frame.obj = sp->data.p;
1150 child_frame.obj = NULL;
1152 if (csignature->ret->type != MONO_TYPE_VOID) {
1153 vt_alloc (csignature->ret, &retval);
1154 child_frame.retval = &retval;
1156 child_frame.retval = NULL;
1159 child_frame.ex = NULL;
1160 child_frame.ex_handler = NULL;
1162 ves_exec_method (&child_frame);
1164 while (endsp > sp) {
1169 if (child_frame.ex) {
1171 * An exception occurred, need to run finally, fault and catch handlers..
1173 frame->ex = child_frame.ex;
1174 goto handle_finally;
1177 /* need to handle typedbyref ... */
1178 if (csignature->ret->type != MONO_TYPE_VOID) {
1185 if (signature->ret->type != MONO_TYPE_VOID) {
1187 if (sp->type == VAL_VALUET) {
1188 /* the caller has already allocated the memory */
1189 stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt);
1192 *frame->retval = *sp;
1195 if (sp > frame->stack)
1196 g_warning ("more values on stack: %d", sp-frame->stack);
1200 CASE (CEE_BR_S) /* Fall through */
1202 if (*ip == CEE_BR) {
1204 ip += (gint32) read32(ip);
1208 ip += (signed char) *ip;
1212 CASE (CEE_BRFALSE) /* Fall through */
1213 CASE (CEE_BRFALSE_S) {
1215 int near_jump = *ip == CEE_BRFALSE_S;
1219 case VAL_I32: result = sp->data.i == 0; break;
1220 case VAL_I64: result = sp->data.l == 0; break;
1221 case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
1222 default: result = sp->data.p == NULL; break;
1226 ip += (signed char)*ip;
1228 ip += (gint32) read32 (ip);
1230 ip += near_jump ? 1: 4;
1233 CASE (CEE_BRTRUE) /* Fall through */
1234 CASE (CEE_BRTRUE_S) {
1236 int near_jump = *ip == CEE_BRTRUE_S;
1240 case VAL_I32: result = sp->data.i != 0; break;
1241 case VAL_I64: result = sp->data.l != 0; break;
1242 case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
1243 default: result = sp->data.p != NULL; break;
1247 ip += (signed char)*ip;
1249 ip += (gint32) read32 (ip);
1251 ip += near_jump ? 1: 4;
1254 CASE (CEE_BEQ) /* Fall through */
1257 int near_jump = *ip == CEE_BEQ_S;
1260 if (sp->type == VAL_I32)
1261 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
1262 else if (sp->type == VAL_I64)
1263 result = sp [0].data.l == sp [1].data.l;
1264 else if (sp->type == VAL_DOUBLE)
1265 result = sp [0].data.f == sp [1].data.f;
1267 result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
1270 ip += (signed char)*ip;
1272 ip += (gint32) read32 (ip);
1274 ip += near_jump ? 1: 4;
1277 CASE (CEE_BGE) /* Fall through */
1280 int near_jump = *ip == CEE_BGE_S;
1283 if (sp->type == VAL_I32)
1284 result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
1285 else if (sp->type == VAL_I64)
1286 result = sp [0].data.l >= sp [1].data.l;
1287 else if (sp->type == VAL_DOUBLE)
1288 result = sp [0].data.f >= sp [1].data.f;
1290 result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
1293 ip += (signed char)*ip;
1295 ip += (gint32) read32 (ip);
1297 ip += near_jump ? 1: 4;
1300 CASE (CEE_BGT) /* Fall through */
1303 int near_jump = *ip == CEE_BGT_S;
1306 if (sp->type == VAL_I32)
1307 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
1308 else if (sp->type == VAL_I64)
1309 result = sp [0].data.l > sp [1].data.l;
1310 else if (sp->type == VAL_DOUBLE)
1311 result = sp [0].data.f > sp [1].data.f;
1313 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
1316 ip += (signed char)*ip;
1318 ip += (gint32) read32 (ip);
1320 ip += near_jump ? 1: 4;
1323 CASE (CEE_BLT) /* Fall through */
1326 int near_jump = *ip == CEE_BLT_S;
1329 if (sp->type == VAL_I32)
1330 result = sp[0].data.i < (gint)GET_NATI(sp[1]);
1331 else if (sp->type == VAL_I64)
1332 result = sp[0].data.l < sp[1].data.l;
1333 else if (sp->type == VAL_DOUBLE)
1334 result = sp[0].data.f < sp[1].data.f;
1336 result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
1339 ip += (signed char)*ip;
1341 ip += (gint32) read32 (ip);
1343 ip += near_jump ? 1: 4;
1346 CASE (CEE_BLE) /* fall through */
1349 int near_jump = *ip == CEE_BLE_S;
1353 if (sp->type == VAL_I32)
1354 result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
1355 else if (sp->type == VAL_I64)
1356 result = sp [0].data.l <= sp [1].data.l;
1357 else if (sp->type == VAL_DOUBLE)
1358 result = sp [0].data.f <= sp [1].data.f;
1361 * FIXME: here and in other places GET_NATI on the left side
1362 * _will_ be wrong when we change the macro to work on 64 bits
1365 result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
1369 ip += (signed char)*ip;
1371 ip += (gint32) read32 (ip);
1373 ip += near_jump ? 1: 4;
1376 CASE (CEE_BNE_UN) /* Fall through */
1377 CASE (CEE_BNE_UN_S) {
1379 int near_jump = *ip == CEE_BNE_UN_S;
1382 if (sp->type == VAL_I32)
1383 result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
1384 else if (sp->type == VAL_I64)
1385 result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
1386 else if (sp->type == VAL_DOUBLE)
1387 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1388 (sp [0].data.f != sp [1].data.f);
1390 result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
1393 ip += (signed char)*ip;
1395 ip += (gint32) read32 (ip);
1397 ip += near_jump ? 1: 4;
1400 CASE (CEE_BGE_UN) /* Fall through */
1401 CASE (CEE_BGE_UN_S) {
1403 int near_jump = *ip == CEE_BGE_UN_S;
1406 if (sp->type == VAL_I32)
1407 result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
1408 else if (sp->type == VAL_I64)
1409 result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
1410 else if (sp->type == VAL_DOUBLE)
1411 result = !isless (sp [0].data.f,sp [1].data.f);
1413 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
1416 ip += (signed char)*ip;
1418 ip += (gint32) read32 (ip);
1420 ip += near_jump ? 1: 4;
1423 CASE (CEE_BGT_UN) /* Fall through */
1424 CASE (CEE_BGT_UN_S) {
1426 int near_jump = *ip == CEE_BGT_UN_S;
1429 if (sp->type == VAL_I32)
1430 result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
1431 else if (sp->type == VAL_I64)
1432 result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
1433 else if (sp->type == VAL_DOUBLE)
1434 result = isgreater (sp [0].data.f, sp [1].data.f);
1436 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
1439 ip += (signed char)*ip;
1441 ip += (gint32) read32 (ip);
1443 ip += near_jump ? 1: 4;
1446 CASE (CEE_BLE_UN) /* Fall through */
1447 CASE (CEE_BLE_UN_S) {
1449 int near_jump = *ip == CEE_BLE_UN_S;
1452 if (sp->type == VAL_I32)
1453 result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
1454 else if (sp->type == VAL_I64)
1455 result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
1456 else if (sp->type == VAL_DOUBLE)
1457 result = islessequal (sp [0].data.f, sp [1].data.f);
1459 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
1462 ip += (signed char)*ip;
1464 ip += (gint32) read32 (ip);
1466 ip += near_jump ? 1: 4;
1469 CASE (CEE_BLT_UN) /* Fall through */
1470 CASE (CEE_BLT_UN_S) {
1472 int near_jump = *ip == CEE_BLT_UN_S;
1475 if (sp->type == VAL_I32)
1476 result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
1477 else if (sp->type == VAL_I64)
1478 result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
1479 else if (sp->type == VAL_DOUBLE)
1480 result = isunordered (sp [0].data.f, sp [1].data.f) ||
1481 (sp [0].data.f < sp [1].data.f);
1483 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
1486 ip += (signed char)*ip;
1488 ip += (gint32) read32 (ip);
1490 ip += near_jump ? 1: 4;
1495 const unsigned char *st;
1499 st = ip + sizeof (gint32) * n;
1501 if ((guint32)sp->data.i < n) {
1503 ip += sizeof (gint32) * (guint32)sp->data.i;
1504 offset = read32 (ip);
1513 sp[-1].type = VAL_I32;
1514 sp[-1].data.i = *(gint8*)sp[-1].data.p;
1518 sp[-1].type = VAL_I32;
1519 sp[-1].data.i = *(guint8*)sp[-1].data.p;
1523 sp[-1].type = VAL_I32;
1524 sp[-1].data.i = *(gint16*)sp[-1].data.p;
1528 sp[-1].type = VAL_I32;
1529 sp[-1].data.i = *(guint16*)sp[-1].data.p;
1531 CASE (CEE_LDIND_I4) /* Fall through */
1534 sp[-1].type = VAL_I32;
1535 sp[-1].data.i = *(gint32*)sp[-1].data.p;
1539 sp[-1].type = VAL_I64;
1540 sp[-1].data.l = *(gint64*)sp[-1].data.p;
1544 sp[-1].type = VAL_NATI;
1545 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1549 sp[-1].type = VAL_DOUBLE;
1550 sp[-1].data.i = *(gfloat*)sp[-1].data.p;
1554 sp[-1].type = VAL_DOUBLE;
1555 sp[-1].data.i = *(gdouble*)sp[-1].data.p;
1557 CASE (CEE_LDIND_REF)
1559 sp[-1].type = VAL_OBJ;
1560 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
1561 sp[-1].data.vt.klass = NULL;
1563 CASE (CEE_STIND_REF)
1566 *(gpointer*)sp->data.p = sp[1].data.p;
1571 *(gint8*)sp->data.p = (gint8)sp[1].data.i;
1576 *(gint16*)sp->data.p = (gint16)sp[1].data.i;
1581 *(gint32*)sp->data.p = sp[1].data.i;
1586 *(gint64*)sp->data.p = sp[1].data.l;
1591 *(gint64*)sp->data.p = sp[1].data.l;
1596 *(gfloat*)sp->data.p = (gfloat)sp[1].data.f;
1601 *(gdouble*)sp->data.p = sp[1].data.f;
1606 /* should probably consider the pointers as unsigned */
1607 if (sp->type == VAL_I32)
1608 sp [-1].data.i += GET_NATI (sp [0]);
1609 else if (sp->type == VAL_I64)
1610 sp [-1].data.l += sp [0].data.l;
1611 else if (sp->type == VAL_DOUBLE)
1612 sp [-1].data.f += sp [0].data.f;
1614 (char*)sp [-1].data.p += GET_NATI (sp [0]);
1619 /* should probably consider the pointers as unsigned */
1620 if (sp->type == VAL_I32)
1621 sp [-1].data.i -= GET_NATI (sp [0]);
1622 else if (sp->type == VAL_I64)
1623 sp [-1].data.l -= sp [0].data.l;
1624 else if (sp->type == VAL_DOUBLE)
1625 sp [-1].data.f -= sp [0].data.f;
1627 (char*)sp [-1].data.p -= GET_NATI (sp [0]);
1632 if (sp->type == VAL_I32)
1633 sp [-1].data.i *= (gint)GET_NATI (sp [0]);
1634 else if (sp->type == VAL_I64)
1635 sp [-1].data.l *= sp [0].data.l;
1636 else if (sp->type == VAL_DOUBLE)
1637 sp [-1].data.f *= sp [0].data.f;
1642 if (sp->type == VAL_I32) {
1643 if (GET_NATI (sp [0]) == 0)
1644 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1645 sp [-1].data.i /= (gint)GET_NATI (sp [0]);
1646 } else if (sp->type == VAL_I64) {
1647 if (sp [0].data.l == 0)
1648 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1649 sp [-1].data.l /= sp [0].data.l;
1650 } else if (sp->type == VAL_DOUBLE) {
1651 /* set NaN is divisor is 0.0 */
1652 sp [-1].data.f /= sp [0].data.f;
1658 if (sp->type == VAL_I32) {
1659 if (GET_NATI (sp [0]) == 0)
1660 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1661 (guint32)sp [-1].data.i /= (guint32)GET_NATI (sp [0]);
1662 } else if (sp->type == VAL_I64) {
1663 if (sp [0].data.l == 0)
1664 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1665 (guint64)sp [-1].data.l /= (guint64)sp [0].data.l;
1666 } else if (sp->type == VAL_NATI) {
1667 if (GET_NATI (sp [0]) == 0)
1668 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1669 (gulong)sp [-1].data.p /= (gulong)sp [0].data.p;
1675 if (sp->type == VAL_I32) {
1676 if (GET_NATI (sp [0]) == 0)
1677 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1678 sp [-1].data.i %= (gint)GET_NATI (sp [0]);
1679 } else if (sp->type == VAL_I64) {
1680 if (sp [0].data.l == 0)
1681 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1682 sp [-1].data.l %= sp [0].data.l;
1683 } else if (sp->type == VAL_DOUBLE) {
1684 /* FIXME: what do we actually do here? */
1687 if (GET_NATI (sp [0]) == 0)
1688 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1689 (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
1695 if (sp->type == VAL_I32) {
1696 if (GET_NATI (sp [0]) == 0)
1697 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1698 (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
1699 } else if (sp->type == VAL_I64) {
1700 if (sp [0].data.l == 0)
1701 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1702 (gulong)sp [-1].data.l %= (gulong)sp [0].data.l;
1703 } else if (sp->type == VAL_DOUBLE) {
1704 /* unspecified behaviour according to the spec */
1706 if (GET_NATI (sp [0]) == 0)
1707 THROW_EX (get_exception_divide_by_zero (), ip - 1);
1708 (gulong)GET_NATI (sp [-1]) %= (gulong)GET_NATI (sp [0]);
1714 if (sp->type == VAL_I32)
1715 sp [-1].data.i &= GET_NATI (sp [0]);
1716 else if (sp->type == VAL_I64)
1717 sp [-1].data.l &= sp [0].data.l;
1719 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
1724 if (sp->type == VAL_I32)
1725 sp [-1].data.i |= GET_NATI (sp [0]);
1726 else if (sp->type == VAL_I64)
1727 sp [-1].data.l |= sp [0].data.l;
1729 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
1734 if (sp->type == VAL_I32)
1735 sp [-1].data.i ^= GET_NATI (sp [0]);
1736 else if (sp->type == VAL_I64)
1737 sp [-1].data.l ^= sp [0].data.l;
1739 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
1744 if (sp->type == VAL_I32)
1745 sp [-1].data.i <<= GET_NATI (sp [0]);
1746 else if (sp->type == VAL_I64)
1747 sp [-1].data.l <<= GET_NATI (sp [0]);
1749 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
1754 if (sp->type == VAL_I32)
1755 sp [-1].data.i >>= GET_NATI (sp [0]);
1756 else if (sp->type == VAL_I64)
1757 sp [-1].data.l >>= GET_NATI (sp [0]);
1759 (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1764 if (sp->type == VAL_I32)
1765 (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
1766 else if (sp->type == VAL_I64)
1767 (gulong)sp [-1].data.l >>= GET_NATI (sp [0]);
1769 (gulong)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
1773 if (sp->type == VAL_I32)
1774 sp->data.i = - sp->data.i;
1775 else if (sp->type == VAL_I64)
1776 sp->data.l = - sp->data.l;
1777 else if (sp->type == VAL_DOUBLE)
1778 sp->data.f = - sp->data.f;
1779 else if (sp->type == VAL_NATI)
1780 sp->data.p = (gpointer)(- (int)sp->data.p);
1784 if (sp->type == VAL_I32)
1785 sp->data.i = ~ sp->data.i;
1786 else if (sp->type == VAL_I64)
1787 sp->data.l = ~ sp->data.l;
1788 else if (sp->type == VAL_NATI)
1789 sp->data.p = (gpointer)(~ (int)sp->data.p);
1791 CASE (CEE_CONV_U1) /* fall through */
1792 CASE (CEE_CONV_I1) {
1794 switch (sp [-1].type) {
1796 sp [-1].data.i = (gint8)sp [-1].data.f;
1799 sp [-1].data.i = (gint8)sp [-1].data.l;
1804 sp [-1].data.i = (gint8)sp [-1].data.i;
1807 sp [-1].data.i = (gint8)sp [-1].data.nati;
1810 sp [-1].type = VAL_I32;
1813 CASE (CEE_CONV_U2) /* fall through */
1814 CASE (CEE_CONV_I2) {
1816 switch (sp [-1].type) {
1818 sp [-1].data.i = (gint16)sp [-1].data.f;
1821 sp [-1].data.i = (gint16)sp [-1].data.l;
1826 sp [-1].data.i = (gint16)sp [-1].data.i;
1829 sp [-1].data.i = (gint16)sp [-1].data.nati;
1832 sp [-1].type = VAL_I32;
1835 CASE (CEE_CONV_U4) /* Fall through */
1836 #if SIZEOF_VOID_P == 4
1837 CASE (CEE_CONV_I) /* Fall through */
1838 CASE (CEE_CONV_U) /* Fall through */
1840 CASE (CEE_CONV_I4) {
1842 switch (sp [-1].type) {
1844 sp [-1].data.i = (gint32)sp [-1].data.f;
1847 sp [-1].data.i = (gint32)sp [-1].data.l;
1854 sp [-1].data.i = (gint32)sp [-1].data.p;
1857 sp [-1].type = VAL_I32;
1860 #if SIZEOF_VOID_P == 8
1861 CASE (CEE_CONV_I) /* Fall through */
1865 switch (sp [-1].type) {
1867 sp [-1].data.l = (gint64)sp [-1].data.f;
1874 sp [-1].data.l = (gint64)sp [-1].data.i;
1877 sp [-1].data.l = (gint64)sp [-1].data.nati;
1880 sp [-1].type = VAL_I64;
1882 CASE (CEE_CONV_R4) /* Fall through */
1883 CASE (CEE_CONV_R8) {
1885 switch (sp [-1].type) {
1887 sp [-1].data.f = (double)sp [-1].data.f;
1890 sp [-1].data.f = (double)sp [-1].data.l;
1895 sp [-1].data.f = (double)sp [-1].data.i;
1898 sp [-1].data.f = (double)sp [-1].data.nati;
1901 sp [-1].type = VAL_DOUBLE;
1904 #if SIZEOF_VOID_P == 8
1905 CASE (CEE_CONV_U) /* Fall through */
1910 switch (sp [-1].type){
1912 sp [-1].data.l = (guint64)sp [-1].data.f;
1919 sp [-1].data.l = (guint64) sp [-1].data.i;
1922 sp [-1].data.l = (guint64) sp [-1].data.nati;
1925 sp [-1].type = VAL_I64;
1930 vtklass = mono_class_get (image, read32 (ip));
1933 memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
1943 token = read32 (ip);
1945 c = mono_class_get (image, token);
1946 addr = sp [-1].data.vt.vt;
1950 vt_alloc (&t, &sp [-1]);
1951 stackval_from_data (&t, &sp [-1], addr);
1961 index = mono_metadata_token_index (read32 (ip));
1964 name = mono_metadata_user_string (image, index);
1965 len = mono_metadata_decode_blob_size (name, &name);
1967 o = mono_new_utf16_string (name, len >> 1);
1970 sp->data.vt.klass = NULL;
1977 MonoMethodSignature *csig;
1978 stackval *endsp = sp;
1984 token = read32 (ip);
1985 o = newobj (image, token);
1988 /* call the contructor */
1989 child_frame.method = mono_get_method (image, token, o->klass);
1990 csig = child_frame.method->signature;
1993 * First arg is the object.
1995 child_frame.obj = o;
1997 if (csig->param_count) {
1998 sp -= csig->param_count;
1999 child_frame.stack_args = sp;
2001 child_frame.stack_args = NULL;
2004 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2006 child_frame.ex = NULL;
2007 child_frame.ex_handler = NULL;
2009 ves_exec_method (&child_frame);
2011 while (endsp > sp) {
2016 if (child_frame.ex) {
2018 * An exception occurred, need to run finally, fault and catch handlers..
2020 frame->ex = child_frame.ex;
2021 goto handle_finally;
2024 * a constructor returns void, but we need to return the object we created
2028 sp->data.vt.klass = o->klass;
2032 CASE (CEE_CASTCLASS) /* Fall through */
2035 MonoClass *c , *oclass;
2037 int do_isinst = *ip == CEE_ISINST;
2038 gboolean found = FALSE;
2041 token = read32 (ip);
2042 c = mono_class_get (image, token);
2044 g_assert (sp [-1].type == VAL_OBJ);
2046 if ((o = sp [-1].data.p)) {
2048 * fixme: this only works for class casts, but not for
2054 sp [-1].data.vt.klass = oclass;
2058 oclass = oclass->parent;
2062 sp [-1].data.p = NULL;
2063 sp [-1].data.vt.klass = NULL;
2065 THROW_EX (get_exception_invalid_cast (), ip - 1);
2071 CASE (CEE_CONV_R_UN)
2072 switch (sp [-1].type) {
2076 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2081 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2084 sp [-1].data.f = (double)(gulong)sp [-1].data.nati;
2087 sp [-1].type = VAL_DOUBLE;
2090 CASE (CEE_UNUSED1) ves_abort(); BREAK;
2097 token = read32 (ip);
2099 c = mono_class_get (image, token);
2103 g_assert (o->klass->type_token == c->type_token);
2105 sp [-1].type = VAL_MP;
2106 sp [-1].data.p = (char *)o + sizeof (MonoObject);
2113 THROW_EX (sp->data.p, ip);
2115 CASE (CEE_LDFLDA) /* Fall through */
2118 MonoClassField *field;
2119 guint32 token, offset;
2120 int load_addr = *ip == CEE_LDFLDA;
2123 token = read32 (ip);
2126 if (sp [-1].type == VAL_OBJ) {
2127 obj = sp [-1].data.p;
2128 field = mono_class_get_field (obj->klass, token);
2129 offset = field->offset;
2130 } else { /* valuetype */
2131 /*g_assert (sp [-1].type == VAL_VALUETA); */
2132 obj = sp [-1].data.vt.vt;
2133 field = mono_class_get_field (sp [-1].data.vt.klass, token);
2134 offset = field->offset - sizeof (MonoObject);
2137 sp [-1].type = VAL_TP;
2138 sp [-1].data.p = (char*)obj + offset;
2139 sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
2141 vt_alloc (field->type, &sp [-1]);
2142 stackval_from_data (field->type, &sp [-1], (char*)obj + offset);
2149 MonoClassField *field;
2150 guint32 token, offset;
2153 token = read32 (ip);
2158 if (sp [0].type == VAL_OBJ) {
2159 obj = sp [0].data.p;
2160 field = mono_class_get_field (obj->klass, token);
2161 offset = field->offset;
2162 } else { /* valuetype */
2163 /*g_assert (sp->type == VAL_VALUETA); */
2164 obj = sp [0].data.vt.vt;
2165 field = mono_class_get_field (sp [0].data.vt.klass, token);
2166 offset = field->offset - sizeof (MonoObject);
2169 stackval_to_data (field->type, &sp [1], (char*)obj + offset);
2173 CASE (CEE_LDSFLD) /* Fall through */
2174 CASE (CEE_LDSFLDA) {
2176 MonoClassField *field;
2178 int load_addr = *ip == CEE_LDSFLDA;
2181 token = read32 (ip);
2184 /* need to handle fieldrefs */
2185 klass = mono_class_get (image,
2186 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2189 field = mono_class_get_field (klass, token);
2193 sp->data.p = MONO_CLASS_STATIC_FIELDS_BASE (klass) + field->offset;
2194 sp->data.vt.klass = mono_class_from_mono_type (field->type);
2196 vt_alloc (field->type, sp);
2197 stackval_from_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2204 MonoClassField *field;
2208 token = read32 (ip);
2212 /* need to handle fieldrefs */
2213 klass = mono_class_get (image,
2214 MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
2217 field = mono_class_get_field (klass, token);
2219 stackval_to_data (field->type, sp, MONO_CLASS_STATIC_FIELDS_BASE(klass) + field->offset);
2226 vtklass = mono_class_get (image, read32 (ip));
2229 memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
2232 #if SIZEOF_VOID_P == 8
2233 CASE (CEE_CONV_OVF_I_UN)
2235 CASE (CEE_CONV_OVF_I8_UN) {
2236 switch (sp [-1].type) {
2238 if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807L)
2239 THROW_EX (get_exception_overflow (), ip);
2240 sp [-1].data.l = (guint64)sp [-1].data.f;
2243 if (sp [-1].data.l < 0)
2244 THROW_EX (get_exception_overflow (), ip);
2249 /* Can't overflow */
2250 sp [-1].data.l = (guint64)sp [-1].data.i;
2253 if ((gint64)sp [-1].data.nati < 0)
2254 THROW_EX (get_exception_overflow (), ip);
2255 sp [-1].data.l = (guint64)sp [-1].data.nati;
2258 sp [-1].type = VAL_I64;
2262 #if SIZEOF_VOID_P == 8
2263 CASE (CEE_CONV_OVF_U_UN)
2265 CASE (CEE_CONV_OVF_U8_UN) {
2266 switch (sp [-1].type) {
2268 if (sp [-1].data.f < 0 || sp [-1].data.f > 18446744073709551615UL)
2269 THROW_EX (get_exception_overflow (), ip);
2270 sp [-1].data.l = (guint64)sp [-1].data.f;
2278 /* Can't overflow */
2279 sp [-1].data.l = (guint64)sp [-1].data.i;
2282 /* Can't overflow */
2283 sp [-1].data.l = (guint64)sp [-1].data.nati;
2286 sp [-1].type = VAL_I64;
2290 #if SIZEOF_VOID_P == 4
2291 CASE (CEE_CONV_OVF_I_UN)
2292 CASE (CEE_CONV_OVF_U_UN)
2294 CASE (CEE_CONV_OVF_I1_UN)
2295 CASE (CEE_CONV_OVF_I2_UN)
2296 CASE (CEE_CONV_OVF_I4_UN)
2297 CASE (CEE_CONV_OVF_U1_UN)
2298 CASE (CEE_CONV_OVF_U2_UN)
2299 CASE (CEE_CONV_OVF_U4_UN) {
2301 switch (sp [-1].type) {
2303 value = (guint64)sp [-1].data.f;
2306 value = (guint64)sp [-1].data.l;
2311 value = (guint64)sp [-1].data.i;
2314 value = (guint64)sp [-1].data.nati;
2318 case CEE_CONV_OVF_I1_UN:
2320 THROW_EX (get_exception_overflow (), ip);
2321 sp [-1].data.i = value;
2322 sp [-1].type = VAL_I32;
2324 case CEE_CONV_OVF_I2_UN:
2326 THROW_EX (get_exception_overflow (), ip);
2327 sp [-1].data.i = value;
2328 sp [-1].type = VAL_I32;
2330 #if SIZEOF_VOID_P == 4
2331 case CEE_CONV_OVF_I_UN: /* Fall through */
2333 case CEE_CONV_OVF_I4_UN:
2334 if (value > 2147483647)
2335 THROW_EX (get_exception_overflow (), ip);
2336 sp [-1].data.i = value;
2337 sp [-1].type = VAL_I32;
2339 case CEE_CONV_OVF_U1_UN:
2341 THROW_EX (get_exception_overflow (), ip);
2342 sp [-1].data.i = value;
2343 sp [-1].type = VAL_I32;
2345 case CEE_CONV_OVF_U2_UN:
2347 THROW_EX (get_exception_overflow (), ip);
2348 sp [-1].data.i = value;
2349 sp [-1].type = VAL_I32;
2351 #if SIZEOF_VOID_P == 4
2352 case CEE_CONV_OVF_U_UN: /* Fall through */
2354 case CEE_CONV_OVF_U4_UN:
2355 if (value > 4294967295U)
2356 THROW_EX (get_exception_overflow (), ip);
2357 sp [-1].data.i = value;
2358 sp [-1].type = VAL_I32;
2361 g_assert_not_reached ();
2371 token = read32 (ip);
2373 class = mono_class_get (image, token);
2374 g_assert (class != NULL);
2376 sp [-1].type = VAL_OBJ;
2377 sp [-1].data.p = mono_value_box (class, &sp [-1]);
2378 /* need to vt_free (sp); */
2390 token = read32 (ip);
2391 class = mono_class_get (image, token);
2392 o = mono_new_szarray (class, sp [-1].data.i);
2395 sp [-1].type = VAL_OBJ;
2405 g_assert (sp [-1].type == VAL_OBJ);
2408 g_assert (o != NULL);
2410 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2412 sp [-1].type = VAL_I32;
2413 sp [-1].data.i = o->bounds [0].length;
2417 CASE (CEE_LDELEMA) {
2419 guint32 esize, token;
2422 token = read32 (ip);
2426 g_assert (sp [0].type == VAL_OBJ);
2429 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2431 g_assert (sp [1].data.i >= 0);
2432 g_assert (sp [1].data.i < o->bounds [0].length);
2434 /* check the array element corresponds to token */
2435 esize = mono_array_element_size ((MonoArrayClass *)o->obj.klass);
2438 sp->data.p = ((MonoArrayObject *)o)->vector + (sp [1].data.i * esize);
2439 sp->data.vt.klass = ((MonoArrayClass *)o->obj.klass)->element_class;
2443 CASE (CEE_LDELEM_I1) /* fall through */
2444 CASE (CEE_LDELEM_U1) /* fall through */
2445 CASE (CEE_LDELEM_I2) /* fall through */
2446 CASE (CEE_LDELEM_U2) /* fall through */
2447 CASE (CEE_LDELEM_I4) /* fall through */
2448 CASE (CEE_LDELEM_U4) /* fall through */
2449 CASE (CEE_LDELEM_I8) /* fall through */
2450 CASE (CEE_LDELEM_I) /* fall through */
2451 CASE (CEE_LDELEM_R4) /* fall through */
2452 CASE (CEE_LDELEM_R8) /* fall through */
2453 CASE (CEE_LDELEM_REF) {
2459 g_assert (sp [0].type == VAL_OBJ);
2462 THROW_EX (get_exception_null_reference (), ip);
2464 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2466 aindex = sp [1].data.nati;
2467 if (aindex >= o->bounds [0].length)
2468 THROW_EX (get_exception_index_out_of_range (), ip);
2471 * FIXME: throw get_exception_array_type_mismatch () if needed
2475 sp [0].data.i = ((gint8 *)o->vector)[aindex];
2476 sp [0].type = VAL_I32;
2479 sp [0].data.i = ((guint8 *)o->vector)[aindex];
2480 sp [0].type = VAL_I32;
2483 sp [0].data.i = ((gint16 *)o->vector)[aindex];
2484 sp [0].type = VAL_I32;
2487 sp [0].data.i = ((guint16 *)o->vector)[aindex];
2488 sp [0].type = VAL_I32;
2491 sp [0].data.nati = ((mono_i *)o->vector)[aindex];
2492 sp [0].type = VAL_NATI;
2495 sp [0].data.i = ((gint32 *)o->vector)[aindex];
2496 sp [0].type = VAL_I32;
2499 sp [0].data.i = ((guint32 *)o->vector)[aindex];
2500 sp [0].type = VAL_I32;
2503 sp [0].data.l = ((gint64 *)o->vector)[aindex];
2504 sp [0].type = VAL_I64;
2507 sp [0].data.f = ((float *)o->vector)[aindex];
2508 sp [0].type = VAL_DOUBLE;
2511 sp [0].data.f = ((double *)o->vector)[aindex];
2512 sp [0].type = VAL_DOUBLE;
2514 case CEE_LDELEM_REF:
2515 sp [0].data.p = ((gpointer *)o->vector)[aindex];
2516 sp [0].data.vt.klass = NULL;
2517 sp [0].type = VAL_OBJ;
2527 CASE (CEE_STELEM_I) /* fall through */
2528 CASE (CEE_STELEM_I1) /* fall through */
2529 CASE (CEE_STELEM_I2) /* fall through */
2530 CASE (CEE_STELEM_I4) /* fall through */
2531 CASE (CEE_STELEM_I8) /* fall through */
2532 CASE (CEE_STELEM_R4) /* fall through */
2533 CASE (CEE_STELEM_R8) /* fall through */
2534 CASE (CEE_STELEM_REF) {
2542 g_assert (sp [0].type == VAL_OBJ);
2545 THROW_EX (get_exception_null_reference (), ip);
2547 g_assert (MONO_CLASS_IS_ARRAY (o->obj.klass));
2548 ac = (MonoArrayClass *)o->obj.klass;
2550 aindex = sp [1].data.nati;
2551 if (aindex >= o->bounds [0].length)
2552 THROW_EX (get_exception_index_out_of_range (), ip);
2555 * FIXME: throw get_exception_array_type_mismatch () if needed
2559 ((mono_i *)o->vector)[aindex] = sp [2].data.nati;
2562 ((gint8 *)o->vector)[aindex] = sp [2].data.i;
2565 ((gint16 *)o->vector)[aindex] = sp [2].data.i;
2568 ((gint32 *)o->vector)[aindex] = sp [2].data.i;
2571 ((gint64 *)o->vector)[aindex] = sp [2].data.l;
2574 ((float *)o->vector)[aindex] = sp [2].data.f;
2577 ((double *)o->vector)[aindex] = sp [2].data.f;
2579 case CEE_STELEM_REF:
2580 g_assert (sp [2].type == VAL_OBJ);
2584 /*fixme: what about type conversions ? */
2585 g_assert (v->klass == ac->element_class);
2587 ((gpointer *)o->vector)[aindex] = sp [2].data.p;
2611 CASE (CEE_UNUSED17) ves_abort(); BREAK;
2612 CASE (CEE_CONV_OVF_I1)
2613 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
2614 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
2615 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
2616 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
2617 CASE (CEE_CONV_OVF_U4)
2619 /* FIXME: handle other cases */
2620 if (sp [-1].type == VAL_I32) {
2621 /* defined as NOP */
2626 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
2627 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
2634 CASE (CEE_UNUSED23) ves_abort(); BREAK;
2635 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
2636 CASE (CEE_CKFINITE) ves_abort(); BREAK;
2637 CASE (CEE_UNUSED24) ves_abort(); BREAK;
2638 CASE (CEE_UNUSED25) ves_abort(); BREAK;
2639 CASE (CEE_MKREFANY) ves_abort(); BREAK;
2648 CASE (CEE_UNUSED67) ves_abort(); BREAK;
2650 /*CASE (CEE_CONV_I) ves_abort(); BREAK; */
2651 CASE (CEE_CONV_OVF_I) ves_abort(); BREAK;
2652 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
2653 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
2654 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
2655 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
2656 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
2657 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
2658 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
2659 CASE (CEE_ENDFINALLY)
2663 * There was no exception, we continue normally at the target address.
2667 CASE (CEE_LEAVE) /* Fall through */
2669 if (*ip == CEE_LEAVE_S) {
2671 ip += (signed char) *ip;
2675 ip += (gint32) read32 (ip);
2679 * We may be either inside a try block or inside an handler.
2680 * In the first case there was no exception and we go on
2681 * executing the finally handlers and after that resume control
2683 * In the second case we need to clear the exception and
2684 * continue directly at the target ip.
2688 frame->ex_handler = NULL;
2691 goto handle_finally;
2723 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
2725 * Note: Exceptions thrown when executing a prefixed opcode need
2726 * to take into account the number of prefix bytes (usually the
2727 * throw point is just (ip - n_prefix_bytes).
2732 case CEE_ARGLIST: ves_abort(); break;
2738 if (sp->type == VAL_I32)
2739 result = sp [0].data.i == (gint)GET_NATI (sp [1]);
2740 else if (sp->type == VAL_I64)
2741 result = sp [0].data.l == sp [1].data.l;
2742 else if (sp->type == VAL_DOUBLE)
2743 result = sp [0].data.f == sp [1].data.f;
2745 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
2747 sp->data.i = result;
2757 if (sp->type == VAL_I32)
2758 result = sp [0].data.i > (gint)GET_NATI (sp [1]);
2759 else if (sp->type == VAL_I64)
2760 result = sp [0].data.l > sp [1].data.l;
2761 else if (sp->type == VAL_DOUBLE)
2762 result = sp [0].data.f > sp [1].data.f;
2764 result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
2766 sp->data.i = result;
2771 case CEE_CGT_UN: ves_abort(); break;
2777 if (sp->type == VAL_I32)
2778 result = sp [0].data.i < (gint)GET_NATI (sp [1]);
2779 else if (sp->type == VAL_I64)
2780 result = sp [0].data.l < sp [1].data.l;
2781 else if (sp->type == VAL_DOUBLE)
2782 result = sp [0].data.f < sp [1].data.f;
2784 result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
2786 sp->data.i = result;
2791 case CEE_CLT_UN: ves_abort(); break;
2795 token = read32 (ip);
2797 sp->type = VAL_NATI;
2798 sp->data.p = mono_create_method_pointer (mono_get_method (image, token, NULL));
2799 sp->data.vt.klass = NULL;
2803 case CEE_LDVIRTFTN: ves_abort(); break;
2804 case CEE_UNUSED56: ves_abort(); break;
2808 arg_pos = read32 (ip);
2810 vt_alloc (ARG_TYPE (signature, arg_pos), sp);
2811 stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2815 case CEE_LDARGA: ves_abort(); break;
2819 arg_pos = read32 (ip);
2822 stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos));
2829 loc_pos = read32 (ip);
2831 vt_alloc (LOCAL_TYPE (header, loc_pos), sp);
2832 stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2842 loc_pos = read32 (ip);
2844 t = LOCAL_TYPE (header, loc_pos);
2845 c = mono_class_from_mono_type (t);
2846 sp->data.vt.vt = LOCAL_POS (loc_pos);
2847 sp->data.vt.klass = c;
2850 sp->type = VAL_VALUETA;
2860 loc_pos = read32 (ip);
2863 stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos));
2868 if (sp != frame->stack)
2869 THROW_EX (get_exception_execution_engine (), ip - 1);
2871 sp->data.p = alloca (sp->data.i);
2874 case CEE_UNUSED57: ves_abort(); break;
2875 case CEE_ENDFILTER: ves_abort(); break;
2876 case CEE_UNALIGNED_:
2878 unaligned_address = 1;
2882 volatile_address = 1;
2891 token = read32 (ip);
2894 * we ignore the value of token (I think we can as unspecified
2895 * behavior described in Partition II, 3.5).
2898 g_assert (sp->type = VAL_VALUETA);
2899 memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
2902 case CEE_UNUSED68: ves_abort(); break;
2905 if (!sp [0].data.p || !sp [1].data.p)
2906 THROW_EX (get_exception_null_reference(), ip - 1);
2908 /* FIXME: value and size may be int64... */
2909 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
2914 THROW_EX (get_exception_null_reference(), ip - 1);
2916 /* FIXME: value and size may be int64... */
2917 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
2919 case CEE_UNUSED69: ves_abort(); break;
2922 * need to clarify what this should actually do:
2923 * start the search from the last found handler in
2924 * this method or continue in the caller or what.
2925 * Also, do we need to run finally/fault handlers after a retrow?
2926 * Well, this implementation will follow the usual search
2927 * for an handler, considering the current ip as throw spot.
2928 * We need to NULL frame->ex_handler for the later code to
2929 * actually run the new found handler.
2931 frame->ex_handler = NULL;
2932 THROW_EX (frame->ex, ip - 1);
2934 case CEE_UNUSED: ves_abort(); break;
2939 token = read32 (ip);
2941 c = mono_class_get (image, token);
2943 sp->data.i = mono_class_value_size (c, NULL);
2947 case CEE_REFANYTYPE: ves_abort(); break;
2954 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
2961 g_assert_not_reached ();
2963 * Exception handling code.
2964 * The exception object is stored in frame->ex.
2966 #define OFFSET_IN_CLAUSE(clause,offset) \
2967 ((clause)->try_offset <= (offset) && (offset) < ((clause)->try_offset + (clause)->try_len))
2973 MonoInvocation *inv;
2974 MonoMethodHeader *hd;
2975 MonoExceptionClause *clause;
2977 for (inv = frame; inv; inv = inv->parent) {
2978 hd = ((MonoMethodNormal*)inv->method)->header;
2979 ip_offset = inv->ip - hd->code;
2980 for (i = 0; i < hd->num_clauses; ++i) {
2981 clause = &hd->clauses [i];
2982 if (clause->flags <= 1 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
2983 if (!clause->flags) {
2984 if (mono_object_isinst (frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
2986 * OK, we found an handler, now we need to execute the finally
2987 * and fault blocks before branching to the handler code.
2989 inv->ex_handler = clause;
2990 goto handle_finally;
2993 /* FIXME: handle filter clauses */
3000 * If we get here, no handler was found: print a stack trace.
3002 g_print ("Unhandled exception %s.%s.\n", frame->ex->klass->name_space, frame->ex->klass->name);
3003 for (inv = frame, i = 0; inv; inv = inv->parent, ++i) {
3004 MonoClass *k = inv->method->klass;
3005 MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
3006 g_print ("#%d: 0x%05x in %s.%s::%s (", i, inv->ip - hd->code,
3007 k->name_space, k->name, inv->method->name);
3008 dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
3017 MonoExceptionClause *clause;
3019 ip_offset = frame->ip - header->code;
3020 for (i = 0; i < header->num_clauses; ++i) {
3021 clause = &header->clauses [i];
3022 if (clause->flags == 2 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3023 ip = header->code + clause->handler_offset;
3028 * If an exception is set, we need to execute the fault handler, too,
3029 * otherwise, we continue normally.
3040 MonoExceptionClause *clause;
3042 ip_offset = frame->ip - header->code;
3043 for (i = 0; i < header->num_clauses; ++i) {
3044 clause = &header->clauses [i];
3045 if (clause->flags == 3 && OFFSET_IN_CLAUSE (clause, ip_offset)) {
3046 ip = header->code + clause->handler_offset;
3051 * If the handler for the exception was found in this method, we jump
3052 * to it right away, otherwise we return and let the caller run
3053 * the finally, fault and catch blocks.
3054 * This same code should be present in the endfault opcode, but it
3055 * is corrently not assigned in the ECMA specs: LAMESPEC.
3057 if (frame->ex_handler) {
3058 ip = header->code + frame->ex_handler->handler_offset;
3061 sp->data.p = frame->ex;
3072 ves_exec (MonoAssembly *assembly, int argc, char *argv[])
3074 MonoImage *image = assembly->image;
3075 MonoCLIImageInfo *iinfo;
3077 MonoInvocation call;
3080 iinfo = image->image_info;
3081 method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
3083 if (method->signature->param_count) {
3085 stackval argv_array;
3086 MonoArrayObject *arr = (MonoArrayObject*)mono_new_szarray (mono_defaults.string_class, argc);
3087 argv_array.type = VAL_OBJ;
3088 argv_array.data.p = arr;
3089 argv_array.data.vt.klass = NULL;
3090 for (i=0; i < argc; ++i) {
3091 ((gpointer *)arr->vector)[i] = mono_new_string (argv [i]);
3093 INIT_FRAME (&call, NULL, NULL, &argv_array, &result, method);
3095 INIT_FRAME (&call, NULL, NULL, NULL, &result, method);
3098 ves_exec_method (&call);
3099 mono_free_method (call.method);
3101 return result.data.i;
3108 "mint %s, the Mono ECMA CLI interpreter, (C) 2001 Ximian, Inc.\n\n"
3109 "Usage is: mint [options] executable args...\n", VERSION);
3111 "Valid Options are:\n"
3113 "--debug method_name\n"
3114 "--opcode-count\n");
3120 test_load_class (MonoImage* image)
3122 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3126 for (i = 1; i <= t->rows; ++i) {
3127 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
3128 mono_class_metadata_init (klass);
3134 main (int argc, char *argv [])
3136 MonoAssembly *assembly;
3137 int retval = 0, i, ocount = 0;
3143 for (i = 1; argv [i][0] == '-'; i++){
3144 if (strcmp (argv [i], "--trace") == 0)
3146 if (strcmp (argv [i], "--opcode-count") == 0)
3148 if (strcmp (argv [i], "--help") == 0)
3150 if (strcmp (argv [i], "--debug") == 0)
3151 db_methods = g_list_append (db_methods, argv [++i]);
3159 mono_add_internal_call ("__array_Set", ves_array_set);
3160 mono_add_internal_call ("__array_Get", ves_array_get);
3162 assembly = mono_assembly_open (file, NULL, NULL);
3164 fprintf (stderr, "Can not open image %s\n", file);
3169 test_load_class (assembly->image);
3172 * skip the program name from the args.
3175 retval = ves_exec (assembly, argc - i, argv + i);
3177 mono_assembly_close (assembly);
3181 fprintf (stderr, "opcode count: %ld\n", opcode_count);
3182 fprintf (stderr, "fcall count: %ld\n", fcall_count);