2 * PLEASE NOTE: This is a research prototype.
5 * interp.c: Interpreter for CIL byte codes
8 * Paolo Molaro (lupus@ximian.com)
9 * Miguel de Icaza (miguel@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2001, 2002 Ximian, Inc.
27 #include <mono/utils/gc_wrapper.h>
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/reflection-internals.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
61 #include "interp-internals.h"
65 #include <mono/mini/mini.h>
66 #include <mono/mini/jit-icalls.h>
69 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
72 #define finite _finite
76 #define finite isfinite
80 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) \
82 (frame)->parent = (parent_frame); \
83 (frame)->stack_args = (method_args); \
84 (frame)->retval = (method_retval); \
85 (frame)->runtime_method = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
88 (frame)->invoke_trap = 0; \
91 void ves_exec_method (MonoInvocation *frame);
93 static char* dump_stack (stackval *stack, stackval *sp);
94 static char* dump_frame (MonoInvocation *inv);
95 static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
96 static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
98 typedef void (*ICallMethod) (MonoInvocation *frame);
100 static guint32 die_on_exception = 0;
101 static MonoNativeTlsKey thread_context_id;
103 static char* dump_args (MonoInvocation *inv);
105 #define DEBUG_INTERP 0
108 int mono_interp_traceopt = 2;
109 /* If true, then we output the opcodes as we interpret them */
110 static int global_tracing = 2;
112 static int debug_indent_level = 0;
114 static int break_on_method = 0;
115 static int nested_trace = 0;
116 static GList *db_methods = NULL;
123 for (h = 0; h < debug_indent_level; h++)
128 db_match_method (gpointer data, gpointer user_data)
130 MonoMethod *m = (MonoMethod*)user_data;
131 MonoMethodDesc *desc = data;
133 if (mono_method_desc_full_match (desc, m))
137 static void debug_enter (MonoInvocation *frame, int *tracing)
140 g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
142 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
146 MonoMethod *method = frame->runtime_method->method;
147 char *mn, *args = dump_args (frame);
148 debug_indent_level++;
150 mn = mono_method_full_name (method, FALSE);
151 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
153 g_print ("%s)\n", args);
156 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)
157 mono_profiler_method_enter (frame->runtime_method->method);
161 #define DEBUG_LEAVE() \
164 args = dump_retval (frame); \
166 mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
167 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
169 g_print (" => %s\n", args); \
171 debug_indent_level--; \
172 if (tracing == 3) global_tracing = 0; \
174 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
175 mono_profiler_method_leave (frame->runtime_method->method);
179 int mono_interp_traceopt = 0;
180 static void debug_enter (MonoInvocation *frame, int *tracing)
183 #define DEBUG_LEAVE()
188 interp_ex_handler (MonoException *ex) {
190 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
194 stack_trace = dump_frame (context->current_frame);
195 ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
196 g_free (stack_trace);
197 if (context->current_env == NULL || strcmp(ex->object.vtable->klass->name, "ExecutionEngineException") == 0) {
198 char *strace = mono_string_to_utf8_checked (ex->stack_trace, &error);
199 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
200 fprintf(stderr, "Nothing can catch this exception: ");
201 fprintf(stderr, "%s", ex->object.vtable->klass->name);
202 if (ex->message != NULL) {
203 char *m = mono_string_to_utf8_checked (ex->message, &error);
204 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
205 fprintf(stderr, ": %s", m);
208 fprintf(stderr, "\n%s\n", strace);
210 if (ex->inner_ex != NULL) {
211 ex = (MonoException *)ex->inner_ex;
212 fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name);
213 if (ex->message != NULL) {
214 char *m = mono_string_to_utf8_checked (ex->message, &error);
215 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
216 fprintf(stderr, ": %s", m);
219 strace = mono_string_to_utf8_checked (ex->stack_trace, &error);
220 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
221 fprintf(stderr, "\n");
222 fprintf(stderr, "%s\n", strace);
225 /* wait for other threads to also collapse */
226 // Sleep(1000); // TODO: proper sleep
229 context->env_frame->ex = ex;
230 context->search_for_handler = 1;
231 longjmp (*context->current_env, 1);
235 ves_real_abort (int line, MonoMethod *mh,
236 const unsigned short *ip, stackval *stack, stackval *sp)
239 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
240 fprintf (stderr, "Line=%d IP=0x%04lx, Aborted execution\n", line,
241 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code);
242 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
243 g_print ("0x%04x %02x\n",
244 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code, *ip);
245 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
247 printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
250 #define ves_abort() \
252 ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
253 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
257 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
262 mono_domain_jit_code_hash_lock (domain);
263 if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) {
264 mono_domain_jit_code_hash_unlock (domain);
267 rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
268 rtm->method = method;
269 rtm->param_count = mono_method_signature (method)->param_count;
270 rtm->hasthis = mono_method_signature (method)->hasthis;
271 mono_internal_hash_table_insert (&domain->jit_code_hash, method, rtm);
272 mono_domain_jit_code_hash_unlock (domain);
278 mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
280 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
281 method = mono_marshal_get_synchronized_wrapper (method);
282 return mono_interp_get_runtime_method (domain, method, error);
285 static inline RuntimeMethod*
286 get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
288 MonoMethod *m = runtime_method->method;
291 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
292 RuntimeMethod *ret = NULL;
293 if (mono_object_is_transparent_proxy (obj)) {
294 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
295 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
296 } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
297 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
298 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
300 ret = runtime_method;
305 mono_class_setup_vtable (obj->vtable->klass);
307 int slot = mono_method_get_vtable_slot (m);
308 if (mono_class_is_interface (m->klass)) {
309 g_assert (obj->vtable->klass != m->klass);
310 /* TODO: interface offset lookup is slow, go through IMT instead */
311 gboolean non_exact_match;
312 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
315 MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
316 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
317 MonoGenericContext context = { NULL, NULL };
319 if (mono_class_is_ginst (virtual_method->klass))
320 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
321 else if (mono_class_is_gtd (virtual_method->klass))
322 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
323 context.method_inst = mono_method_get_context (m)->method_inst;
325 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
326 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
328 RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
329 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
330 return virtual_runtime_method;
334 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
337 switch (type->type) {
338 case MONO_TYPE_OBJECT:
339 case MONO_TYPE_CLASS:
340 case MONO_TYPE_STRING:
341 case MONO_TYPE_ARRAY:
342 case MONO_TYPE_SZARRAY:
347 result->data.p = *(gpointer*)data;
350 switch (type->type) {
354 result->data.i = *(gint8*)data;
357 case MONO_TYPE_BOOLEAN:
358 result->data.i = *(guint8*)data;
361 result->data.i = *(gint16*)data;
365 result->data.i = *(guint16*)data;
368 result->data.i = *(gint32*)data;
372 result->data.nati = *(mono_i*)data;
375 result->data.p = *(gpointer*)data;
378 result->data.i = *(guint32*)data;
381 result->data.f = *(float*)data;
385 result->data.l = *(gint64*)data;
388 result->data.f = *(double*)data;
390 case MONO_TYPE_STRING:
391 case MONO_TYPE_SZARRAY:
392 case MONO_TYPE_CLASS:
393 case MONO_TYPE_OBJECT:
394 case MONO_TYPE_ARRAY:
395 result->data.p = *(gpointer*)data;
397 case MONO_TYPE_VALUETYPE:
398 if (type->data.klass->enumtype) {
399 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
402 mono_value_copy (result->data.vt, data, type->data.klass);
404 case MONO_TYPE_GENERICINST:
405 stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
408 g_warning ("got type 0x%02x", type->type);
409 g_assert_not_reached ();
414 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
417 gpointer *p = (gpointer*)data;
421 /* printf ("TODAT0 %p\n", data); */
422 switch (type->type) {
425 guint8 *p = (guint8*)data;
429 case MONO_TYPE_BOOLEAN: {
430 guint8 *p = (guint8*)data;
431 *p = (val->data.i != 0);
436 case MONO_TYPE_CHAR: {
437 guint16 *p = (guint16*)data;
442 mono_i *p = (mono_i*)data;
443 /* In theory the value used by stloc should match the local var type
444 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
445 a native int - both by csc and mcs). Not sure what to do about sign extension
446 as it is outside the spec... doing the obvious */
447 *p = (mono_i)val->data.nati;
451 mono_u *p = (mono_u*)data;
453 *p = (mono_u)val->data.nati;
458 gint32 *p = (gint32*)data;
464 gint64 *p = (gint64*)data;
469 float *p = (float*)data;
474 double *p = (double*)data;
478 case MONO_TYPE_STRING:
479 case MONO_TYPE_SZARRAY:
480 case MONO_TYPE_CLASS:
481 case MONO_TYPE_OBJECT:
482 case MONO_TYPE_ARRAY:
483 case MONO_TYPE_PTR: {
484 gpointer *p = (gpointer*)data;
488 case MONO_TYPE_VALUETYPE:
489 if (type->data.klass->enumtype) {
490 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
493 mono_value_copy (data, val->data.vt, type->data.klass);
495 case MONO_TYPE_GENERICINST:
496 stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
499 g_warning ("got type %x", type->type);
500 g_assert_not_reached ();
505 fill_in_trace (MonoException *exception, MonoInvocation *frame)
507 char *stack_trace = dump_frame (frame);
508 MonoDomain *domain = mono_domain_get();
509 (exception)->stack_trace = mono_string_new (domain, stack_trace);
510 (exception)->trace_ips = get_trace_ips (domain, frame);
511 g_free (stack_trace);
514 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
516 #define THROW_EX(exception,ex_ip) \
518 frame->ip = (ex_ip); \
519 frame->ex = (MonoException*)(exception); \
520 FILL_IN_TRACE(frame->ex, frame); \
521 goto handle_exception; \
525 ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
528 intptr_t *lower_bounds;
533 lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
534 for (i = 0; i < sig->param_count; ++i) {
535 lengths [i] = values->data.i;
538 if (klass->rank == sig->param_count) {
539 /* Only lengths provided. */
542 /* lower bounds are first. */
543 lower_bounds = (intptr_t *) lengths;
544 lengths += klass->rank;
546 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
547 if (!mono_error_ok (&error)) {
548 frame->ex = mono_error_convert_to_exception (&error);
549 FILL_IN_TRACE (frame->ex, frame);
551 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
556 ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
558 g_assert (!frame->ex);
559 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
563 for (gint32 i = 0; i < ac->rank; i++) {
564 guint32 idx = sp [i].data.i;
565 guint32 lower = ao->bounds [i].lower_bound;
566 guint32 len = ao->bounds [i].length;
567 if (idx < lower || (idx - lower) >= len) {
568 frame->ex = mono_get_exception_index_out_of_range ();
569 FILL_IN_TRACE (frame->ex, frame);
572 pos = (pos * len) + idx - lower;
576 if (pos >= ao->max_length) {
577 frame->ex = mono_get_exception_index_out_of_range ();
578 FILL_IN_TRACE (frame->ex, frame);
586 ves_array_set (MonoInvocation *frame)
588 stackval *sp = frame->stack_args + 1;
590 MonoObject *o = frame->stack_args->data.p;
591 MonoArray *ao = (MonoArray *) o;
592 MonoClass *ac = o->vtable->klass;
594 g_assert (ac->rank >= 1);
596 gint32 pos = ves_array_calculate_index (ao, sp, frame);
600 if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
602 MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
603 mono_error_cleanup (&error);
605 frame->ex = mono_get_exception_array_type_mismatch ();
606 FILL_IN_TRACE (frame->ex, frame);
611 gint32 esize = mono_array_element_size (ac);
612 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
614 MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
615 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
619 ves_array_get (MonoInvocation *frame)
621 stackval *sp = frame->stack_args + 1;
623 MonoObject *o = frame->stack_args->data.p;
624 MonoArray *ao = (MonoArray *) o;
625 MonoClass *ac = o->vtable->klass;
627 g_assert (ac->rank >= 1);
629 gint32 pos = ves_array_calculate_index (ao, sp, frame);
633 gint32 esize = mono_array_element_size (ac);
634 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
636 MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret;
637 stackval_from_data (mt, frame->retval, ea, FALSE);
641 ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
643 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
645 g_assert (ac->rank >= 1);
647 gint32 pos = ves_array_calculate_index (ao, sp, frame);
651 if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
652 frame->ex = mono_get_exception_array_type_mismatch ();
653 FILL_IN_TRACE (frame->ex, frame);
656 gint32 esize = mono_array_element_size (ac);
657 return mono_array_addr_with_size (ao, esize, pos);
661 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
664 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
666 MonoInvocation *frame = context->current_frame;
669 MonoStackFrameInfo fi;
670 memset (&fi, 0, sizeof (MonoStackFrameInfo));
672 /* TODO: hack to make some asserts happy. */
673 fi.ji = (MonoJitInfo *) frame->runtime_method;
675 if (frame->runtime_method)
676 fi.method = fi.actual_method = frame->runtime_method->method;
678 if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
680 fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
682 MonoMethodHeader *hd = mono_method_get_header_checked (fi.method, &error);
683 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
684 fi.type = FRAME_TYPE_MANAGED;
685 fi.il_offset = frame->ip - (const unsigned short *) hd->code;
686 if (!fi.method->wrapper_type)
690 if (func (&fi, ctx, user_data))
692 frame = frame->parent;
698 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
700 struct _MethodArguments {
709 typedef struct _MethodArguments MethodArguments;
711 // TODO: this function is also arch dependent (register width).
712 static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
714 // TODO: don't malloc this data structure.
715 MethodArguments *margs = g_malloc0 (sizeof (MethodArguments));
720 for (int i = 0; i < sig->param_count; i++) {
721 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
723 case MONO_TYPE_BOOLEAN:
734 case MONO_TYPE_SZARRAY:
735 case MONO_TYPE_CLASS:
736 case MONO_TYPE_OBJECT:
737 case MONO_TYPE_STRING:
739 case MONO_TYPE_VALUETYPE:
740 case MONO_TYPE_GENERICINST:
748 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
753 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
756 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
759 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
762 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
769 margs->iargs [0] = frame->stack_args->data.p;
773 for (int i = 0; i < sig->param_count; i++) {
774 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
776 case MONO_TYPE_BOOLEAN:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_STRING:
792 case MONO_TYPE_VALUETYPE:
793 case MONO_TYPE_GENERICINST:
794 margs->iargs [int_i] = frame->stack_args [i].data.p;
796 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
802 if (ptype == MONO_TYPE_R4)
803 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
805 margs->fargs [int_f] = frame->stack_args [i].data.f;
807 g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i);
812 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
816 switch (sig->ret->type) {
817 case MONO_TYPE_BOOLEAN:
828 case MONO_TYPE_SZARRAY:
829 case MONO_TYPE_CLASS:
830 case MONO_TYPE_OBJECT:
831 case MONO_TYPE_STRING:
833 case MONO_TYPE_VALUETYPE:
834 case MONO_TYPE_GENERICINST:
835 margs->retval = &(frame->retval->data.p);
839 margs->retval = &(frame->retval->data.p);
840 margs->is_float_ret = 1;
843 margs->retval = NULL;
846 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
853 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
856 MonoInvocation *old_frame = context->current_frame;
857 MonoInvocation *old_env_frame = context->env_frame;
858 jmp_buf *old_env = context->current_env;
861 context->current_frame = old_frame;
862 context->env_frame = old_env_frame;
863 context->current_env = old_env;
864 context->managed_code = 1;
869 context->env_frame = frame;
870 context->current_env = &env;
872 g_assert (!frame->runtime_method);
873 if (!mono_interp_enter_icall_trampoline) {
875 mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
877 // mono_tramp_info_register (info, NULL);
880 MethodArguments *margs = build_args_from_sig (sig, frame);
882 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
883 g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
886 context->current_frame = frame;
887 context->managed_code = 0;
889 mono_interp_enter_icall_trampoline (addr, margs);
891 context->managed_code = 1;
892 /* domain can only be changed by native code */
893 context->domain = mono_domain_get ();
895 if (*mono_thread_interruption_request_flag ()) {
896 MonoException *exc = mono_thread_interruption_checkpoint ();
899 context->search_for_handler = 1;
903 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
904 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
906 context->current_frame = old_frame;
907 context->env_frame = old_env_frame;
908 context->current_env = old_env;
910 g_free (margs->iargs);
911 g_free (margs->fargs);
916 mono_interp_init_delegate (MonoDelegate *del)
919 del->method = ((RuntimeMethod *) del->method_ptr)->method;
924 * runtime specifies that the implementation of the method is automatically
925 * provided by the runtime and is primarily used for the methods of delegates.
928 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
930 MonoMethod *method = frame->runtime_method->method;
931 const char *name = method->name;
932 MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
933 MonoObject *isinst_obj;
936 mono_class_init (method->klass);
938 isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
939 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
940 if (obj && isinst_obj) {
941 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
942 ves_array_set (frame);
945 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
946 ves_array_get (frame);
951 g_error ("Don't know how to exec runtime method %s.%s::%s",
952 method->klass->name_space, method->klass->name,
957 dump_stack (stackval *stack, stackval *sp)
960 GString *str = g_string_new ("");
963 return g_string_free (str, FALSE);
966 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
969 return g_string_free (str, FALSE);
973 dump_stackval (GString *str, stackval *s, MonoType *type)
975 switch (type->type) {
983 case MONO_TYPE_BOOLEAN:
984 g_string_append_printf (str, "[%d] ", s->data.i);
986 case MONO_TYPE_STRING:
987 case MONO_TYPE_SZARRAY:
988 case MONO_TYPE_CLASS:
989 case MONO_TYPE_OBJECT:
990 case MONO_TYPE_ARRAY:
994 g_string_append_printf (str, "[%p] ", s->data.p);
996 case MONO_TYPE_VALUETYPE:
997 if (type->data.klass->enumtype)
998 g_string_append_printf (str, "[%d] ", s->data.i);
1000 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1004 g_string_append_printf (str, "[%g] ", s->data.f);
1009 GString *res = g_string_new ("");
1010 mono_type_get_desc (res, type, TRUE);
1011 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1012 g_string_free (res, TRUE);
1019 dump_args (MonoInvocation *inv)
1021 GString *str = g_string_new ("");
1023 MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method);
1025 if (signature->param_count == 0 && !signature->hasthis)
1026 return g_string_free (str, FALSE);
1028 if (signature->hasthis) {
1029 MonoMethod *method = inv->runtime_method->method;
1030 dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1033 for (i = 0; i < signature->param_count; ++i)
1034 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1036 return g_string_free (str, FALSE);
1040 dump_retval (MonoInvocation *inv)
1042 GString *str = g_string_new ("");
1043 MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
1045 if (ret->type != MONO_TYPE_VOID)
1046 dump_stackval (str, inv->retval, ret);
1048 return g_string_free (str, FALSE);
1052 dump_frame (MonoInvocation *inv)
1054 GString *str = g_string_new ("");
1059 for (i = 0; inv; inv = inv->parent) {
1060 if (inv->runtime_method != NULL) {
1061 MonoMethod *method = inv->runtime_method->method;
1065 const char * opname = "";
1067 gchar *source = NULL;
1071 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1072 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1073 MonoMethodHeader *hd = mono_method_get_header_checked (method, &error);
1074 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1078 opname = mono_interp_opname [*inv->ip];
1079 codep = inv->ip - inv->runtime_method->code;
1080 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1085 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1086 source = mono_debug_method_lookup_location (minfo, codep);
1090 args = dump_args (inv);
1091 name = mono_method_full_name (method, TRUE);
1093 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1095 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1102 return g_string_free (str, FALSE);
1106 get_trace_ips (MonoDomain *domain, MonoInvocation *top)
1110 MonoInvocation *inv;
1113 for (i = 0, inv = top; inv; inv = inv->parent)
1114 if (inv->runtime_method != NULL)
1117 res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error);
1118 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1120 for (i = 0, inv = top; inv; inv = inv->parent)
1121 if (inv->runtime_method != NULL) {
1122 mono_array_set (res, gpointer, i, inv->runtime_method);
1124 mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1132 #define MYGUINT64_MAX 18446744073709551615ULL
1133 #define MYGINT64_MAX 9223372036854775807LL
1134 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1136 #define MYGUINT32_MAX 4294967295U
1137 #define MYGINT32_MAX 2147483647
1138 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1140 #define CHECK_ADD_OVERFLOW(a,b) \
1141 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1142 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1144 #define CHECK_SUB_OVERFLOW(a,b) \
1145 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1146 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1148 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1149 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1151 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1152 (guint32)(a) < (guint32)(b) ? -1 : 0
1154 #define CHECK_ADD_OVERFLOW64(a,b) \
1155 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1156 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1158 #define CHECK_SUB_OVERFLOW64(a,b) \
1159 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1160 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1162 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1163 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1165 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1166 (guint64)(a) < (guint64)(b) ? -1 : 0
1168 #if SIZEOF_VOID_P == 4
1169 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1170 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1172 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1173 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1176 /* Resolves to TRUE if the operands would overflow */
1177 #define CHECK_MUL_OVERFLOW(a,b) \
1178 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1179 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1180 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1181 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1182 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1183 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1184 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1186 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1187 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1188 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1190 #define CHECK_MUL_OVERFLOW64(a,b) \
1191 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1192 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1193 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1194 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1195 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1196 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1197 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1199 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1200 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1201 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1203 #if SIZEOF_VOID_P == 4
1204 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1205 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1207 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1208 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1212 mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1214 MonoInvocation frame;
1215 ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1216 MonoObject *retval = NULL;
1217 MonoMethodSignature *sig = mono_method_signature (method);
1218 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1219 int i, type, isobject = 0;
1222 stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
1223 ThreadContext context_struct;
1224 MonoInvocation *old_frame = NULL;
1232 if (context != &context_struct) {
1233 context->domain = mono_domain_get ();
1234 context->current_frame = old_frame;
1235 context->managed_code = 0;
1237 mono_native_tls_set_value (thread_context_id, NULL);
1239 *exc = (MonoObject *)frame.ex;
1243 if (context == NULL) {
1244 context = &context_struct;
1245 context_struct.base_frame = &frame;
1246 context_struct.current_frame = NULL;
1247 context_struct.env_frame = &frame;
1248 context_struct.current_env = &env;
1249 context_struct.search_for_handler = 0;
1250 context_struct.managed_code = 0;
1251 mono_native_tls_set_value (thread_context_id, context);
1254 old_frame = context->current_frame;
1256 context->domain = mono_domain_get ();
1258 switch (sig->ret->type) {
1259 case MONO_TYPE_VOID:
1261 case MONO_TYPE_STRING:
1262 case MONO_TYPE_OBJECT:
1263 case MONO_TYPE_CLASS:
1264 case MONO_TYPE_ARRAY:
1265 case MONO_TYPE_SZARRAY:
1268 case MONO_TYPE_VALUETYPE:
1269 retval = mono_object_new_checked (context->domain, klass, error);
1270 ret = ((char*)retval) + sizeof (MonoObject);
1271 if (!sig->ret->data.klass->enumtype)
1272 result.data.vt = ret;
1275 retval = mono_object_new_checked (context->domain, klass, error);
1276 ret = ((char*)retval) + sizeof (MonoObject);
1281 args [0].data.p = obj;
1283 for (i = 0; i < sig->param_count; ++i) {
1284 int a_index = i + !!sig->hasthis;
1285 if (sig->params [i]->byref) {
1286 args [a_index].data.p = params [i];
1289 type = sig->params [i]->type;
1294 case MONO_TYPE_BOOLEAN:
1295 args [a_index].data.i = *(MonoBoolean*)params [i];
1299 case MONO_TYPE_CHAR:
1300 args [a_index].data.i = *(gint16*)params [i];
1302 #if SIZEOF_VOID_P == 4
1303 case MONO_TYPE_U: /* use VAL_POINTER? */
1308 args [a_index].data.i = *(gint32*)params [i];
1310 #if SIZEOF_VOID_P == 8
1316 args [a_index].data.l = *(gint64*)params [i];
1318 case MONO_TYPE_VALUETYPE:
1319 if (sig->params [i]->data.klass->enumtype) {
1320 type = mono_class_enum_basetype (sig->params [i]->data.klass)->type;
1323 args [a_index].data.p = params [i];
1326 case MONO_TYPE_STRING:
1327 case MONO_TYPE_CLASS:
1328 case MONO_TYPE_ARRAY:
1329 case MONO_TYPE_SZARRAY:
1330 case MONO_TYPE_OBJECT:
1331 args [a_index].data.p = params [i];
1334 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1338 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1339 method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
1340 INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
1342 frame.invoke_trap = 1;
1343 context->managed_code = 1;
1344 ves_exec_method_with_context (&frame, context);
1345 context->managed_code = 0;
1346 if (context == &context_struct)
1347 mono_native_tls_set_value (thread_context_id, NULL);
1349 context->current_frame = old_frame;
1350 if (frame.ex != NULL) {
1352 *exc = (MonoObject*) frame.ex;
1355 if (context->current_env != NULL) {
1356 context->env_frame->ex = frame.ex;
1357 longjmp(*context->current_env, 1);
1360 printf("dropped exception...\n");
1362 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1364 if (isobject || method->string_ctor)
1365 return result.data.p;
1366 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1371 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1373 MonoInvocation *old_frame = context->current_frame;
1374 MonoInvocation *old_env_frame = context->env_frame;
1375 jmp_buf *old_env = context->current_env;
1379 context->current_frame = old_frame;
1380 context->env_frame = old_env_frame;
1381 context->current_env = old_env;
1382 context->managed_code = 1;
1386 context->env_frame = context->current_frame;
1387 context->current_env = &env;
1388 context->managed_code = 0;
1391 case MINT_ICALL_V_V: {
1392 void (*func)() = ptr;
1396 case MINT_ICALL_V_P: {
1397 gpointer (*func)() = ptr;
1399 sp [-1].data.p = func ();
1402 case MINT_ICALL_P_V: {
1403 void (*func)(gpointer) = ptr;
1404 func (sp [-1].data.p);
1408 case MINT_ICALL_P_P: {
1409 gpointer (*func)(gpointer) = ptr;
1410 sp [-1].data.p = func (sp [-1].data.p);
1413 case MINT_ICALL_PP_V: {
1414 void (*func)(gpointer,gpointer) = ptr;
1416 func (sp [0].data.p, sp [1].data.p);
1419 case MINT_ICALL_PI_V: {
1420 void (*func)(gpointer,int) = ptr;
1422 func (sp [0].data.p, sp [1].data.i);
1425 case MINT_ICALL_PP_P: {
1426 gpointer (*func)(gpointer,gpointer) = ptr;
1428 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1431 case MINT_ICALL_PI_P: {
1432 gpointer (*func)(gpointer,int) = ptr;
1434 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1437 case MINT_ICALL_PPP_V: {
1438 void (*func)(gpointer,gpointer,gpointer) = ptr;
1440 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1443 case MINT_ICALL_PPI_V: {
1444 void (*func)(gpointer,gpointer,int) = ptr;
1446 func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1450 g_assert_not_reached ();
1453 context->env_frame = old_env_frame;
1454 context->current_env = old_env;
1459 static mono_mutex_t create_method_pointer_mutex;
1461 static GHashTable *method_pointer_hash = NULL;
1463 static MonoMethod *method_pointers [2] = {0};
1466 mp_tramp_0 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) {
1468 void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method};
1469 MonoObject *ret = mono_interp_runtime_invoke (method_pointers [0], NULL, params_real, NULL, &error);
1470 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1475 mp_tramp_1 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) {
1477 void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method};
1478 MonoObject *ret = mono_interp_runtime_invoke (method_pointers [1], NULL, params_real, NULL, &error);
1479 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1483 gpointer *mp_tramps[] = {(gpointer) mp_tramp_0, (gpointer) mp_tramp_1};
1485 static int tramps_used = 0;
1488 mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
1493 mono_os_mutex_lock (&create_method_pointer_mutex);
1494 if (!method_pointer_hash) {
1495 // FIXME: is registering method table as GC root really necessary?
1496 // MONO_GC_REGISTER_ROOT_FIXED (method_pointer_hash);
1497 method_pointer_hash = g_hash_table_new (NULL, NULL);
1499 addr = g_hash_table_lookup (method_pointer_hash, method);
1501 mono_os_mutex_unlock (&create_method_pointer_mutex);
1506 * If it is a static P/Invoke method, we can just return the pointer
1507 * to the method implementation.
1509 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) {
1510 ji = g_new0 (MonoJitInfo, 1);
1511 ji->d.method = method;
1513 ji->code_start = addr = ((MonoMethodPInvoke*) method)->addr;
1515 mono_jit_info_table_add (mono_get_root_domain (), ji);
1518 g_assert (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE);
1519 g_assert (tramps_used < 2);
1521 /* FIXME: needs locking */
1522 method_pointers [tramps_used] = method;
1523 addr = mp_tramps [tramps_used];
1527 g_hash_table_insert (method_pointer_hash, method, addr);
1528 mono_os_mutex_unlock (&create_method_pointer_mutex);
1534 static int opcode_counts[512];
1536 #define COUNT_OP(op) opcode_counts[op]++
1538 #define COUNT_OP(op)
1542 #define DUMP_INSTR() \
1543 if (tracing > 1) { \
1545 if (sp > frame->stack) { \
1546 ins = dump_stack (frame->stack, sp); \
1548 ins = g_strdup (""); \
1552 char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
1553 g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
1555 mono_interp_dis_mintop(rtm->code, ip); \
1556 g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
1560 #define DUMP_INSTR()
1564 #define USE_COMPUTED_GOTO 1
1566 #if USE_COMPUTED_GOTO
1567 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
1568 #define MINT_IN_CASE(x) LAB_ ## x:
1570 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
1572 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
1574 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
1576 #define MINT_IN_SWITCH(op) switch (op)
1577 #define MINT_IN_CASE(x) case x:
1578 #define MINT_IN_BREAK break
1579 #define MINT_IN_DEFAULT default:
1583 * Defining this causes register allocation errors in some versions of gcc:
1584 * error: unable to find a register to spill in class `SIREG'
1586 /* #define MINT_USE_DEDICATED_IP_REG */
1589 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
1591 MonoInvocation child_frame;
1592 GSList *finally_ips = NULL;
1593 const unsigned short *endfinally_ip = NULL;
1594 #if defined(__GNUC__) && defined (i386) && defined (MINT_USE_DEDICATED_IP_REG)
1595 register const unsigned short *ip asm ("%esi");
1597 register const unsigned short *ip;
1599 register stackval *sp;
1602 gint tracing = global_tracing;
1603 unsigned char *vtalloc;
1606 unsigned char *vt_sp;
1607 unsigned char *locals;
1609 MonoObject *o = NULL;
1611 #if USE_COMPUTED_GOTO
1612 static void *in_labels[] = {
1613 #define OPDEF(a,b,c,d) \
1615 #include "mintops.def"
1620 frame->ex_handler = NULL;
1622 context->current_frame = frame;
1625 debug_enter (frame, &tracing);
1628 if (!frame->runtime_method->transformed) {
1629 context->managed_code = 0;
1631 char *mn = mono_method_full_name (frame->runtime_method->method, TRUE);
1632 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
1635 frame->ex = mono_interp_transform_method (frame->runtime_method, context);
1636 context->managed_code = 1;
1644 rtm = frame->runtime_method;
1645 frame->args = alloca (rtm->alloca_size);
1646 memset (frame->args, 0, rtm->alloca_size);
1648 sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size);
1649 memset (sp, 0, rtm->stack_size);
1651 vt_sp = (unsigned char *) sp + rtm->stack_size;
1652 memset (vt_sp, 0, rtm->vt_stack_size);
1657 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
1658 memset (vt_sp, 0, rtm->locals_size);
1660 child_frame.parent = frame;
1666 * using while (ip < end) may result in a 15% performance drop,
1667 * but it may be useful for debug
1671 /* g_assert (sp >= frame->stack); */
1672 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
1674 MINT_IN_SWITCH (*ip) {
1675 MINT_IN_CASE(MINT_INITLOCALS)
1676 memset (locals, 0, rtm->locals_size);
1679 MINT_IN_CASE(MINT_NOP)
1682 MINT_IN_CASE(MINT_BREAK)
1684 G_BREAKPOINT (); /* this is not portable... */
1686 MINT_IN_CASE(MINT_LDNULL)
1691 MINT_IN_CASE(MINT_VTRESULT) {
1692 int ret_size = * (guint16 *)(ip + 1);
1693 unsigned char *ret_vt_sp = vt_sp;
1694 vt_sp -= READ32(ip + 2);
1696 memmove (vt_sp, ret_vt_sp, ret_size);
1697 sp [-1].data.p = vt_sp;
1698 vt_sp += (ret_size + 7) & ~7;
1703 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
1704 MINT_IN_CASE(MINT_LDC_I4_M1)
1707 MINT_IN_CASE(MINT_LDC_I4_0)
1710 MINT_IN_CASE(MINT_LDC_I4_1)
1713 MINT_IN_CASE(MINT_LDC_I4_2)
1716 MINT_IN_CASE(MINT_LDC_I4_3)
1719 MINT_IN_CASE(MINT_LDC_I4_4)
1722 MINT_IN_CASE(MINT_LDC_I4_5)
1725 MINT_IN_CASE(MINT_LDC_I4_6)
1728 MINT_IN_CASE(MINT_LDC_I4_7)
1731 MINT_IN_CASE(MINT_LDC_I4_8)
1734 MINT_IN_CASE(MINT_LDC_I4_S)
1735 sp->data.i = *(const short *)(ip + 1);
1739 MINT_IN_CASE(MINT_LDC_I4)
1741 sp->data.i = READ32 (ip);
1745 MINT_IN_CASE(MINT_LDC_I8)
1747 sp->data.l = READ64 (ip);
1751 MINT_IN_CASE(MINT_LDC_R4) {
1755 sp->data.f = * (float *)&val;
1760 MINT_IN_CASE(MINT_LDC_R8)
1761 sp->data.l = READ64 (ip + 1); /* note union usage */
1765 MINT_IN_CASE(MINT_DUP)
1770 MINT_IN_CASE(MINT_DUP_VT)
1771 i32 = READ32 (ip + 1);
1773 memcpy(sp->data.p, sp [-1].data.p, i32);
1774 vt_sp += (i32 + 7) & ~7;
1778 MINT_IN_CASE(MINT_POP) {
1779 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
1781 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
1786 MINT_IN_CASE(MINT_JMP) {
1787 RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
1788 if (!new_method->transformed) {
1790 frame->ex = mono_interp_transform_method (new_method, context);
1795 if (new_method->alloca_size > rtm->alloca_size)
1796 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size);
1797 rtm = frame->runtime_method = new_method;
1798 vt_sp = (unsigned char *) sp + rtm->stack_size;
1802 locals = vt_sp + rtm->vt_stack_size;
1803 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
1806 MINT_IN_CASE(MINT_CALLI) {
1807 MonoMethodSignature *csignature;
1808 stackval *endsp = sp;
1812 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
1816 child_frame.runtime_method = sp->data.p;
1819 child_frame.retval = sp;
1820 /* decrement by the actual number of args */
1821 sp -= csignature->param_count;
1822 if (csignature->hasthis)
1824 child_frame.stack_args = sp;
1826 /* `this' can be NULL for string:.ctor */
1827 if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
1828 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
1829 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1830 } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1831 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
1832 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1835 if (csignature->hasthis) {
1836 MonoObject *this_arg = sp->data.p;
1838 if (this_arg->vtable->klass->valuetype) {
1839 gpointer *unboxed = mono_object_unbox (this_arg);
1840 sp [0].data.p = unboxed;
1844 ves_exec_method_with_context (&child_frame, context);
1846 context->current_frame = frame;
1848 if (child_frame.ex) {
1850 * An exception occurred, need to run finally, fault and catch handlers..
1852 frame->ex = child_frame.ex;
1853 goto handle_finally;
1856 /* need to handle typedbyref ... */
1857 if (csignature->ret->type != MONO_TYPE_VOID) {
1863 MINT_IN_CASE(MINT_CALLI_NAT) {
1864 MonoMethodSignature *csignature;
1865 stackval *endsp = sp;
1866 unsigned char *code = NULL;
1870 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
1875 child_frame.runtime_method = NULL;
1878 child_frame.retval = sp;
1879 /* decrement by the actual number of args */
1880 sp -= csignature->param_count;
1881 if (csignature->hasthis)
1883 child_frame.stack_args = sp;
1884 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
1886 context->current_frame = frame;
1888 if (child_frame.ex) {
1890 * An exception occurred, need to run finally, fault and catch handlers..
1892 frame->ex = child_frame.ex;
1893 if (context->search_for_handler) {
1894 context->search_for_handler = 0;
1895 goto handle_exception;
1897 goto handle_finally;
1900 /* need to handle typedbyref ... */
1901 if (csignature->ret->type != MONO_TYPE_VOID) {
1907 MINT_IN_CASE(MINT_CALL) {
1908 stackval *endsp = sp;
1912 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
1915 child_frame.retval = sp;
1916 /* decrement by the actual number of args */
1917 sp -= child_frame.runtime_method->param_count;
1918 if (child_frame.runtime_method->hasthis)
1920 child_frame.stack_args = sp;
1922 /* `this' can be NULL for string:.ctor */
1923 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
1924 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
1925 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1927 ves_exec_method_with_context (&child_frame, context);
1929 context->current_frame = frame;
1931 if (child_frame.ex) {
1933 * An exception occurred, need to run finally, fault and catch handlers..
1935 frame->ex = child_frame.ex;
1936 goto handle_exception;;
1939 /* need to handle typedbyref ... */
1944 MINT_IN_CASE(MINT_VCALL) {
1947 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
1951 child_frame.retval = sp;
1952 /* decrement by the actual number of args */
1953 sp -= child_frame.runtime_method->param_count;
1954 if (child_frame.runtime_method->hasthis) {
1956 MonoObject *this_arg = sp->data.p;
1958 THROW_EX (mono_get_exception_null_reference(), ip - 2);
1960 child_frame.stack_args = sp;
1962 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
1963 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
1964 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1967 ves_exec_method_with_context (&child_frame, context);
1969 context->current_frame = frame;
1971 if (child_frame.ex) {
1973 * An exception occurred, need to run finally, fault and catch handlers..
1975 frame->ex = child_frame.ex;
1976 goto handle_finally;
1980 MINT_IN_CASE(MINT_CALLVIRT) {
1981 stackval *endsp = sp;
1982 MonoObject *this_arg;
1987 token = * (unsigned short *)(ip + 1);
1989 child_frame.runtime_method = rtm->data_items [token];
1991 child_frame.retval = sp;
1993 /* decrement by the actual number of args */
1994 sp -= child_frame.runtime_method->param_count + 1;
1995 child_frame.stack_args = sp;
1996 this_arg = sp->data.p;
1998 THROW_EX (mono_get_exception_null_reference(), ip - 2);
1999 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2001 MonoClass *this_class = this_arg->vtable->klass;
2002 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2004 gpointer *unboxed = mono_object_unbox (this_arg);
2005 sp [0].data.p = unboxed;
2008 ves_exec_method_with_context (&child_frame, context);
2010 context->current_frame = frame;
2012 if (child_frame.ex) {
2014 * An exception occurred, need to run finally, fault and catch handlers..
2016 frame->ex = child_frame.ex;
2017 if (context->search_for_handler) {
2018 context->search_for_handler = 0;
2019 goto handle_exception;
2021 goto handle_finally;
2024 /* need to handle typedbyref ... */
2029 MINT_IN_CASE(MINT_VCALLVIRT) {
2030 MonoObject *this_arg;
2035 token = * (unsigned short *)(ip + 1);
2037 child_frame.runtime_method = rtm->data_items [token];
2039 child_frame.retval = sp;
2041 /* decrement by the actual number of args */
2042 sp -= child_frame.runtime_method->param_count + 1;
2043 child_frame.stack_args = sp;
2044 this_arg = sp->data.p;
2046 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2047 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2049 MonoClass *this_class = this_arg->vtable->klass;
2050 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2051 gpointer *unboxed = mono_object_unbox (this_arg);
2052 sp [0].data.p = unboxed;
2055 ves_exec_method_with_context (&child_frame, context);
2057 context->current_frame = frame;
2059 if (child_frame.ex) {
2061 * An exception occurred, need to run finally, fault and catch handlers..
2063 frame->ex = child_frame.ex;
2064 if (context->search_for_handler) {
2065 context->search_for_handler = 0;
2066 goto handle_exception;
2068 goto handle_finally;
2072 MINT_IN_CASE(MINT_CALLRUN)
2073 ves_runtime_method (frame, context);
2076 goto handle_exception;
2079 MINT_IN_CASE(MINT_RET)
2081 *frame->retval = *sp;
2082 if (sp > frame->stack)
2083 g_warning ("ret: more values on stack: %d", sp-frame->stack);
2085 MINT_IN_CASE(MINT_RET_VOID)
2086 if (sp > frame->stack)
2087 g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
2089 MINT_IN_CASE(MINT_RET_VT)
2090 i32 = READ32(ip + 1);
2092 memcpy(frame->retval->data.p, sp->data.p, i32);
2093 if (sp > frame->stack)
2094 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2096 MINT_IN_CASE(MINT_BR_S)
2097 ip += (short) *(ip + 1);
2099 MINT_IN_CASE(MINT_BR)
2100 ip += (gint32) READ32(ip + 1);
2102 #define ZEROP_S(datamem, op) \
2104 if (sp->data.datamem op 0) \
2105 ip += * (gint16 *)(ip + 1); \
2109 #define ZEROP(datamem, op) \
2111 if (sp->data.datamem op 0) \
2112 ip += READ32(ip + 1); \
2116 MINT_IN_CASE(MINT_BRFALSE_I4_S)
2119 MINT_IN_CASE(MINT_BRFALSE_I8_S)
2122 MINT_IN_CASE(MINT_BRFALSE_R8_S)
2125 MINT_IN_CASE(MINT_BRFALSE_I4)
2128 MINT_IN_CASE(MINT_BRFALSE_I8)
2131 MINT_IN_CASE(MINT_BRFALSE_R8)
2134 MINT_IN_CASE(MINT_BRTRUE_I4_S)
2137 MINT_IN_CASE(MINT_BRTRUE_I8_S)
2140 MINT_IN_CASE(MINT_BRTRUE_R8_S)
2143 MINT_IN_CASE(MINT_BRTRUE_I4)
2146 MINT_IN_CASE(MINT_BRTRUE_I8)
2149 MINT_IN_CASE(MINT_BRTRUE_R8)
2152 #define CONDBR_S(cond) \
2155 ip += * (gint16 *)(ip + 1); \
2158 #define BRELOP_S(datamem, op) \
2159 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2161 #define CONDBR(cond) \
2164 ip += READ32(ip + 1); \
2168 #define BRELOP(datamem, op) \
2169 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2171 MINT_IN_CASE(MINT_BEQ_I4_S)
2174 MINT_IN_CASE(MINT_BEQ_I8_S)
2177 MINT_IN_CASE(MINT_BEQ_R8_S)
2178 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2180 MINT_IN_CASE(MINT_BEQ_I4)
2183 MINT_IN_CASE(MINT_BEQ_I8)
2186 MINT_IN_CASE(MINT_BEQ_R8)
2187 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2189 MINT_IN_CASE(MINT_BGE_I4_S)
2192 MINT_IN_CASE(MINT_BGE_I8_S)
2195 MINT_IN_CASE(MINT_BGE_R8_S)
2196 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2198 MINT_IN_CASE(MINT_BGE_I4)
2201 MINT_IN_CASE(MINT_BGE_I8)
2204 MINT_IN_CASE(MINT_BGE_R8)
2205 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2207 MINT_IN_CASE(MINT_BGT_I4_S)
2210 MINT_IN_CASE(MINT_BGT_I8_S)
2213 MINT_IN_CASE(MINT_BGT_R8_S)
2214 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2216 MINT_IN_CASE(MINT_BGT_I4)
2219 MINT_IN_CASE(MINT_BGT_I8)
2222 MINT_IN_CASE(MINT_BGT_R8)
2223 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2225 MINT_IN_CASE(MINT_BLT_I4_S)
2228 MINT_IN_CASE(MINT_BLT_I8_S)
2231 MINT_IN_CASE(MINT_BLT_R8_S)
2232 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2234 MINT_IN_CASE(MINT_BLT_I4)
2237 MINT_IN_CASE(MINT_BLT_I8)
2240 MINT_IN_CASE(MINT_BLT_R8)
2241 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2243 MINT_IN_CASE(MINT_BLE_I4_S)
2246 MINT_IN_CASE(MINT_BLE_I8_S)
2249 MINT_IN_CASE(MINT_BLE_R8_S)
2250 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2252 MINT_IN_CASE(MINT_BLE_I4)
2255 MINT_IN_CASE(MINT_BLE_I8)
2258 MINT_IN_CASE(MINT_BLE_R8)
2259 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2261 MINT_IN_CASE(MINT_BNE_UN_I4_S)
2264 MINT_IN_CASE(MINT_BNE_UN_I8_S)
2267 MINT_IN_CASE(MINT_BNE_UN_R8_S)
2268 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2270 MINT_IN_CASE(MINT_BNE_UN_I4)
2273 MINT_IN_CASE(MINT_BNE_UN_I8)
2276 MINT_IN_CASE(MINT_BNE_UN_R8)
2277 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2280 #define BRELOP_S_CAST(datamem, op, type) \
2282 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2283 ip += * (gint16 *)(ip + 1); \
2287 #define BRELOP_CAST(datamem, op, type) \
2289 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2290 ip += READ32(ip + 1); \
2294 MINT_IN_CASE(MINT_BGE_UN_I4_S)
2295 BRELOP_S_CAST(i, >=, guint32);
2297 MINT_IN_CASE(MINT_BGE_UN_I8_S)
2298 BRELOP_S_CAST(l, >=, guint64);
2300 MINT_IN_CASE(MINT_BGE_UN_R8_S)
2301 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
2303 MINT_IN_CASE(MINT_BGE_UN_I4)
2304 BRELOP_CAST(i, >=, guint32);
2306 MINT_IN_CASE(MINT_BGE_UN_I8)
2307 BRELOP_CAST(l, >=, guint64);
2309 MINT_IN_CASE(MINT_BGE_UN_R8)
2310 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
2312 MINT_IN_CASE(MINT_BGT_UN_I4_S)
2313 BRELOP_S_CAST(i, >, guint32);
2315 MINT_IN_CASE(MINT_BGT_UN_I8_S)
2316 BRELOP_S_CAST(l, >, guint64);
2318 MINT_IN_CASE(MINT_BGT_UN_R8_S)
2319 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
2321 MINT_IN_CASE(MINT_BGT_UN_I4)
2322 BRELOP_CAST(i, >, guint32);
2324 MINT_IN_CASE(MINT_BGT_UN_I8)
2325 BRELOP_CAST(l, >, guint64);
2327 MINT_IN_CASE(MINT_BGT_UN_R8)
2328 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
2330 MINT_IN_CASE(MINT_BLE_UN_I4_S)
2331 BRELOP_S_CAST(i, <=, guint32);
2333 MINT_IN_CASE(MINT_BLE_UN_I8_S)
2334 BRELOP_S_CAST(l, <=, guint64);
2336 MINT_IN_CASE(MINT_BLE_UN_R8_S)
2337 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
2339 MINT_IN_CASE(MINT_BLE_UN_I4)
2340 BRELOP_CAST(i, <=, guint32);
2342 MINT_IN_CASE(MINT_BLE_UN_I8)
2343 BRELOP_CAST(l, <=, guint64);
2345 MINT_IN_CASE(MINT_BLE_UN_R8)
2346 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
2348 MINT_IN_CASE(MINT_BLT_UN_I4_S)
2349 BRELOP_S_CAST(i, <, guint32);
2351 MINT_IN_CASE(MINT_BLT_UN_I8_S)
2352 BRELOP_S_CAST(l, <, guint64);
2354 MINT_IN_CASE(MINT_BLT_UN_R8_S)
2355 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
2357 MINT_IN_CASE(MINT_BLT_UN_I4)
2358 BRELOP_CAST(i, <, guint32);
2360 MINT_IN_CASE(MINT_BLT_UN_I8)
2361 BRELOP_CAST(l, <, guint64);
2363 MINT_IN_CASE(MINT_BLT_UN_R8)
2364 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
2366 MINT_IN_CASE(MINT_SWITCH) {
2368 const unsigned short *st;
2374 if ((guint32)sp->data.i < n) {
2376 ip += 2 * (guint32)sp->data.i;
2377 offset = READ32 (ip);
2384 MINT_IN_CASE(MINT_LDIND_I1)
2386 sp[-1].data.i = *(gint8*)sp[-1].data.p;
2388 MINT_IN_CASE(MINT_LDIND_U1)
2390 sp[-1].data.i = *(guint8*)sp[-1].data.p;
2392 MINT_IN_CASE(MINT_LDIND_I2)
2394 sp[-1].data.i = *(gint16*)sp[-1].data.p;
2396 MINT_IN_CASE(MINT_LDIND_U2)
2398 sp[-1].data.i = *(guint16*)sp[-1].data.p;
2400 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
2401 MINT_IN_CASE(MINT_LDIND_U4)
2403 sp[-1].data.i = *(gint32*)sp[-1].data.p;
2405 MINT_IN_CASE(MINT_LDIND_I8)
2407 sp[-1].data.l = *(gint64*)sp[-1].data.p;
2409 MINT_IN_CASE(MINT_LDIND_I) {
2410 guint16 offset = * (guint16 *)(ip + 1);
2411 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
2415 MINT_IN_CASE(MINT_LDIND_R4)
2417 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
2419 MINT_IN_CASE(MINT_LDIND_R8)
2421 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
2423 MINT_IN_CASE(MINT_LDIND_REF)
2425 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
2427 MINT_IN_CASE(MINT_STIND_REF)
2430 * (gpointer *) sp->data.p = sp[1].data.p;
2432 MINT_IN_CASE(MINT_STIND_I1)
2435 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
2437 MINT_IN_CASE(MINT_STIND_I2)
2440 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
2442 MINT_IN_CASE(MINT_STIND_I4)
2445 * (gint32 *) sp->data.p = sp[1].data.i;
2447 MINT_IN_CASE(MINT_STIND_I)
2450 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
2452 MINT_IN_CASE(MINT_STIND_I8)
2455 * (gint64 *) sp->data.p = sp[1].data.l;
2457 MINT_IN_CASE(MINT_STIND_R4)
2460 * (float *) sp->data.p = (gfloat)sp[1].data.f;
2462 MINT_IN_CASE(MINT_STIND_R8)
2465 * (double *) sp->data.p = sp[1].data.f;
2467 #define BINOP(datamem, op) \
2469 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
2471 MINT_IN_CASE(MINT_ADD_I4)
2474 MINT_IN_CASE(MINT_ADD_I8)
2477 MINT_IN_CASE(MINT_ADD_R8)
2480 MINT_IN_CASE(MINT_ADD1_I4)
2484 MINT_IN_CASE(MINT_SUB_I4)
2487 MINT_IN_CASE(MINT_SUB_I8)
2490 MINT_IN_CASE(MINT_SUB_R8)
2493 MINT_IN_CASE(MINT_SUB1_I4)
2497 MINT_IN_CASE(MINT_MUL_I4)
2500 MINT_IN_CASE(MINT_MUL_I8)
2503 MINT_IN_CASE(MINT_MUL_R8)
2506 MINT_IN_CASE(MINT_DIV_I4)
2507 if (sp [-1].data.i == 0)
2508 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2509 if (sp [-1].data.i == (-1))
2510 THROW_EX (mono_get_exception_overflow (), ip);
2513 MINT_IN_CASE(MINT_DIV_I8)
2514 if (sp [-1].data.l == 0)
2515 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2516 if (sp [-1].data.l == (-1))
2517 THROW_EX (mono_get_exception_overflow (), ip);
2520 MINT_IN_CASE(MINT_DIV_R8)
2524 #define BINOP_CAST(datamem, op, type) \
2526 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
2528 MINT_IN_CASE(MINT_DIV_UN_I4)
2529 if (sp [-1].data.i == 0)
2530 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2531 BINOP_CAST(i, /, guint32);
2533 MINT_IN_CASE(MINT_DIV_UN_I8)
2534 if (sp [-1].data.l == 0)
2535 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2536 BINOP_CAST(l, /, guint64);
2538 MINT_IN_CASE(MINT_REM_I4)
2539 if (sp [-1].data.i == 0)
2540 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2541 if (sp [-1].data.i == (-1))
2542 THROW_EX (mono_get_exception_overflow (), ip);
2545 MINT_IN_CASE(MINT_REM_I8)
2546 if (sp [-1].data.l == 0)
2547 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2548 if (sp [-1].data.l == (-1))
2549 THROW_EX (mono_get_exception_overflow (), ip);
2552 MINT_IN_CASE(MINT_REM_R8)
2553 /* FIXME: what do we actually do here? */
2555 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
2558 MINT_IN_CASE(MINT_REM_UN_I4)
2559 if (sp [-1].data.i == 0)
2560 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2561 BINOP_CAST(i, %, guint32);
2563 MINT_IN_CASE(MINT_REM_UN_I8)
2564 if (sp [-1].data.l == 0)
2565 THROW_EX (mono_get_exception_divide_by_zero (), ip);
2566 BINOP_CAST(l, %, guint64);
2568 MINT_IN_CASE(MINT_AND_I4)
2571 MINT_IN_CASE(MINT_AND_I8)
2574 MINT_IN_CASE(MINT_OR_I4)
2577 MINT_IN_CASE(MINT_OR_I8)
2580 MINT_IN_CASE(MINT_XOR_I4)
2583 MINT_IN_CASE(MINT_XOR_I8)
2587 #define SHIFTOP(datamem, op) \
2589 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
2592 MINT_IN_CASE(MINT_SHL_I4)
2595 MINT_IN_CASE(MINT_SHL_I8)
2598 MINT_IN_CASE(MINT_SHR_I4)
2601 MINT_IN_CASE(MINT_SHR_I8)
2604 MINT_IN_CASE(MINT_SHR_UN_I4)
2606 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
2609 MINT_IN_CASE(MINT_SHR_UN_I8)
2611 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
2614 MINT_IN_CASE(MINT_NEG_I4)
2615 sp [-1].data.i = - sp [-1].data.i;
2618 MINT_IN_CASE(MINT_NEG_I8)
2619 sp [-1].data.l = - sp [-1].data.l;
2622 MINT_IN_CASE(MINT_NEG_R8)
2623 sp [-1].data.f = - sp [-1].data.f;
2626 MINT_IN_CASE(MINT_NOT_I4)
2627 sp [-1].data.i = ~ sp [-1].data.i;
2630 MINT_IN_CASE(MINT_NOT_I8)
2631 sp [-1].data.l = ~ sp [-1].data.l;
2634 MINT_IN_CASE(MINT_CONV_I1_I4)
2635 sp [-1].data.i = (gint8)sp [-1].data.i;
2638 MINT_IN_CASE(MINT_CONV_I1_I8)
2639 sp [-1].data.i = (gint8)sp [-1].data.l;
2642 MINT_IN_CASE(MINT_CONV_I1_R8)
2643 sp [-1].data.i = (gint8)sp [-1].data.f;
2646 MINT_IN_CASE(MINT_CONV_U1_I4)
2647 sp [-1].data.i = (guint8)sp [-1].data.i;
2650 MINT_IN_CASE(MINT_CONV_U1_I8)
2651 sp [-1].data.i = (guint8)sp [-1].data.l;
2654 MINT_IN_CASE(MINT_CONV_U1_R8)
2655 sp [-1].data.i = (guint8)sp [-1].data.f;
2658 MINT_IN_CASE(MINT_CONV_I2_I4)
2659 sp [-1].data.i = (gint16)sp [-1].data.i;
2662 MINT_IN_CASE(MINT_CONV_I2_I8)
2663 sp [-1].data.i = (gint16)sp [-1].data.l;
2666 MINT_IN_CASE(MINT_CONV_I2_R8)
2667 sp [-1].data.i = (gint16)sp [-1].data.f;
2670 MINT_IN_CASE(MINT_CONV_U2_I4)
2671 sp [-1].data.i = (guint16)sp [-1].data.i;
2674 MINT_IN_CASE(MINT_CONV_U2_I8)
2675 sp [-1].data.i = (guint16)sp [-1].data.l;
2678 MINT_IN_CASE(MINT_CONV_U2_R8)
2679 sp [-1].data.i = (guint16)sp [-1].data.f;
2682 MINT_IN_CASE(MINT_CONV_I4_R8)
2683 sp [-1].data.i = (gint32)sp [-1].data.f;
2686 MINT_IN_CASE(MINT_CONV_U4_I8)
2687 MINT_IN_CASE(MINT_CONV_I4_I8)
2688 sp [-1].data.i = (gint32)sp [-1].data.l;
2691 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
2692 sp [-2].data.i = (gint32)sp [-2].data.l;
2695 MINT_IN_CASE(MINT_CONV_U4_R8)
2696 sp [-1].data.i = (guint32)sp [-1].data.f;
2699 MINT_IN_CASE(MINT_CONV_I8_I4)
2700 sp [-1].data.l = sp [-1].data.i;
2703 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
2704 sp [-2].data.l = sp [-2].data.i;
2707 MINT_IN_CASE(MINT_CONV_I8_U4)
2708 sp [-1].data.l = (guint32)sp [-1].data.i;
2711 MINT_IN_CASE(MINT_CONV_I8_R8)
2712 sp [-1].data.l = (gint64)sp [-1].data.f;
2715 MINT_IN_CASE(MINT_CONV_R4_I4)
2716 sp [-1].data.f = (float)sp [-1].data.i;
2719 MINT_IN_CASE(MINT_CONV_R4_I8)
2720 sp [-1].data.f = (float)sp [-1].data.l;
2723 MINT_IN_CASE(MINT_CONV_R4_R8)
2724 sp [-1].data.f = (float)sp [-1].data.f;
2727 MINT_IN_CASE(MINT_CONV_R8_I4)
2728 sp [-1].data.f = (double)sp [-1].data.i;
2731 MINT_IN_CASE(MINT_CONV_R8_I8)
2732 sp [-1].data.f = (double)sp [-1].data.l;
2735 MINT_IN_CASE(MINT_CONV_U8_I4)
2736 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
2739 MINT_IN_CASE(MINT_CONV_U8_R8)
2740 sp [-1].data.l = (guint64)sp [-1].data.f;
2743 MINT_IN_CASE(MINT_CPOBJ) {
2744 c = rtm->data_items[* (guint16 *)(ip + 1)];
2745 g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
2746 stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
2751 MINT_IN_CASE(MINT_LDOBJ) {
2753 c = rtm->data_items[* (guint16 *)(ip + 1)];
2756 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
2757 int size = mono_class_value_size (c, NULL);
2758 sp [-1].data.p = vt_sp;
2759 vt_sp += (size + 7) & ~7;
2761 stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
2764 MINT_IN_CASE(MINT_LDSTR)
2765 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
2769 MINT_IN_CASE(MINT_NEWOBJ) {
2770 MonoClass *newobj_class;
2771 MonoMethodSignature *csig;
2772 stackval valuetype_this;
2778 token = * (guint16 *)(ip + 1);
2781 child_frame.ip = NULL;
2782 child_frame.ex = NULL;
2784 child_frame.runtime_method = rtm->data_items [token];
2785 csig = mono_method_signature (child_frame.runtime_method->method);
2786 newobj_class = child_frame.runtime_method->method->klass;
2787 /*if (profiling_classes) {
2788 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
2790 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
2793 if (newobj_class->parent == mono_defaults.array_class) {
2794 sp -= csig->param_count;
2795 child_frame.stack_args = sp;
2796 o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
2798 THROW_EX (child_frame.ex, ip);
2799 goto array_constructed;
2802 g_assert (csig->hasthis);
2803 if (csig->param_count) {
2804 sp -= csig->param_count;
2805 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
2807 child_frame.stack_args = sp;
2810 * First arg is the object.
2812 if (newobj_class->valuetype) {
2813 MonoType *t = &newobj_class->byval_arg;
2814 memset (&valuetype_this, 0, sizeof (stackval));
2815 if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
2817 valuetype_this.data.p = vt_sp;
2819 sp->data.p = &valuetype_this;
2822 if (newobj_class != mono_defaults.string_class) {
2823 context->managed_code = 0;
2824 o = mono_object_new_checked (context->domain, newobj_class, &error);
2825 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2826 context->managed_code = 1;
2827 if (*mono_thread_interruption_request_flag ())
2828 mono_thread_interruption_checkpoint ();
2832 child_frame.retval = &retval;
2836 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
2838 ves_exec_method_with_context (&child_frame, context);
2840 context->current_frame = frame;
2842 if (child_frame.ex) {
2844 * An exception occurred, need to run finally, fault and catch handlers..
2846 frame->ex = child_frame.ex;
2847 goto handle_finally;
2850 * a constructor returns void, but we need to return the object we created
2853 if (newobj_class->valuetype && !newobj_class->enumtype) {
2854 *sp = valuetype_this;
2855 } else if (newobj_class == mono_defaults.string_class) {
2863 MINT_IN_CASE(MINT_CASTCLASS)
2864 c = rtm->data_items [*(guint16 *)(ip + 1)];
2865 if ((o = sp [-1].data.p)) {
2866 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
2867 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2869 THROW_EX (mono_get_exception_invalid_cast (), ip);
2873 MINT_IN_CASE(MINT_ISINST)
2874 c = rtm->data_items [*(guint16 *)(ip + 1)];
2875 if ((o = sp [-1].data.p)) {
2876 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
2877 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2879 sp [-1].data.p = NULL;
2883 MINT_IN_CASE(MINT_CONV_R_UN_I4)
2884 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
2887 MINT_IN_CASE(MINT_CONV_R_UN_I8)
2888 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
2891 MINT_IN_CASE(MINT_UNBOX)
2892 c = rtm->data_items[*(guint16 *)(ip + 1)];
2896 THROW_EX (mono_get_exception_null_reference (), ip);
2898 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
2899 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2900 if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
2901 THROW_EX (mono_get_exception_invalid_cast (), ip);
2903 sp [-1].data.p = mono_object_unbox (o);
2906 MINT_IN_CASE(MINT_THROW)
2908 frame->ex_handler = NULL;
2910 sp->data.p = mono_get_exception_null_reference ();
2911 THROW_EX ((MonoException *)sp->data.p, ip);
2913 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
2915 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
2918 MINT_IN_CASE(MINT_LDFLDA)
2921 THROW_EX (mono_get_exception_null_reference (), ip);
2922 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
2925 MINT_IN_CASE(MINT_CKNULL)
2928 THROW_EX (mono_get_exception_null_reference (), ip);
2932 #define LDFLD(datamem, fieldtype) \
2933 o = sp [-1].data.p; \
2935 THROW_EX (mono_get_exception_null_reference (), ip); \
2936 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
2939 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
2940 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
2941 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
2942 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
2943 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
2944 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
2945 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
2946 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
2947 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
2948 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
2950 MINT_IN_CASE(MINT_LDFLD_VT)
2953 THROW_EX (mono_get_exception_null_reference (), ip);
2954 i32 = READ32(ip + 2);
2955 sp [-1].data.p = vt_sp;
2956 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
2957 vt_sp += (i32 + 7) & ~7;
2961 MINT_IN_CASE(MINT_LDRMFLD) {
2963 MonoClassField *field;
2968 THROW_EX (mono_get_exception_null_reference (), ip);
2969 field = rtm->data_items[* (guint16 *)(ip + 1)];
2971 if (mono_object_is_transparent_proxy (o)) {
2972 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2974 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
2975 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2977 addr = (char*)o + field->offset;
2980 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2984 MINT_IN_CASE(MINT_LDRMFLD_VT) {
2985 MonoClassField *field;
2991 THROW_EX (mono_get_exception_null_reference (), ip);
2992 field = rtm->data_items[* (guint16 *)(ip + 1)];
2993 i32 = READ32(ip + 2);
2995 if (mono_object_is_transparent_proxy (o)) {
2996 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2997 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
2998 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3000 addr = (char*)o + field->offset;
3003 sp [-1].data.p = vt_sp;
3004 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3005 vt_sp += (i32 + 7) & ~7;
3006 memcpy(sp [-1].data.p, addr, i32);
3010 #define STFLD(datamem, fieldtype) \
3011 o = sp [-2].data.p; \
3013 THROW_EX (mono_get_exception_null_reference (), ip); \
3015 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3018 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3019 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3020 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3021 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3022 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3023 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3024 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3025 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3026 MINT_IN_CASE(MINT_STFLD_O) STFLD(p, gpointer); MINT_IN_BREAK;
3027 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3029 MINT_IN_CASE(MINT_STFLD_VT)
3032 THROW_EX (mono_get_exception_null_reference (), ip);
3033 i32 = READ32(ip + 2);
3035 memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32);
3036 vt_sp -= (i32 + 7) & ~7;
3040 MINT_IN_CASE(MINT_STRMFLD) {
3041 MonoClassField *field;
3045 THROW_EX (mono_get_exception_null_reference (), ip);
3047 field = rtm->data_items[* (guint16 *)(ip + 1)];
3050 if (mono_object_is_transparent_proxy (o)) {
3051 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3052 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3053 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3055 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3060 MINT_IN_CASE(MINT_STRMFLD_VT) {
3061 MonoClassField *field;
3065 THROW_EX (mono_get_exception_null_reference (), ip);
3066 field = rtm->data_items[* (guint16 *)(ip + 1)];
3067 i32 = READ32(ip + 2);
3070 if (mono_object_is_transparent_proxy (o)) {
3071 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3072 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3073 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3075 memcpy((char*)o + field->offset, sp [-1].data.p, i32);
3078 vt_sp -= (i32 + 7) & ~7;
3081 MINT_IN_CASE(MINT_LDSFLDA) {
3082 MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3083 sp->data.p = mono_class_static_field_address (context->domain, field);
3088 MINT_IN_CASE(MINT_LDSFLD) {
3089 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3090 gpointer addr = mono_class_static_field_address (context->domain, field);
3091 stackval_from_data (field->type, sp, addr, FALSE);
3096 MINT_IN_CASE(MINT_LDSFLD_VT) {
3097 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3098 gpointer addr = mono_class_static_field_address (context->domain, field);
3099 int size = READ32 (ip + 2);
3103 vt_sp += (size + 7) & ~7;
3104 stackval_from_data (field->type, sp, addr, FALSE);
3108 MINT_IN_CASE(MINT_STSFLD) {
3109 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3110 gpointer addr = mono_class_static_field_address (context->domain, field);
3113 stackval_to_data (field->type, sp, addr, FALSE);
3116 MINT_IN_CASE(MINT_STSFLD_VT) {
3117 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3118 gpointer addr = mono_class_static_field_address (context->domain, field);
3119 int size = READ32 (ip + 2);
3123 stackval_to_data (field->type, sp, addr, FALSE);
3124 vt_sp -= (size + 7) & ~7;
3127 MINT_IN_CASE(MINT_STOBJ_VT) {
3129 c = rtm->data_items[* (guint16 *)(ip + 1)];
3131 size = mono_class_value_size (c, NULL);
3132 memcpy(sp [-2].data.p, sp [-1].data.p, size);
3133 vt_sp -= (size + 7) & ~7;
3137 MINT_IN_CASE(MINT_STOBJ) {
3139 c = rtm->data_items[* (guint16 *)(ip + 1)];
3141 size = mono_class_value_size (c, NULL);
3142 memcpy(sp [-2].data.p, &sp [-1].data, size);
3146 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3147 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3148 THROW_EX (mono_get_exception_overflow (), ip);
3149 sp [-1].data.i = (guint32)sp [-1].data.f;
3152 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3153 if (sp [-1].data.i < 0)
3154 THROW_EX (mono_get_exception_overflow (), ip);
3155 sp [-1].data.l = sp [-1].data.i;
3158 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
3159 if (sp [-1].data.l < 0)
3160 THROW_EX (mono_get_exception_overflow (), ip);
3163 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
3164 if ((guint64) sp [-1].data.l > MYGINT64_MAX)
3165 THROW_EX (mono_get_exception_overflow (), ip);
3168 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
3169 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
3170 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
3171 THROW_EX (mono_get_exception_overflow (), ip);
3172 sp [-1].data.l = (guint64)sp [-1].data.f;
3175 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
3176 if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
3177 THROW_EX (mono_get_exception_overflow (), ip);
3178 sp [-1].data.l = (gint64)sp [-1].data.f;
3181 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
3182 if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
3183 THROW_EX (mono_get_exception_overflow (), ip);
3184 sp [-1].data.i = (mono_u)sp [-1].data.l;
3187 MINT_IN_CASE(MINT_BOX) {
3188 c = rtm->data_items [* (guint16 *)(ip + 1)];
3189 guint16 offset = * (guint16 *)(ip + 2);
3191 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
3192 int size = mono_class_value_size (c, NULL);
3193 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error);
3194 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3195 size = (size + 7) & ~7;
3198 stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
3199 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error);
3200 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3205 MINT_IN_CASE(MINT_NEWARR)
3206 sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
3207 if (!mono_error_ok (&error)) {
3208 THROW_EX (mono_error_convert_to_exception (&error), ip);
3210 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3212 /*if (profiling_classes) {
3213 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3215 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3219 MINT_IN_CASE(MINT_LDLEN)
3222 THROW_EX (mono_get_exception_null_reference (), ip);
3223 sp [-1].data.nati = mono_array_length ((MonoArray *)o);
3226 MINT_IN_CASE(MINT_GETCHR) {
3230 THROW_EX (mono_get_exception_null_reference (), ip);
3231 i32 = sp [-1].data.i;
3232 if (i32 < 0 || i32 >= mono_string_length (s))
3233 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3235 sp [-1].data.i = mono_string_chars(s)[i32];
3239 MINT_IN_CASE(MINT_STRLEN)
3241 sp [-1].data.i = mono_string_length ((MonoString*)sp [-1].data.p);
3243 MINT_IN_CASE(MINT_ARRAY_RANK)
3246 THROW_EX (mono_get_exception_null_reference (), ip);
3247 sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
3250 MINT_IN_CASE(MINT_LDELEMA)
3251 MINT_IN_CASE(MINT_LDELEMA_TC) {
3252 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
3254 MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
3255 guint16 numargs = *(guint16 *) (ip + 2);
3260 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
3262 THROW_EX (frame->ex, ip);
3267 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
3268 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
3269 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
3270 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
3271 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
3272 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
3273 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
3274 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
3275 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
3276 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
3277 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
3278 MINT_IN_CASE(MINT_LDELEM_VT) {
3286 THROW_EX (mono_get_exception_null_reference (), ip);
3288 aindex = sp [1].data.i;
3289 if (aindex >= mono_array_length (o))
3290 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3293 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
3296 case MINT_LDELEM_I1:
3297 sp [0].data.i = mono_array_get (o, gint8, aindex);
3299 case MINT_LDELEM_U1:
3300 sp [0].data.i = mono_array_get (o, guint8, aindex);
3302 case MINT_LDELEM_I2:
3303 sp [0].data.i = mono_array_get (o, gint16, aindex);
3305 case MINT_LDELEM_U2:
3306 sp [0].data.i = mono_array_get (o, guint16, aindex);
3309 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
3311 case MINT_LDELEM_I4:
3312 sp [0].data.i = mono_array_get (o, gint32, aindex);
3314 case MINT_LDELEM_U4:
3315 sp [0].data.i = mono_array_get (o, guint32, aindex);
3317 case MINT_LDELEM_I8:
3318 sp [0].data.l = mono_array_get (o, guint64, aindex);
3320 case MINT_LDELEM_R4:
3321 sp [0].data.f = mono_array_get (o, float, aindex);
3323 case MINT_LDELEM_R8:
3324 sp [0].data.f = mono_array_get (o, double, aindex);
3326 case MINT_LDELEM_REF:
3327 sp [0].data.p = mono_array_get (o, gpointer, aindex);
3329 case MINT_LDELEM_VT: {
3330 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
3331 i32 = READ32 (ip + 2);
3332 char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
3333 sp [0].data.vt = vt_sp;
3334 stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
3335 vt_sp += (i32 + 7) & ~7;
3347 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
3348 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
3349 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
3350 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
3351 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
3352 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
3353 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
3354 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
3355 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
3356 MINT_IN_CASE(MINT_STELEM_VT) {
3363 THROW_EX (mono_get_exception_null_reference (), ip);
3365 aindex = sp [1].data.i;
3366 if (aindex >= mono_array_length ((MonoArray *)o))
3367 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3371 mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
3373 case MINT_STELEM_I1:
3374 mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
3376 case MINT_STELEM_U1:
3377 mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
3379 case MINT_STELEM_I2:
3380 mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
3382 case MINT_STELEM_I4:
3383 mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
3385 case MINT_STELEM_I8:
3386 mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
3388 case MINT_STELEM_R4:
3389 mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
3391 case MINT_STELEM_R8:
3392 mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
3394 case MINT_STELEM_REF: {
3395 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error);
3396 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3397 if (sp [2].data.p && !isinst_obj)
3398 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
3399 mono_array_set ((MonoArray *)o, gpointer, aindex, sp [2].data.p);
3402 case MINT_STELEM_VT: {
3403 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
3404 i32 = READ32 (ip + 2);
3405 char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
3407 stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
3408 vt_sp -= (i32 + 7) & ~7;
3419 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
3420 if (sp [-1].data.i < 0)
3421 THROW_EX (mono_get_exception_overflow (), ip);
3424 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
3425 if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
3426 THROW_EX (mono_get_exception_overflow (), ip);
3427 sp [-1].data.i = (gint32) sp [-1].data.l;
3430 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
3431 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
3432 THROW_EX (mono_get_exception_overflow (), ip);
3433 sp [-1].data.i = (gint32) sp [-1].data.l;
3436 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
3437 if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
3438 THROW_EX (mono_get_exception_overflow (), ip);
3439 sp [-1].data.i = (gint32) sp [-1].data.f;
3442 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
3443 if (sp [-1].data.i < 0)
3444 THROW_EX (mono_get_exception_overflow (), ip);
3447 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
3448 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
3449 THROW_EX (mono_get_exception_overflow (), ip);
3450 sp [-1].data.i = (guint32) sp [-1].data.l;
3453 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
3454 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3455 THROW_EX (mono_get_exception_overflow (), ip);
3456 sp [-1].data.i = (guint32) sp [-1].data.f;
3459 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
3460 if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
3461 THROW_EX (mono_get_exception_overflow (), ip);
3464 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
3465 if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
3466 THROW_EX (mono_get_exception_overflow (), ip);
3467 sp [-1].data.i = (gint16) sp [-1].data.l;
3470 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
3471 if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
3472 THROW_EX (mono_get_exception_overflow (), ip);
3473 sp [-1].data.i = (gint16) sp [-1].data.f;
3476 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
3477 if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
3478 THROW_EX (mono_get_exception_overflow (), ip);
3481 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
3482 if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
3483 THROW_EX (mono_get_exception_overflow (), ip);
3484 sp [-1].data.i = (guint16) sp [-1].data.l;
3487 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
3488 if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
3489 THROW_EX (mono_get_exception_overflow (), ip);
3490 sp [-1].data.i = (guint16) sp [-1].data.f;
3493 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
3494 if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
3495 THROW_EX (mono_get_exception_overflow (), ip);
3498 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
3499 if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
3500 THROW_EX (mono_get_exception_overflow (), ip);
3501 sp [-1].data.i = (gint8) sp [-1].data.l;
3504 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
3505 if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
3506 THROW_EX (mono_get_exception_overflow (), ip);
3507 sp [-1].data.i = (gint8) sp [-1].data.f;
3510 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
3511 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
3512 THROW_EX (mono_get_exception_overflow (), ip);
3515 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
3516 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
3517 THROW_EX (mono_get_exception_overflow (), ip);
3518 sp [-1].data.i = (guint8) sp [-1].data.l;
3521 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
3522 if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
3523 THROW_EX (mono_get_exception_overflow (), ip);
3524 sp [-1].data.i = (guint8) sp [-1].data.f;
3528 MINT_IN_CASE(MINT_LDELEM)
3529 MINT_IN_CASE(MINT_STELEM)
3530 MINT_IN_CASE(MINT_UNBOX_ANY)
3532 MINT_IN_CASE(MINT_REFANYVAL) ves_abort(); MINT_IN_BREAK;
3534 MINT_IN_CASE(MINT_CKFINITE)
3535 if (!isfinite(sp [-1].data.f))
3536 THROW_EX (mono_get_exception_arithmetic (), ip);
3540 MINT_IN_CASE(MINT_MKREFANY) ves_abort(); MINT_IN_BREAK;
3542 MINT_IN_CASE(MINT_LDTOKEN)
3545 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
3549 MINT_IN_CASE(MINT_ADD_OVF_I4)
3550 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
3551 THROW_EX (mono_get_exception_overflow (), ip);
3554 MINT_IN_CASE(MINT_ADD_OVF_I8)
3555 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
3556 THROW_EX (mono_get_exception_overflow (), ip);
3559 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
3560 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
3561 THROW_EX (mono_get_exception_overflow (), ip);
3562 BINOP_CAST(i, +, guint32);
3564 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
3565 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
3566 THROW_EX (mono_get_exception_overflow (), ip);
3567 BINOP_CAST(l, +, guint64);
3569 MINT_IN_CASE(MINT_MUL_OVF_I4)
3570 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
3571 THROW_EX (mono_get_exception_overflow (), ip);
3574 MINT_IN_CASE(MINT_MUL_OVF_I8)
3575 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
3576 THROW_EX (mono_get_exception_overflow (), ip);
3579 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
3580 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
3581 THROW_EX (mono_get_exception_overflow (), ip);
3582 BINOP_CAST(i, *, guint32);
3584 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
3585 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
3586 THROW_EX (mono_get_exception_overflow (), ip);
3587 BINOP_CAST(l, *, guint64);
3589 MINT_IN_CASE(MINT_SUB_OVF_I4)
3590 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
3591 THROW_EX (mono_get_exception_overflow (), ip);
3594 MINT_IN_CASE(MINT_SUB_OVF_I8)
3595 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
3596 THROW_EX (mono_get_exception_overflow (), ip);
3599 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
3600 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
3601 THROW_EX (mono_get_exception_overflow (), ip);
3602 BINOP_CAST(i, -, guint32);
3604 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
3605 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
3606 THROW_EX (mono_get_exception_overflow (), ip);
3607 BINOP_CAST(l, -, guint64);
3609 MINT_IN_CASE(MINT_ENDFINALLY)
3611 ip = finally_ips->data;
3612 finally_ips = g_slist_remove (finally_ips, ip);
3619 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
3620 MINT_IN_CASE(MINT_LEAVE_S)
3621 while (sp > frame->stack) {
3625 if (*ip == MINT_LEAVE_S) {
3626 ip += (short) *(ip + 1);
3628 ip += (gint32) READ32 (ip + 1);
3631 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
3632 frame->ex_handler = NULL;
3635 goto handle_finally;
3637 MINT_IN_CASE(MINT_ICALL_V_V)
3638 MINT_IN_CASE(MINT_ICALL_V_P)
3639 MINT_IN_CASE(MINT_ICALL_P_V)
3640 MINT_IN_CASE(MINT_ICALL_P_P)
3641 MINT_IN_CASE(MINT_ICALL_PP_V)
3642 MINT_IN_CASE(MINT_ICALL_PI_V)
3643 MINT_IN_CASE(MINT_ICALL_PP_P)
3644 MINT_IN_CASE(MINT_ICALL_PI_P)
3645 MINT_IN_CASE(MINT_ICALL_PPP_V)
3646 MINT_IN_CASE(MINT_ICALL_PPI_V)
3647 sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
3648 if (frame->ex != NULL)
3649 goto handle_exception;
3652 MINT_IN_CASE(MINT_MONO_LDPTR)
3653 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
3657 MINT_IN_CASE(MINT_MONO_NEWOBJ)
3658 sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
3659 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3663 MINT_IN_CASE(MINT_MONO_FREE)
3666 g_error ("that doesn't seem right");
3667 g_free (sp->data.p);
3669 MINT_IN_CASE(MINT_MONO_RETOBJ)
3672 stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p,
3673 mono_method_signature (frame->runtime_method->method)->pinvoke);
3674 if (sp > frame->stack)
3675 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
3678 #define RELOP(datamem, op) \
3680 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
3682 MINT_IN_CASE(MINT_CEQ_I4)
3685 MINT_IN_CASE(MINT_CEQ0_I4)
3686 sp [-1].data.i = (sp [-1].data.i == 0);
3689 MINT_IN_CASE(MINT_CEQ_I8)
3692 MINT_IN_CASE(MINT_CEQ_R8)
3694 if (isunordered (sp [-1].data.f, sp [0].data.f))
3697 sp [-1].data.i = sp [-1].data.f == sp [0].data.f;
3700 MINT_IN_CASE(MINT_CGT_I4)
3703 MINT_IN_CASE(MINT_CGT_I8)
3706 MINT_IN_CASE(MINT_CGT_R8)
3708 if (isunordered (sp [-1].data.f, sp [0].data.f))
3711 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
3715 #define RELOP_CAST(datamem, op, type) \
3717 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3720 MINT_IN_CASE(MINT_CGT_UN_I4)
3721 RELOP_CAST(i, >, guint32);
3723 MINT_IN_CASE(MINT_CGT_UN_I8)
3724 RELOP_CAST(l, >, guint64);
3726 MINT_IN_CASE(MINT_CGT_UN_R8)
3728 if (isunordered (sp [-1].data.f, sp [0].data.f))
3731 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
3734 MINT_IN_CASE(MINT_CLT_I4)
3737 MINT_IN_CASE(MINT_CLT_I8)
3740 MINT_IN_CASE(MINT_CLT_R8)
3742 if (isunordered (sp [-1].data.f, sp [0].data.f))
3745 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
3748 MINT_IN_CASE(MINT_CLT_UN_I4)
3749 RELOP_CAST(i, <, guint32);
3751 MINT_IN_CASE(MINT_CLT_UN_I8)
3752 RELOP_CAST(l, <, guint64);
3754 MINT_IN_CASE(MINT_CLT_UN_R8)
3756 if (isunordered (sp [-1].data.f, sp [0].data.f))
3759 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
3762 MINT_IN_CASE(MINT_LDFTN) {
3763 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3768 MINT_IN_CASE(MINT_LDVIRTFTN) {
3769 RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
3773 THROW_EX (mono_get_exception_null_reference (), ip - 2);
3775 sp->data.p = get_virtual_method (context->domain, m, sp->data.p);
3780 MINT_IN_CASE(MINT_LDTHISA)
3781 g_error ("should not happen");
3782 // sp->data.p = &frame->obj;
3787 #define LDARG(datamem, argtype) \
3788 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
3792 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
3793 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
3794 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
3795 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
3796 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
3797 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
3798 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
3799 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
3800 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
3801 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
3803 MINT_IN_CASE(MINT_LDARG_VT)
3805 i32 = READ32(ip + 2);
3806 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
3807 vt_sp += (i32 + 7) & ~7;
3812 #define STARG(datamem, argtype) \
3814 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
3817 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
3818 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
3819 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
3820 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
3821 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
3822 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
3823 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
3824 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
3825 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
3826 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
3828 MINT_IN_CASE(MINT_STARG_VT)
3829 i32 = READ32(ip + 2);
3831 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
3832 vt_sp -= (i32 + 7) & ~7;
3836 #define STINARG(datamem, argtype) \
3838 int n = * (guint16 *)(ip + 1); \
3839 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
3843 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
3844 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
3845 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
3846 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
3847 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
3848 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
3849 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
3850 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
3851 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
3852 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
3854 MINT_IN_CASE(MINT_STINARG_VT) {
3855 int n = * (guint16 *)(ip + 1);
3856 i32 = READ32(ip + 2);
3857 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
3862 MINT_IN_CASE(MINT_LDARGA)
3863 sp->data.p = frame->args + * (guint16 *)(ip + 1);
3868 #define LDLOC(datamem, argtype) \
3869 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
3873 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
3874 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
3875 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
3876 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
3877 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
3878 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
3879 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
3880 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
3881 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
3882 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
3884 MINT_IN_CASE(MINT_LDLOC_VT)
3886 i32 = READ32(ip + 2);
3887 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
3888 vt_sp += (i32 + 7) & ~7;
3893 MINT_IN_CASE(MINT_LDLOCA_S)
3894 sp->data.p = locals + * (guint16 *)(ip + 1);
3899 #define STLOC(datamem, argtype) \
3901 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
3904 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
3905 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
3906 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
3907 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
3908 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
3909 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
3910 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
3911 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
3912 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
3913 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
3915 #define STLOC_NP(datamem, argtype) \
3916 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
3919 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
3920 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
3922 MINT_IN_CASE(MINT_STLOC_VT)
3923 i32 = READ32(ip + 2);
3925 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
3926 vt_sp -= (i32 + 7) & ~7;
3930 MINT_IN_CASE(MINT_LOCALLOC) {
3931 if (sp != frame->stack + 1) /*FIX?*/
3932 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
3934 int len = sp [-1].data.i;
3935 sp [-1].data.p = alloca (len);
3936 MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
3937 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3938 if (header->init_locals)
3939 memset (sp [-1].data.p, 0, len);
3944 MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK;
3946 MINT_IN_CASE(MINT_INITOBJ)
3948 memset (sp->data.vt, 0, READ32(ip + 1));
3951 MINT_IN_CASE(MINT_CPBLK)
3953 if (!sp [0].data.p || !sp [1].data.p)
3954 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3956 /* FIXME: value and size may be int64... */
3957 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
3960 MINT_IN_CASE(MINT_CONSTRAINED_) {
3962 /* FIXME: implement */
3964 token = READ32 (ip);
3969 MINT_IN_CASE(MINT_INITBLK)
3972 THROW_EX (mono_get_exception_null_reference(), ip - 1);
3974 /* FIXME: value and size may be int64... */
3975 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
3978 MINT_IN_CASE(MINT_NO_)
3979 /* FIXME: implement */
3983 MINT_IN_CASE(MINT_RETHROW)
3985 * need to clarify what this should actually do:
3986 * start the search from the last found handler in
3987 * this method or continue in the caller or what.
3988 * Also, do we need to run finally/fault handlers after a retrow?
3989 * Well, this implementation will follow the usual search
3990 * for an handler, considering the current ip as throw spot.
3991 * We need to NULL frame->ex_handler for the later code to
3992 * actually run the new found handler.
3994 frame->ex_handler = NULL;
3995 THROW_EX (frame->ex, ip - 1);
3998 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
3999 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
4003 g_assert_not_reached ();
4005 * Exception handling code.
4006 * The exception object is stored in frame->ex.
4013 MonoInvocation *inv;
4014 MonoExceptionClause *clause;
4020 g_print ("* Handling exception '%s' at IL_%04x\n",
4021 frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name,
4022 rtm == NULL ? 0 : frame->ip - rtm->code);
4024 if (die_on_exception)
4027 for (inv = frame; inv; inv = inv->parent) {
4029 if (inv->runtime_method == NULL)
4031 method = inv->runtime_method->method;
4032 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4034 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4036 if (inv->ip == NULL)
4038 ip_offset = inv->ip - inv->runtime_method->code;
4039 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4040 for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
4041 clause = &inv->runtime_method->clauses [i];
4042 if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4043 if (!clause->flags) {
4044 MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
4045 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4048 * OK, we found an handler, now we need to execute the finally
4049 * and fault blocks before branching to the handler code.
4051 inv->ex_handler = clause;
4054 g_print ("* Found handler at '%s'\n", method->name);
4056 goto handle_finally;
4059 g_error ("FIXME: handle filter clause");
4065 * If we get here, no handler was found: print a stack trace.
4067 for (inv = frame; inv; inv = inv->parent) {
4068 if (inv->invoke_trap)
4069 goto handle_finally;
4072 ex_obj = (MonoObject*)frame->ex;
4073 mono_unhandled_exception (ex_obj);
4080 MonoExceptionClause *clause;
4081 GSList *old_list = finally_ips;
4082 MonoMethod *method = frame->runtime_method->method;
4083 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
4084 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4088 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
4090 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4091 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4094 ip_offset = frame->ip - rtm->code;
4096 if (endfinally_ip != NULL)
4097 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4098 for (i = 0; i < header->num_clauses; ++i)
4099 if (frame->ex_handler == &rtm->clauses [i])
4103 clause = &rtm->clauses [i];
4104 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
4105 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4106 ip = rtm->code + clause->handler_offset;
4107 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4110 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4116 endfinally_ip = NULL;
4118 if (old_list != finally_ips && finally_ips) {
4119 ip = finally_ips->data;
4120 finally_ips = g_slist_remove (finally_ips, ip);
4121 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4126 * If an exception is set, we need to execute the fault handler, too,
4127 * otherwise, we continue normally.
4137 MonoExceptionClause *clause;
4138 MonoMethod *method = frame->runtime_method->method;
4139 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
4140 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4144 g_print ("* Handle fault\n");
4146 ip_offset = frame->ip - rtm->code;
4147 for (i = 0; i < header->num_clauses; ++i) {
4148 clause = &rtm->clauses [i];
4149 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4150 ip = rtm->code + clause->handler_offset;
4153 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4159 * If the handler for the exception was found in this method, we jump
4160 * to it right away, otherwise we return and let the caller run
4161 * the finally, fault and catch blocks.
4162 * This same code should be present in the endfault opcode, but it
4163 * is corrently not assigned in the ECMA specs: LAMESPEC.
4165 if (frame->ex_handler) {
4168 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4170 ip = rtm->code + frame->ex_handler->handler_offset;
4172 vt_sp = (unsigned char *) sp + rtm->stack_size;
4173 sp->data.p = frame->ex;
4184 ves_exec_method (MonoInvocation *frame)
4186 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
4187 ThreadContext context_struct;
4194 mono_unhandled_exception ((MonoObject*)frame->ex);
4197 if (context == NULL) {
4198 context = &context_struct;
4199 context_struct.domain = mono_domain_get ();
4200 context_struct.base_frame = frame;
4201 context_struct.current_frame = NULL;
4202 context_struct.env_frame = frame;
4203 context_struct.current_env = &env;
4204 context_struct.search_for_handler = 0;
4205 context_struct.managed_code = 0;
4206 mono_native_tls_set_value (thread_context_id, context);
4209 frame->parent = context->current_frame;
4210 frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
4211 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4212 context->managed_code = 1;
4213 ves_exec_method_with_context (frame, context);
4214 context->managed_code = 0;
4216 if (context != &context_struct && context->current_env) {
4217 context->env_frame->ex = frame->ex;
4218 longjmp (*context->current_env, 1);
4221 mono_unhandled_exception ((MonoObject*)frame->ex);
4223 if (context->base_frame == frame)
4224 mono_native_tls_set_value (thread_context_id, NULL);
4226 context->current_frame = frame->parent;
4230 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
4232 MonoImage *image = mono_assembly_get_image (assembly);
4237 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
4238 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4241 g_error ("No entry point method found in %s", mono_image_get_filename (image));
4243 rval = mono_runtime_run_main_checked (method, argc, argv, &error);
4244 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4252 "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
4253 "Usage is: mint [options] executable args...\n\n", VERSION);
4255 "Runtime Debugging:\n"
4260 " --noptr\t\t\tdon't print pointer addresses in trace output\n"
4263 " --traceclassinit\n"
4266 " --debug method_name\n"
4273 " --config filename load the specified config file instead of the default\n"
4274 " --workers n maximum number of worker threads\n"
4280 interp_ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
4281 MonoReflectionMethod **method,
4282 gint32 *iloffset, gint32 *native_offset,
4283 MonoString **file, gint32 *line, gint32 *column)
4285 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
4286 MonoInvocation *inv = context->current_frame;
4290 for (i = 0; inv && i < skip; inv = inv->parent)
4291 if (inv->runtime_method != NULL)
4302 *method = mono_method_get_object_checked (context->domain, inv->runtime_method->method, NULL, &error);
4303 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4308 if (need_file_info) {
4312 *file = mono_string_new (mono_domain_get (), "unknown");
4319 interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
4321 MonoDomain *domain = mono_domain_get ();
4323 MonoArray *ta = exc->trace_ips;
4328 /* Exception is not thrown yet */
4329 MonoArray *array = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, &error);
4330 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4334 len = mono_array_length (ta);
4336 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error);
4337 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4339 for (i = skip; i < len / 2; i++) {
4340 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
4341 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4342 gushort *ip = mono_array_get (ta, gpointer, 2 * i + 1);
4343 RuntimeMethod *rtm = mono_array_get (ta, gpointer, 2 * i);
4346 sf->method = mono_method_get_object_checked (domain, rtm->method, NULL, &error);
4347 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4348 sf->native_offset = ip - rtm->code;
4352 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
4354 if (need_file_info) {
4357 filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
4359 sf->filename = filename? mono_string_new (domain, filename): NULL;
4366 mono_array_set (res, gpointer, i, sf);
4375 mono_native_tls_alloc (&thread_context_id, NULL);
4376 mono_native_tls_set_value (thread_context_id, NULL);
4377 mono_os_mutex_init_recursive (&create_method_pointer_mutex);
4379 mono_interp_transform_init ();
4382 typedef int (*TestMethod) (void);
4385 interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain)
4387 int result, expected, failed, cfailed, run;
4388 double elapsed, transform_time;
4390 MonoObject *result_obj;
4391 static gboolean filter_method_init = FALSE;
4392 static const char *filter_method = NULL;
4394 g_print ("Test run: image=%s\n", mono_image_get_filename (image));
4395 cfailed = failed = run = 0;
4396 transform_time = elapsed = 0.0;
4398 g_timer_start (timer);
4399 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4400 MonoObject *exc = NULL;
4402 MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4404 mono_error_cleanup (&error); /* FIXME don't swallow the error */
4408 if (!filter_method_init) {
4409 filter_method = g_getenv ("INTERP_FILTER_METHOD");
4410 filter_method_init = TRUE;
4412 gboolean filter = FALSE;
4413 if (filter_method) {
4414 const char *name = filter_method;
4416 if ((strchr (name, '.') > name) || strchr (name, ':')) {
4417 MonoMethodDesc *desc = mono_method_desc_new (name, TRUE);
4418 filter = mono_method_desc_full_match (desc, method);
4419 mono_method_desc_free (desc);
4421 filter = strcmp (method->name, name) == 0;
4423 } else { /* no filter, check for `Category' attribute on method */
4425 MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error);
4426 mono_error_cleanup (&error);
4430 for (j = 0; j < ainfo->num_attrs && filter; ++j) {
4431 MonoCustomAttrEntry *centry = &ainfo->attrs [j];
4432 if (centry->ctor == NULL)
4435 MonoClass *klass = centry->ctor->klass;
4436 if (strcmp (klass->name, "CategoryAttribute"))
4439 MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error);
4440 /* FIXME: there is an ordering problem if there're multiple attributes, do this instead:
4441 * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */
4442 mono_error_cleanup (&error);
4443 MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1);
4444 MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error);
4445 mono_error_cleanup (&error);
4446 char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error);
4447 mono_error_cleanup (&error);
4448 if (!strcmp (utf8_str, "!INTERPRETER")) {
4449 g_print ("skip %s...\n", method->name);
4455 if (strncmp (method->name, "test_", 5) == 0 && filter) {
4456 MonoError interp_error;
4457 MonoObject *exc = NULL;
4459 result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error);
4460 if (!mono_error_ok (&interp_error)) {
4462 g_print ("Test '%s' execution failed.\n", method->name);
4463 } else if (exc != NULL) {
4464 g_print ("Exception in Test '%s' occured:\n", method->name);
4465 mono_object_describe (exc);
4469 result = *(gint32 *) mono_object_unbox (result_obj);
4470 expected = atoi (method->name + 5); // FIXME: oh no.
4473 if (result != expected) {
4475 g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
4480 g_timer_stop (timer);
4481 elapsed = g_timer_elapsed (timer, NULL);
4482 if (failed > 0 || cfailed > 0){
4483 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
4484 run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
4486 g_print ("Results: total tests: %d, all pass \n", run);
4489 g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed,
4490 elapsed - transform_time, transform_time);
4491 *total += failed + cfailed;
4495 interp_regression (MonoImage *image, int verbose, int *total_run)
4498 GTimer *timer = g_timer_new ();
4499 MonoDomain *domain = mono_domain_get ();
4503 /* load the metadata */
4504 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
4506 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
4508 mono_error_cleanup (&error);
4511 mono_class_init (method->klass);
4516 interp_regression_step (image, verbose, total_run, &total, timer, domain);
4518 g_timer_destroy (timer);
4523 mono_interp_regression_list (int verbose, int count, char *images [])
4525 int i, total, total_run, run;
4527 total_run = total = 0;
4528 for (i = 0; i < count; ++i) {
4529 MonoAssembly *ass = mono_assembly_open (images [i], NULL);
4531 g_warning ("failed to load assembly: %s", images [i]);
4534 total += interp_regression (mono_assembly_get_image (ass), verbose, &run);
4538 g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run);
4540 g_print ("Overall results: tests: %d, 100%% pass\n", total_run);