3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001, 2002 Ximian, Inc.
28 #include <mono/utils/gc_wrapper.h>
34 # define alloca __builtin_alloca
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/utils/atomic.h>
63 #include "interp-internals.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/mini-arm.h>
74 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
77 #define finite _finite
81 #define finite isfinite
86 init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *rmethod, stackval *method_args, stackval *method_retval)
88 frame->parent = parent_frame;
89 frame->stack_args = method_args;
90 frame->retval = method_retval;
91 frame->runtime_method = rmethod;
94 frame->invoke_trap = 0;
97 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
98 RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
99 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
103 * List of classes whose methods will be executed by transitioning to JITted code.
108 void ves_exec_method (MonoInvocation *frame);
110 static char* dump_frame (MonoInvocation *inv);
111 static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
112 static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally);
114 typedef void (*ICallMethod) (MonoInvocation *frame);
116 static guint32 die_on_exception = 0;
117 static MonoNativeTlsKey thread_context_id;
119 static char* dump_args (MonoInvocation *inv);
121 #define DEBUG_INTERP 0
124 int mono_interp_traceopt = 2;
125 /* If true, then we output the opcodes as we interpret them */
126 static int global_tracing = 2;
128 static int debug_indent_level = 0;
130 static int break_on_method = 0;
131 static int nested_trace = 0;
132 static GList *db_methods = NULL;
139 for (h = 0; h < debug_indent_level; h++)
144 db_match_method (gpointer data, gpointer user_data)
146 MonoMethod *m = (MonoMethod*)user_data;
147 MonoMethodDesc *desc = data;
149 if (mono_method_desc_full_match (desc, m))
154 debug_enter (MonoInvocation *frame, int *tracing)
157 g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
159 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
163 MonoMethod *method = frame->runtime_method->method;
164 char *mn, *args = dump_args (frame);
165 debug_indent_level++;
167 mn = mono_method_full_name (method, FALSE);
168 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
170 g_print ("%s)\n", args);
173 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)
174 mono_profiler_method_enter (frame->runtime_method->method);
178 #define DEBUG_LEAVE() \
181 args = dump_retval (frame); \
183 mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
184 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
186 g_print (" => %s\n", args); \
188 debug_indent_level--; \
189 if (tracing == 3) global_tracing = 0; \
191 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
192 mono_profiler_method_leave (frame->runtime_method->method);
196 int mono_interp_traceopt = 0;
197 static void debug_enter (MonoInvocation *frame, int *tracing)
200 #define DEBUG_LEAVE()
204 /* Set the current execution state to the resume state in context */
205 #define SET_RESUME_STATE(context) do { \
206 ip = (context)->handler_ip; \
207 sp->data.p = frame->ex; \
210 (context)->has_resume_state = 0; \
211 (context)->handler_frame = NULL; \
216 ves_real_abort (int line, MonoMethod *mh,
217 const unsigned short *ip, stackval *stack, stackval *sp)
220 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
221 fprintf (stderr, "Line=%d IP=0x%04lx, Aborted execution\n", line,
222 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code);
223 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
224 g_print ("0x%04x %02x\n",
225 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code, *ip);
226 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
228 printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
231 #define ves_abort() \
233 ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
234 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
238 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
241 MonoJitDomainInfo *info;
242 MonoMethodSignature *sig;
247 info = domain_jit_info (domain);
248 mono_domain_jit_code_hash_lock (domain);
249 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
250 mono_domain_jit_code_hash_unlock (domain);
254 sig = mono_method_signature (method);
256 rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
257 rtm->method = method;
258 rtm->param_count = sig->param_count;
259 rtm->hasthis = sig->hasthis;
260 rtm->rtype = mini_get_underlying_type (sig->ret);
261 rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
262 for (i = 0; i < sig->param_count; ++i)
263 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
265 mono_domain_jit_code_hash_lock (domain);
266 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
267 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
268 mono_domain_jit_code_hash_unlock (domain);
274 mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
276 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
277 method = mono_marshal_get_synchronized_wrapper (method);
278 return mono_interp_get_runtime_method (domain, method, error);
281 static inline RuntimeMethod*
282 get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
284 MonoMethod *m = runtime_method->method;
287 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
288 RuntimeMethod *ret = NULL;
289 if (mono_object_is_transparent_proxy (obj)) {
290 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
291 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
292 } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
293 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
294 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
296 ret = runtime_method;
301 mono_class_setup_vtable (obj->vtable->klass);
303 int slot = mono_method_get_vtable_slot (m);
304 if (mono_class_is_interface (m->klass)) {
305 g_assert (obj->vtable->klass != m->klass);
306 /* TODO: interface offset lookup is slow, go through IMT instead */
307 gboolean non_exact_match;
308 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
311 MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
312 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
313 MonoGenericContext context = { NULL, NULL };
315 if (mono_class_is_ginst (virtual_method->klass))
316 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
317 else if (mono_class_is_gtd (virtual_method->klass))
318 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
319 context.method_inst = mono_method_get_context (m)->method_inst;
321 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
322 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
325 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
326 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
329 RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
330 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
331 return virtual_runtime_method;
335 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
338 switch (type->type) {
339 case MONO_TYPE_OBJECT:
340 case MONO_TYPE_CLASS:
341 case MONO_TYPE_STRING:
342 case MONO_TYPE_ARRAY:
343 case MONO_TYPE_SZARRAY:
348 result->data.p = *(gpointer*)data;
351 switch (type->type) {
355 result->data.i = *(gint8*)data;
358 case MONO_TYPE_BOOLEAN:
359 result->data.i = *(guint8*)data;
362 result->data.i = *(gint16*)data;
366 result->data.i = *(guint16*)data;
369 result->data.i = *(gint32*)data;
373 result->data.nati = *(mono_i*)data;
376 result->data.p = *(gpointer*)data;
379 result->data.i = *(guint32*)data;
382 result->data.f = *(float*)data;
386 result->data.l = *(gint64*)data;
389 result->data.f = *(double*)data;
391 case MONO_TYPE_STRING:
392 case MONO_TYPE_SZARRAY:
393 case MONO_TYPE_CLASS:
394 case MONO_TYPE_OBJECT:
395 case MONO_TYPE_ARRAY:
396 result->data.p = *(gpointer*)data;
398 case MONO_TYPE_VALUETYPE:
399 if (type->data.klass->enumtype) {
400 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
403 mono_value_copy (result->data.vt, data, type->data.klass);
405 case MONO_TYPE_GENERICINST: {
406 if (mono_type_generic_inst_is_valuetype (type)) {
407 mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
410 stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
414 g_warning ("got type 0x%02x", type->type);
415 g_assert_not_reached ();
420 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
423 gpointer *p = (gpointer*)data;
427 /* printf ("TODAT0 %p\n", data); */
428 switch (type->type) {
431 guint8 *p = (guint8*)data;
435 case MONO_TYPE_BOOLEAN: {
436 guint8 *p = (guint8*)data;
437 *p = (val->data.i != 0);
442 case MONO_TYPE_CHAR: {
443 guint16 *p = (guint16*)data;
448 mono_i *p = (mono_i*)data;
449 /* In theory the value used by stloc should match the local var type
450 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
451 a native int - both by csc and mcs). Not sure what to do about sign extension
452 as it is outside the spec... doing the obvious */
453 *p = (mono_i)val->data.nati;
457 mono_u *p = (mono_u*)data;
459 *p = (mono_u)val->data.nati;
464 gint32 *p = (gint32*)data;
470 gint64 *p = (gint64*)data;
475 float *p = (float*)data;
480 double *p = (double*)data;
484 case MONO_TYPE_STRING:
485 case MONO_TYPE_SZARRAY:
486 case MONO_TYPE_CLASS:
487 case MONO_TYPE_OBJECT:
488 case MONO_TYPE_ARRAY: {
489 gpointer *p = (gpointer *) data;
490 mono_gc_wbarrier_generic_store (p, val->data.p);
493 case MONO_TYPE_PTR: {
494 gpointer *p = (gpointer *) data;
498 case MONO_TYPE_VALUETYPE:
499 if (type->data.klass->enumtype) {
500 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
503 mono_value_copy (data, val->data.vt, type->data.klass);
505 case MONO_TYPE_GENERICINST: {
506 MonoClass *container_class = type->data.generic_class->container_class;
508 if (container_class->valuetype && !container_class->enumtype) {
509 mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
512 stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
516 g_warning ("got type %x", type->type);
517 g_assert_not_reached ();
522 fill_in_trace (MonoException *exception, MonoInvocation *frame)
525 char *stack_trace = dump_frame (frame);
526 MonoDomain *domain = mono_domain_get();
527 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
528 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
529 (exception)->trace_ips = get_trace_ips (domain, frame);
530 g_free (stack_trace);
533 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
535 #define THROW_EX(exception,ex_ip) \
537 frame->ip = (ex_ip); \
538 frame->ex = (MonoException*)(exception); \
539 FILL_IN_TRACE(frame->ex, frame); \
540 goto handle_exception; \
544 ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
547 intptr_t *lower_bounds;
552 lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
553 for (i = 0; i < sig->param_count; ++i) {
554 lengths [i] = values->data.i;
557 if (klass->rank == sig->param_count) {
558 /* Only lengths provided. */
561 /* lower bounds are first. */
562 lower_bounds = (intptr_t *) lengths;
563 lengths += klass->rank;
565 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
566 if (!mono_error_ok (&error)) {
567 frame->ex = mono_error_convert_to_exception (&error);
568 FILL_IN_TRACE (frame->ex, frame);
570 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
575 ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame, gboolean safe)
577 g_assert (!frame->ex);
578 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
582 for (gint32 i = 0; i < ac->rank; i++) {
583 guint32 idx = sp [i].data.i;
584 guint32 lower = ao->bounds [i].lower_bound;
585 guint32 len = ao->bounds [i].length;
586 if (safe && (idx < lower || (idx - lower) >= len)) {
587 frame->ex = mono_get_exception_index_out_of_range ();
588 FILL_IN_TRACE (frame->ex, frame);
591 pos = (pos * len) + idx - lower;
595 if (safe && pos >= ao->max_length) {
596 frame->ex = mono_get_exception_index_out_of_range ();
597 FILL_IN_TRACE (frame->ex, frame);
605 ves_array_set (MonoInvocation *frame)
607 stackval *sp = frame->stack_args + 1;
609 MonoObject *o = frame->stack_args->data.p;
610 MonoArray *ao = (MonoArray *) o;
611 MonoClass *ac = o->vtable->klass;
613 g_assert (ac->rank >= 1);
615 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
619 if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
621 MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
622 mono_error_cleanup (&error);
624 frame->ex = mono_get_exception_array_type_mismatch ();
625 FILL_IN_TRACE (frame->ex, frame);
630 gint32 esize = mono_array_element_size (ac);
631 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
633 MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
634 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
638 ves_array_get (MonoInvocation *frame, gboolean safe)
640 stackval *sp = frame->stack_args + 1;
642 MonoObject *o = frame->stack_args->data.p;
643 MonoArray *ao = (MonoArray *) o;
644 MonoClass *ac = o->vtable->klass;
646 g_assert (ac->rank >= 1);
648 gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
652 gint32 esize = mono_array_element_size (ac);
653 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
655 MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret;
656 stackval_from_data (mt, frame->retval, ea, FALSE);
660 ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
662 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
664 g_assert (ac->rank >= 1);
666 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
670 if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
671 frame->ex = mono_get_exception_array_type_mismatch ();
672 FILL_IN_TRACE (frame->ex, frame);
675 gint32 esize = mono_array_element_size (ac);
676 return mono_array_addr_with_size (ao, esize, pos);
680 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
683 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
688 MonoInvocation *frame = context->current_frame;
691 MonoStackFrameInfo fi;
692 memset (&fi, 0, sizeof (MonoStackFrameInfo));
694 /* TODO: hack to make some asserts happy. */
695 fi.ji = (MonoJitInfo *) frame->runtime_method;
697 if (frame->runtime_method)
698 fi.method = fi.actual_method = frame->runtime_method->method;
700 if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
702 fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
704 MonoMethodHeader *hd = mono_method_get_header_checked (fi.method, &error);
705 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
706 fi.type = FRAME_TYPE_MANAGED;
707 fi.il_offset = frame->ip - (const unsigned short *) hd->code;
708 if (!fi.method->wrapper_type)
712 if (func (&fi, ctx, user_data))
714 frame = frame->parent;
718 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
720 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
722 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
725 g_assert (mono_arm_eabi_supported ());
726 int i8_align = mono_arm_i8_align ();
732 for (int i = 0; i < sig->param_count; i++) {
733 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
735 case MONO_TYPE_BOOLEAN:
746 case MONO_TYPE_SZARRAY:
747 case MONO_TYPE_CLASS:
748 case MONO_TYPE_OBJECT:
749 case MONO_TYPE_STRING:
750 case MONO_TYPE_VALUETYPE:
751 case MONO_TYPE_GENERICINST:
752 #if SIZEOF_VOID_P == 8
757 #if SIZEOF_VOID_P == 4
760 /* pairs begin at even registers */
761 if (i8_align == 8 && margs->ilen & 1)
768 #if SIZEOF_VOID_P == 8
773 #if SIZEOF_VOID_P == 4
779 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
784 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
787 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
789 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
790 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
792 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
793 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
800 margs->iargs [0] = frame->stack_args->data.p;
804 for (int i = 0; i < sig->param_count; i++) {
805 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
807 case MONO_TYPE_BOOLEAN:
818 case MONO_TYPE_SZARRAY:
819 case MONO_TYPE_CLASS:
820 case MONO_TYPE_OBJECT:
821 case MONO_TYPE_STRING:
822 case MONO_TYPE_VALUETYPE:
823 case MONO_TYPE_GENERICINST:
824 #if SIZEOF_VOID_P == 8
827 margs->iargs [int_i] = frame->stack_args [i].data.p;
829 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
833 #if SIZEOF_VOID_P == 4
835 stackval *sarg = &frame->stack_args [i];
837 /* pairs begin at even registers */
838 if (i8_align == 8 && int_i & 1)
841 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
843 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
845 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
853 if (ptype == MONO_TYPE_R4)
854 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
856 margs->fargs [int_f] = frame->stack_args [i].data.f;
858 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);
860 #if SIZEOF_VOID_P == 4
867 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
871 switch (sig->ret->type) {
872 case MONO_TYPE_BOOLEAN:
883 case MONO_TYPE_SZARRAY:
884 case MONO_TYPE_CLASS:
885 case MONO_TYPE_OBJECT:
886 case MONO_TYPE_STRING:
888 case MONO_TYPE_VALUETYPE:
889 case MONO_TYPE_GENERICINST:
890 margs->retval = &(frame->retval->data.p);
891 margs->is_float_ret = 0;
895 margs->retval = &(frame->retval->data.p);
896 margs->is_float_ret = 1;
899 margs->retval = NULL;
902 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
909 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
912 MonoInvocation *old_frame = context->current_frame;
913 MonoInvocation *old_env_frame = context->env_frame;
914 jmp_buf *old_env = context->current_env;
918 context->current_frame = old_frame;
919 context->env_frame = old_env_frame;
920 context->current_env = old_env;
921 context->managed_code = 1;
926 context->env_frame = frame;
927 context->current_env = &env;
929 g_assert (!frame->runtime_method);
930 if (!mono_interp_enter_icall_trampoline) {
932 mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
934 // mono_tramp_info_register (info, NULL);
937 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
939 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
940 g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
943 context->current_frame = frame;
944 context->managed_code = 0;
947 * Push an LMF frame on the LMF stack
948 * to mark the transition to native code.
950 memset (&ext, 0, sizeof (ext));
951 ext.interp_exit = TRUE;
952 ext.interp_exit_data = frame;
954 mono_push_lmf (&ext);
956 mono_interp_enter_icall_trampoline (addr, margs);
958 mono_pop_lmf (&ext.lmf);
960 context->managed_code = 1;
961 /* domain can only be changed by native code */
962 context->domain = mono_domain_get ();
964 if (*mono_thread_interruption_request_flag ()) {
965 MonoException *exc = mono_thread_interruption_checkpoint ();
968 context->search_for_handler = 1;
972 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
973 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
975 context->current_frame = old_frame;
976 context->env_frame = old_env_frame;
977 context->current_env = old_env;
979 g_free (margs->iargs);
980 g_free (margs->fargs);
985 mono_interp_init_delegate (MonoDelegate *del)
989 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
990 del->method = ((RuntimeMethod *) del->method_ptr)->method;
995 * runtime specifies that the implementation of the method is automatically
996 * provided by the runtime and is primarily used for the methods of delegates.
999 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
1001 MonoMethod *method = frame->runtime_method->method;
1002 const char *name = method->name;
1003 MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
1004 MonoObject *isinst_obj;
1007 mono_class_init (method->klass);
1009 if (method->klass == mono_defaults.array_class) {
1010 if (!strcmp (method->name, "UnsafeMov")) {
1011 /* TODO: layout checks */
1012 MonoType *mt = mono_method_signature (method)->ret;
1013 stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
1016 if (!strcmp (method->name, "UnsafeLoad")) {
1017 ves_array_get (frame, FALSE);
1022 isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
1023 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1024 if (obj && isinst_obj) {
1025 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1026 ves_array_set (frame);
1029 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1030 ves_array_get (frame, TRUE);
1035 g_error ("Don't know how to exec runtime method %s.%s::%s",
1036 method->klass->name_space, method->klass->name,
1042 dump_stack (stackval *stack, stackval *sp)
1044 stackval *s = stack;
1045 GString *str = g_string_new ("");
1048 return g_string_free (str, FALSE);
1051 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1054 return g_string_free (str, FALSE);
1059 dump_stackval (GString *str, stackval *s, MonoType *type)
1061 switch (type->type) {
1068 case MONO_TYPE_CHAR:
1069 case MONO_TYPE_BOOLEAN:
1070 g_string_append_printf (str, "[%d] ", s->data.i);
1072 case MONO_TYPE_STRING:
1073 case MONO_TYPE_SZARRAY:
1074 case MONO_TYPE_CLASS:
1075 case MONO_TYPE_OBJECT:
1076 case MONO_TYPE_ARRAY:
1080 g_string_append_printf (str, "[%p] ", s->data.p);
1082 case MONO_TYPE_VALUETYPE:
1083 if (type->data.klass->enumtype)
1084 g_string_append_printf (str, "[%d] ", s->data.i);
1086 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1090 g_string_append_printf (str, "[%g] ", s->data.f);
1095 GString *res = g_string_new ("");
1096 mono_type_get_desc (res, type, TRUE);
1097 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1098 g_string_free (res, TRUE);
1106 dump_retval (MonoInvocation *inv)
1108 GString *str = g_string_new ("");
1109 MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
1111 if (ret->type != MONO_TYPE_VOID)
1112 dump_stackval (str, inv->retval, ret);
1114 return g_string_free (str, FALSE);
1119 dump_args (MonoInvocation *inv)
1121 GString *str = g_string_new ("");
1123 MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method);
1125 if (signature->param_count == 0 && !signature->hasthis)
1126 return g_string_free (str, FALSE);
1128 if (signature->hasthis) {
1129 MonoMethod *method = inv->runtime_method->method;
1130 dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1133 for (i = 0; i < signature->param_count; ++i)
1134 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1136 return g_string_free (str, FALSE);
1140 dump_frame (MonoInvocation *inv)
1142 GString *str = g_string_new ("");
1147 for (i = 0; inv; inv = inv->parent) {
1148 if (inv->runtime_method != NULL) {
1149 MonoMethod *method = inv->runtime_method->method;
1153 const char * opname = "";
1155 gchar *source = NULL;
1159 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1160 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1161 MonoMethodHeader *hd = mono_method_get_header_checked (method, &error);
1162 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1166 opname = mono_interp_opname [*inv->ip];
1167 codep = inv->ip - inv->runtime_method->code;
1168 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1173 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1174 source = mono_debug_method_lookup_location (minfo, codep);
1178 args = dump_args (inv);
1179 name = mono_method_full_name (method, TRUE);
1181 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1183 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1190 return g_string_free (str, FALSE);
1194 get_trace_ips (MonoDomain *domain, MonoInvocation *top)
1198 MonoInvocation *inv;
1201 for (i = 0, inv = top; inv; inv = inv->parent)
1202 if (inv->runtime_method != NULL)
1205 res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error);
1206 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1208 for (i = 0, inv = top; inv; inv = inv->parent)
1209 if (inv->runtime_method != NULL) {
1210 mono_array_set (res, gpointer, i, inv->runtime_method);
1212 mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1220 #define MYGUINT64_MAX 18446744073709551615ULL
1221 #define MYGINT64_MAX 9223372036854775807LL
1222 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1224 #define MYGUINT32_MAX 4294967295U
1225 #define MYGINT32_MAX 2147483647
1226 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1228 #define CHECK_ADD_OVERFLOW(a,b) \
1229 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1230 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1232 #define CHECK_SUB_OVERFLOW(a,b) \
1233 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1234 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1236 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1237 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1239 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1240 (guint32)(a) < (guint32)(b) ? -1 : 0
1242 #define CHECK_ADD_OVERFLOW64(a,b) \
1243 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1244 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1246 #define CHECK_SUB_OVERFLOW64(a,b) \
1247 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1248 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1250 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1251 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1253 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1254 (guint64)(a) < (guint64)(b) ? -1 : 0
1256 #if SIZEOF_VOID_P == 4
1257 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1258 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1260 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1261 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1264 /* Resolves to TRUE if the operands would overflow */
1265 #define CHECK_MUL_OVERFLOW(a,b) \
1266 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1267 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1268 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1269 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1270 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1271 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1272 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1274 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1275 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1276 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1278 #define CHECK_MUL_OVERFLOW64(a,b) \
1279 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1280 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1281 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1282 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1283 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1284 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1285 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1287 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1288 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1289 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1291 #if SIZEOF_VOID_P == 4
1292 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1293 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1295 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1296 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1300 mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1302 MonoInvocation frame;
1303 ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1304 MonoObject *retval = NULL;
1305 MonoMethodSignature *sig = mono_method_signature (method);
1306 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1307 int i, type, isobject = 0;
1310 stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
1311 ThreadContext context_struct;
1312 MonoInvocation *old_frame = NULL;
1322 if (context != &context_struct) {
1323 context->domain = mono_domain_get ();
1324 context->current_frame = old_frame;
1325 context->managed_code = 0;
1327 mono_native_tls_set_value (thread_context_id, NULL);
1329 *exc = (MonoObject *)frame.ex;
1333 if (context == NULL) {
1334 context = &context_struct;
1335 memset (context, 0, sizeof (ThreadContext));
1336 context_struct.base_frame = &frame;
1337 context_struct.env_frame = &frame;
1338 context_struct.current_env = &env;
1339 mono_native_tls_set_value (thread_context_id, context);
1342 old_frame = context->current_frame;
1344 context->domain = mono_domain_get ();
1346 switch (sig->ret->type) {
1347 case MONO_TYPE_VOID:
1349 case MONO_TYPE_STRING:
1350 case MONO_TYPE_OBJECT:
1351 case MONO_TYPE_CLASS:
1352 case MONO_TYPE_ARRAY:
1353 case MONO_TYPE_SZARRAY:
1356 case MONO_TYPE_VALUETYPE:
1357 retval = mono_object_new_checked (context->domain, klass, error);
1358 ret = mono_object_unbox (retval);
1359 if (!sig->ret->data.klass->enumtype)
1360 result.data.vt = ret;
1362 result.data.vt = alloca (mono_class_instance_size (klass));
1364 case MONO_TYPE_GENERICINST:
1365 if (!MONO_TYPE_IS_REFERENCE (sig->ret)) {
1366 retval = mono_object_new_checked (context->domain, klass, error);
1367 ret = mono_object_unbox (retval);
1368 if (!sig->ret->data.klass->enumtype)
1369 result.data.vt = ret;
1371 result.data.vt = alloca (mono_class_instance_size (klass));
1378 retval = mono_object_new_checked (context->domain, mono_defaults.int_class, error);
1379 ret = mono_object_unbox (retval);
1382 retval = mono_object_new_checked (context->domain, klass, error);
1383 ret = mono_object_unbox (retval);
1388 args [0].data.p = obj;
1390 for (i = 0; i < sig->param_count; ++i) {
1391 int a_index = i + !!sig->hasthis;
1392 if (sig->params [i]->byref) {
1393 args [a_index].data.p = params [i];
1396 type = sig->params [i]->type;
1401 case MONO_TYPE_BOOLEAN:
1402 args [a_index].data.i = *(MonoBoolean*)params [i];
1406 case MONO_TYPE_CHAR:
1407 args [a_index].data.i = *(gint16*)params [i];
1409 #if SIZEOF_VOID_P == 4
1410 case MONO_TYPE_U: /* use VAL_POINTER? */
1415 args [a_index].data.i = *(gint32*)params [i];
1417 #if SIZEOF_VOID_P == 8
1423 args [a_index].data.l = *(gint64*)params [i];
1426 args [a_index].data.f = *(gfloat *) params [i];
1429 args [a_index].data.f = *(gdouble *) params [i];
1431 case MONO_TYPE_VALUETYPE:
1432 if (sig->params [i]->data.klass->enumtype) {
1433 type = mono_class_enum_basetype (sig->params [i]->data.klass)->type;
1436 args [a_index].data.p = params [i];
1439 case MONO_TYPE_STRING:
1441 case MONO_TYPE_CLASS:
1442 case MONO_TYPE_ARRAY:
1443 case MONO_TYPE_SZARRAY:
1444 case MONO_TYPE_OBJECT:
1445 case MONO_TYPE_GENERICINST:
1446 args [a_index].data.p = params [i];
1449 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1453 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1454 method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
1455 INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
1457 frame.invoke_trap = 1;
1458 context->managed_code = 1;
1459 ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
1460 context->managed_code = 0;
1461 if (context == &context_struct)
1462 mono_native_tls_set_value (thread_context_id, NULL);
1464 context->current_frame = old_frame;
1465 if (frame.ex != NULL) {
1467 *exc = (MonoObject*) frame.ex;
1470 if (context->current_env != NULL) {
1471 context->env_frame->ex = frame.ex;
1472 longjmp(*context->current_env, 1);
1475 printf("dropped exception...\n");
1477 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1479 if (isobject || method->string_ctor)
1480 return result.data.p;
1481 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1486 RuntimeMethod *rmethod;
1490 gpointer *many_args;
1493 /* Main function for entering the interpreter from compiled code */
1495 interp_entry (InterpEntryData *data)
1497 MonoInvocation frame;
1498 RuntimeMethod *rmethod = data->rmethod;
1499 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
1500 ThreadContext context_struct;
1501 MonoInvocation *old_frame;
1505 MonoMethodSignature *sig;
1509 method = rmethod->method;
1510 sig = mono_method_signature (method);
1512 // FIXME: Optimize this
1514 //printf ("%s\n", mono_method_full_name (method, 1));
1517 if (context == NULL) {
1518 context = &context_struct;
1519 memset (context, 0, sizeof (ThreadContext));
1520 context_struct.base_frame = &frame;
1521 context_struct.env_frame = &frame;
1522 mono_native_tls_set_value (thread_context_id, context);
1525 old_frame = context->current_frame;
1526 context->domain = mono_domain_get ();
1528 args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
1530 args [0].data.p = data->this_arg;
1533 if (data->many_args)
1534 params = data->many_args;
1536 params = data->args;
1537 for (i = 0; i < sig->param_count; ++i) {
1538 int a_index = i + (sig->hasthis ? 1 : 0);
1539 if (sig->params [i]->byref) {
1540 args [a_index].data.p = params [i];
1543 type = rmethod->param_types [i];
1544 switch (type->type) {
1547 args [a_index].data.i = *(MonoBoolean*)params [i];
1551 args [a_index].data.i = *(gint16*)params [i];
1554 #if SIZEOF_VOID_P == 4
1555 args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
1557 args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
1561 #if SIZEOF_VOID_P == 4
1562 args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
1564 args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
1568 args [a_index].data.i = *(guint32*)params [i];
1571 args [a_index].data.i = *(gint32*)params [i];
1574 args [a_index].data.l = *(guint64*)params [i];
1577 args [a_index].data.l = *(gint64*)params [i];
1580 case MONO_TYPE_OBJECT:
1581 args [a_index].data.p = *(MonoObject**)params [i];
1583 case MONO_TYPE_VALUETYPE:
1584 args [a_index].data.p = params [i];
1586 case MONO_TYPE_GENERICINST:
1587 if (MONO_TYPE_IS_REFERENCE (type))
1588 args [a_index].data.p = params [i];
1590 args [a_index].data.vt = params [i];
1593 printf ("%s\n", mono_type_full_name (sig->params [i]));
1599 init_frame (&frame, NULL, data->rmethod, args, &result);
1600 context->managed_code = 1;
1602 type = rmethod->rtype;
1603 switch (type->type) {
1604 case MONO_TYPE_GENERICINST:
1605 if (!MONO_TYPE_IS_REFERENCE (type))
1606 frame.retval->data.vt = data->res;
1608 case MONO_TYPE_VALUETYPE:
1609 frame.retval->data.vt = data->res;
1615 ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
1616 context->managed_code = 0;
1617 if (context == &context_struct)
1618 mono_native_tls_set_value (thread_context_id, NULL);
1620 context->current_frame = old_frame;
1623 g_assert (frame.ex == NULL);
1625 type = rmethod->rtype;
1626 switch (type->type) {
1627 case MONO_TYPE_VOID:
1630 *(gint8*)data->res = frame.retval->data.i;
1633 *(guint8*)data->res = frame.retval->data.i;
1636 *(gint16*)data->res = frame.retval->data.i;
1639 *(guint16*)data->res = frame.retval->data.i;
1642 *(gint32*)data->res = frame.retval->data.i;
1645 *(guint64*)data->res = frame.retval->data.i;
1648 *(gint64*)data->res = frame.retval->data.i;
1651 *(guint64*)data->res = frame.retval->data.i;
1654 #if SIZEOF_VOID_P == 8
1655 *(gint64*)data->res = (gint64)frame.retval->data.p;
1657 *(gint32*)data->res = (gint32)frame.retval->data.p;
1661 #if SIZEOF_VOID_P == 8
1662 *(guint64*)data->res = (guint64)frame.retval->data.p;
1664 *(guint32*)data->res = (guint32)frame.retval->data.p;
1667 case MONO_TYPE_OBJECT:
1668 /* No need for a write barrier */
1669 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1671 case MONO_TYPE_GENERICINST:
1672 if (MONO_TYPE_IS_REFERENCE (type)) {
1673 *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
1675 /* Already set before the call */
1678 case MONO_TYPE_VALUETYPE:
1679 /* Already set before the call */
1682 printf ("%s\n", mono_type_full_name (sig->ret));
1689 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1691 MonoInvocation *old_frame = context->current_frame;
1692 MonoInvocation *old_env_frame = context->env_frame;
1693 jmp_buf *old_env = context->current_env;
1697 context->current_frame = old_frame;
1698 context->env_frame = old_env_frame;
1699 context->current_env = old_env;
1700 context->managed_code = 1;
1704 context->env_frame = context->current_frame;
1705 context->current_env = &env;
1706 context->managed_code = 0;
1709 case MINT_ICALL_V_V: {
1710 void (*func)(void) = ptr;
1714 case MINT_ICALL_V_P: {
1715 gpointer (*func)(void) = ptr;
1717 sp [-1].data.p = func ();
1720 case MINT_ICALL_P_V: {
1721 void (*func)(gpointer) = ptr;
1722 func (sp [-1].data.p);
1726 case MINT_ICALL_P_P: {
1727 gpointer (*func)(gpointer) = ptr;
1728 sp [-1].data.p = func (sp [-1].data.p);
1731 case MINT_ICALL_PP_V: {
1732 void (*func)(gpointer,gpointer) = ptr;
1734 func (sp [0].data.p, sp [1].data.p);
1737 case MINT_ICALL_PI_V: {
1738 void (*func)(gpointer,int) = ptr;
1740 func (sp [0].data.p, sp [1].data.i);
1743 case MINT_ICALL_PP_P: {
1744 gpointer (*func)(gpointer,gpointer) = ptr;
1746 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1749 case MINT_ICALL_PI_P: {
1750 gpointer (*func)(gpointer,int) = ptr;
1752 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1755 case MINT_ICALL_PPP_V: {
1756 void (*func)(gpointer,gpointer,gpointer) = ptr;
1758 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1761 case MINT_ICALL_PPI_V: {
1762 void (*func)(gpointer,gpointer,int) = ptr;
1764 func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1768 g_assert_not_reached ();
1771 context->env_frame = old_env_frame;
1772 context->current_env = old_env;
1778 * These functions are the entry points into the interpreter from compiled code.
1779 * They are called by the interp_in wrappers. They have the following signature:
1780 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1781 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1782 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1783 * more wrappers then these functions.
1784 * this/static * ret/void * 16 arguments -> 64 functions.
1787 #define MAX_INTERP_ENTRY_ARGS 8
1789 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1790 InterpEntryData data; \
1791 (data).rmethod = (_method); \
1792 (data).res = (_res); \
1793 (data).this_arg = (_this_arg); \
1794 (data).many_args = NULL;
1796 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
1797 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1798 interp_entry (&data); \
1800 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
1801 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1802 (data).args [0] = arg1; \
1803 interp_entry (&data); \
1805 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
1806 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1807 (data).args [0] = arg1; \
1808 (data).args [1] = arg2; \
1809 interp_entry (&data); \
1811 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
1812 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1813 (data).args [0] = arg1; \
1814 (data).args [1] = arg2; \
1815 (data).args [2] = arg3; \
1816 interp_entry (&data); \
1818 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
1819 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1820 (data).args [0] = arg1; \
1821 (data).args [1] = arg2; \
1822 (data).args [2] = arg3; \
1823 (data).args [3] = arg4; \
1824 interp_entry (&data); \
1826 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
1827 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1828 (data).args [0] = arg1; \
1829 (data).args [1] = arg2; \
1830 (data).args [2] = arg3; \
1831 (data).args [3] = arg4; \
1832 (data).args [4] = arg5; \
1833 interp_entry (&data); \
1835 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
1836 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1837 (data).args [0] = arg1; \
1838 (data).args [1] = arg2; \
1839 (data).args [2] = arg3; \
1840 (data).args [3] = arg4; \
1841 (data).args [4] = arg5; \
1842 (data).args [5] = arg6; \
1843 interp_entry (&data); \
1845 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
1846 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1847 (data).args [0] = arg1; \
1848 (data).args [1] = arg2; \
1849 (data).args [2] = arg3; \
1850 (data).args [3] = arg4; \
1851 (data).args [4] = arg5; \
1852 (data).args [5] = arg6; \
1853 (data).args [6] = arg7; \
1854 interp_entry (&data); \
1856 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
1857 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1858 (data).args [0] = arg1; \
1859 (data).args [1] = arg2; \
1860 (data).args [2] = arg3; \
1861 (data).args [3] = arg4; \
1862 (data).args [4] = arg5; \
1863 (data).args [5] = arg6; \
1864 (data).args [6] = arg7; \
1865 (data).args [7] = arg8; \
1866 interp_entry (&data); \
1869 #define ARGLIST0 RuntimeMethod *rmethod
1870 #define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
1871 #define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
1872 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
1873 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
1874 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
1875 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
1876 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
1877 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *rmethod
1879 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
1880 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
1881 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
1882 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
1883 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
1884 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
1885 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
1886 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
1887 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
1888 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
1889 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
1890 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
1891 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
1892 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
1893 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
1894 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
1895 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
1896 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
1897 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
1898 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
1899 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
1900 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
1901 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
1902 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
1903 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
1904 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
1905 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
1906 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
1907 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
1908 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
1909 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
1910 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
1911 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
1912 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
1913 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod)
1914 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod)
1916 #define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
1918 gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
1919 gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
1920 gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
1921 gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
1923 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
1925 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1927 INTERP_ENTRY_BASE (rmethod, this_arg, res);
1928 data.many_args = args;
1929 interp_entry (&data);
1933 * mono_interp_create_method_pointer:
1935 * Return a function pointer which can be used to call METHOD using the
1936 * interpreter. Return NULL for methods which are not supported.
1939 mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
1942 MonoMethodSignature *sig = mono_method_signature (method);
1943 MonoMethod *wrapper;
1944 RuntimeMethod *rmethod;
1946 /* HACK: method_ptr of delegate should point to a runtime method*/
1947 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1948 return mono_interp_get_runtime_method (mono_domain_get (), method, error);
1950 rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
1951 if (rmethod->jit_entry)
1952 return rmethod->jit_entry;
1953 wrapper = mini_get_interp_in_wrapper (sig);
1955 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
1956 mono_error_assert_ok (error);
1958 //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1959 gpointer entry_func;
1960 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
1961 entry_func = interp_entry_general;
1962 } else if (sig->hasthis) {
1963 if (sig->ret->type == MONO_TYPE_VOID)
1964 entry_func = entry_funcs_instance [sig->param_count];
1966 entry_func = entry_funcs_instance_ret [sig->param_count];
1968 if (sig->ret->type == MONO_TYPE_VOID)
1969 entry_func = entry_funcs_static [sig->param_count];
1971 entry_func = entry_funcs_static_ret [sig->param_count];
1973 g_assert (entry_func);
1975 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
1976 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
1977 ftndesc->addr = entry_func;
1978 ftndesc->arg = rmethod;
1979 mono_error_assert_ok (error);
1982 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
1983 * rgctx register using a trampoline.
1987 g_assert (!mono_aot_only);
1988 addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
1990 mono_memory_barrier ();
1991 rmethod->jit_entry = addr;
1997 static int opcode_counts[512];
1999 #define COUNT_OP(op) opcode_counts[op]++
2001 #define COUNT_OP(op)
2005 #define DUMP_INSTR() \
2006 if (tracing > 1) { \
2008 if (sp > frame->stack) { \
2009 ins = dump_stack (frame->stack, sp); \
2011 ins = g_strdup (""); \
2015 char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
2016 g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
2018 mono_interp_dis_mintop(rtm->code, ip); \
2019 g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
2023 #define DUMP_INSTR()
2027 #define USE_COMPUTED_GOTO 1
2029 #if USE_COMPUTED_GOTO
2030 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2031 #define MINT_IN_CASE(x) LAB_ ## x:
2033 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2035 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2037 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2039 #define MINT_IN_SWITCH(op) switch (op)
2040 #define MINT_IN_CASE(x) case x:
2041 #define MINT_IN_BREAK break
2042 #define MINT_IN_DEFAULT default:
2046 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2049 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally)
2051 MonoInvocation child_frame;
2052 GSList *finally_ips = NULL;
2053 const unsigned short *endfinally_ip = NULL;
2054 const unsigned short *ip = NULL;
2055 register stackval *sp;
2058 gint tracing = global_tracing;
2059 unsigned char *vtalloc;
2064 unsigned char *vt_sp;
2065 unsigned char *locals;
2067 MonoObject *o = NULL;
2069 #if USE_COMPUTED_GOTO
2070 static void *in_labels[] = {
2071 #define OPDEF(a,b,c,d) \
2073 #include "mintops.def"
2078 frame->ex_handler = NULL;
2080 context->current_frame = frame;
2082 debug_enter (frame, &tracing);
2084 if (!frame->runtime_method->transformed) {
2085 context->managed_code = 0;
2087 char *mn = mono_method_full_name (frame->runtime_method->method, TRUE);
2088 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2091 frame->ex = mono_interp_transform_method (frame->runtime_method, context);
2092 context->managed_code = 1;
2100 rtm = frame->runtime_method;
2101 if (!start_with_ip ) {
2102 frame->args = alloca (rtm->alloca_size);
2103 memset (frame->args, 0, rtm->alloca_size);
2109 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2110 vt_sp = (unsigned char *) sp + rtm->stack_size;
2114 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2115 child_frame.parent = frame;
2117 if (filter_exception) {
2118 sp->data.p = filter_exception;
2123 * using while (ip < end) may result in a 15% performance drop,
2124 * but it may be useful for debug
2128 /* g_assert (sp >= frame->stack); */
2129 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2131 MINT_IN_SWITCH (*ip) {
2132 MINT_IN_CASE(MINT_INITLOCALS)
2133 memset (locals, 0, rtm->locals_size);
2136 MINT_IN_CASE(MINT_NOP)
2139 MINT_IN_CASE(MINT_BREAK)
2141 G_BREAKPOINT (); /* this is not portable... */
2143 MINT_IN_CASE(MINT_LDNULL)
2148 MINT_IN_CASE(MINT_VTRESULT) {
2149 int ret_size = * (guint16 *)(ip + 1);
2150 unsigned char *ret_vt_sp = vt_sp;
2151 vt_sp -= READ32(ip + 2);
2153 memmove (vt_sp, ret_vt_sp, ret_size);
2154 sp [-1].data.p = vt_sp;
2155 vt_sp += (ret_size + 7) & ~7;
2160 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2161 MINT_IN_CASE(MINT_LDC_I4_M1)
2164 MINT_IN_CASE(MINT_LDC_I4_0)
2167 MINT_IN_CASE(MINT_LDC_I4_1)
2170 MINT_IN_CASE(MINT_LDC_I4_2)
2173 MINT_IN_CASE(MINT_LDC_I4_3)
2176 MINT_IN_CASE(MINT_LDC_I4_4)
2179 MINT_IN_CASE(MINT_LDC_I4_5)
2182 MINT_IN_CASE(MINT_LDC_I4_6)
2185 MINT_IN_CASE(MINT_LDC_I4_7)
2188 MINT_IN_CASE(MINT_LDC_I4_8)
2191 MINT_IN_CASE(MINT_LDC_I4_S)
2192 sp->data.i = *(const short *)(ip + 1);
2196 MINT_IN_CASE(MINT_LDC_I4)
2198 sp->data.i = READ32 (ip);
2202 MINT_IN_CASE(MINT_LDC_I8)
2204 sp->data.l = READ64 (ip);
2208 MINT_IN_CASE(MINT_LDC_R4) {
2212 sp->data.f = * (float *)&val;
2217 MINT_IN_CASE(MINT_LDC_R8)
2218 sp->data.l = READ64 (ip + 1); /* note union usage */
2222 MINT_IN_CASE(MINT_DUP)
2227 MINT_IN_CASE(MINT_DUP_VT)
2228 i32 = READ32 (ip + 1);
2230 memcpy(sp->data.p, sp [-1].data.p, i32);
2231 vt_sp += (i32 + 7) & ~7;
2235 MINT_IN_CASE(MINT_POP) {
2236 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2238 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2243 MINT_IN_CASE(MINT_JMP) {
2244 RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
2245 if (!new_method->transformed) {
2247 frame->ex = mono_interp_transform_method (new_method, context);
2252 if (new_method->alloca_size > rtm->alloca_size)
2253 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size);
2254 rtm = frame->runtime_method = new_method;
2255 vt_sp = (unsigned char *) sp + rtm->stack_size;
2259 locals = vt_sp + rtm->vt_stack_size;
2260 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2263 MINT_IN_CASE(MINT_CALLI) {
2264 MonoMethodSignature *csignature;
2265 stackval *endsp = sp;
2269 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2273 child_frame.runtime_method = sp->data.p;
2276 child_frame.retval = sp;
2277 /* decrement by the actual number of args */
2278 sp -= csignature->param_count;
2279 if (csignature->hasthis)
2281 child_frame.stack_args = sp;
2283 /* `this' can be NULL for string:.ctor */
2284 if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
2285 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2286 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2287 } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2288 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
2289 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2292 if (csignature->hasthis) {
2293 MonoObject *this_arg = sp->data.p;
2295 if (this_arg->vtable->klass->valuetype) {
2296 gpointer *unboxed = mono_object_unbox (this_arg);
2297 sp [0].data.p = unboxed;
2301 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2303 context->current_frame = frame;
2305 if (context->has_resume_state) {
2306 if (frame == context->handler_frame)
2307 SET_RESUME_STATE (context);
2312 if (child_frame.ex) {
2314 * An exception occurred, need to run finally, fault and catch handlers..
2316 frame->ex = child_frame.ex;
2317 goto handle_finally;
2320 /* need to handle typedbyref ... */
2321 if (csignature->ret->type != MONO_TYPE_VOID) {
2327 MINT_IN_CASE(MINT_CALLI_NAT) {
2328 MonoMethodSignature *csignature;
2329 stackval *endsp = sp;
2330 unsigned char *code = NULL;
2334 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2339 child_frame.runtime_method = NULL;
2342 child_frame.retval = sp;
2343 /* decrement by the actual number of args */
2344 sp -= csignature->param_count;
2345 if (csignature->hasthis)
2347 child_frame.stack_args = sp;
2348 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2350 context->current_frame = frame;
2352 if (context->has_resume_state) {
2353 if (frame == context->handler_frame)
2354 SET_RESUME_STATE (context);
2359 if (child_frame.ex) {
2361 * An exception occurred, need to run finally, fault and catch handlers..
2363 frame->ex = child_frame.ex;
2364 if (context->search_for_handler) {
2365 context->search_for_handler = 0;
2366 goto handle_exception;
2368 goto handle_finally;
2371 /* need to handle typedbyref ... */
2372 if (csignature->ret->type != MONO_TYPE_VOID) {
2378 MINT_IN_CASE(MINT_CALL) {
2379 stackval *endsp = sp;
2383 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
2386 child_frame.retval = sp;
2387 /* decrement by the actual number of args */
2388 sp -= child_frame.runtime_method->param_count;
2389 if (child_frame.runtime_method->hasthis)
2391 child_frame.stack_args = sp;
2393 /* `this' can be NULL for string:.ctor */
2394 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
2395 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2396 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2399 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2401 context->current_frame = frame;
2403 if (context->has_resume_state) {
2404 if (frame == context->handler_frame)
2405 SET_RESUME_STATE (context);
2410 if (child_frame.ex) {
2412 * An exception occurred, need to run finally, fault and catch handlers..
2414 frame->ex = child_frame.ex;
2415 goto handle_exception;;
2418 /* need to handle typedbyref ... */
2423 MINT_IN_CASE(MINT_VCALL) {
2426 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
2430 child_frame.retval = sp;
2431 /* decrement by the actual number of args */
2432 sp -= child_frame.runtime_method->param_count;
2433 if (child_frame.runtime_method->hasthis) {
2435 MonoObject *this_arg = sp->data.p;
2437 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2439 child_frame.stack_args = sp;
2441 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
2442 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2443 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2446 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2448 context->current_frame = frame;
2450 if (context->has_resume_state) {
2451 if (frame == context->handler_frame)
2452 SET_RESUME_STATE (context);
2457 if (child_frame.ex) {
2459 * An exception occurred, need to run finally, fault and catch handlers..
2461 frame->ex = child_frame.ex;
2462 goto handle_finally;
2467 MINT_IN_CASE(MINT_JIT_CALL) {
2468 MonoMethodSignature *sig;
2469 RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
2470 MonoFtnDesc ftndesc;
2471 guint8 res_buf [256];
2475 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
2478 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2479 * by ref and return a return value using an explicit return value argument.
2481 if (!rmethod->jit_wrapper) {
2482 MonoMethod *method = rmethod->method;
2485 sig = mono_method_signature (method);
2488 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2489 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2491 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
2492 mono_error_assert_ok (&error);
2494 gpointer addr = mono_jit_compile_method_jit_only (method, &error);
2496 mono_error_assert_ok (&error);
2498 rmethod->jit_addr = addr;
2499 rmethod->jit_sig = sig;
2500 mono_memory_barrier ();
2501 rmethod->jit_wrapper = jit_wrapper;
2504 sig = rmethod->jit_sig;
2509 sp -= sig->param_count;
2513 ftndesc.addr = rmethod->jit_addr;
2516 // FIXME: Optimize this
2520 int stack_index = 0;
2521 if (rmethod->hasthis) {
2522 args [pindex ++] = sp [0].data.p;
2525 type = rmethod->rtype;
2526 if (type->type != MONO_TYPE_VOID) {
2527 if (MONO_TYPE_ISSTRUCT (type))
2528 args [pindex ++] = vt_sp;
2530 args [pindex ++] = res_buf;
2532 for (int i = 0; i < rmethod->param_count; ++i) {
2533 MonoType *t = rmethod->param_types [i];
2534 stackval *sval = &sp [stack_index + i];
2535 if (sig->params [i]->byref) {
2536 args [pindex ++] = sval->data.p;
2537 } else if (MONO_TYPE_ISSTRUCT (t)) {
2538 args [pindex ++] = sval->data.p;
2539 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2540 args [pindex ++] = &sval->data.p;
2549 case MONO_TYPE_VALUETYPE:
2550 args [pindex ++] = &sval->data.i;
2553 case MONO_TYPE_FNPTR:
2556 case MONO_TYPE_OBJECT:
2557 args [pindex ++] = &sval->data.p;
2561 args [pindex ++] = &sval->data.l;
2564 printf ("%s\n", mono_type_full_name (t));
2565 g_assert_not_reached ();
2571 * Push an LMF frame on the LMF stack
2572 * to mark the transition to compiled code.
2574 memset (&ext, 0, sizeof (ext));
2575 ext.interp_exit = TRUE;
2576 ext.interp_exit_data = frame;
2578 mono_push_lmf (&ext);
2582 void (*func)(gpointer) = rmethod->jit_wrapper;
2588 void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
2590 func (args [0], &ftndesc);
2594 void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2596 func (args [0], args [1], &ftndesc);
2600 void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2602 func (args [0], args [1], args [2], &ftndesc);
2606 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2608 func (args [0], args [1], args [2], args [3], &ftndesc);
2612 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2614 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2618 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2620 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2624 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2626 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2630 g_assert_not_reached ();
2634 mono_pop_lmf (&ext.lmf);
2636 if (context->has_resume_state) {
2638 * If this bit is set, it means the call has thrown the exception, and we
2639 * reached this point because the EH code in mono_handle_exception ()
2640 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2641 * has set the fields in context to indicate where we have to resume execution.
2643 if (frame == context->handler_frame)
2644 SET_RESUME_STATE (context);
2649 MonoType *rtype = rmethod->rtype;
2650 switch (rtype->type) {
2651 case MONO_TYPE_VOID:
2652 case MONO_TYPE_OBJECT:
2653 case MONO_TYPE_STRING:
2654 case MONO_TYPE_CLASS:
2655 case MONO_TYPE_ARRAY:
2656 case MONO_TYPE_SZARRAY:
2659 sp->data.p = *(gpointer*)res_buf;
2662 sp->data.i = *(gint8*)res_buf;
2665 sp->data.i = *(guint8*)res_buf;
2668 sp->data.i = *(gint16*)res_buf;
2671 sp->data.i = *(guint16*)res_buf;
2674 sp->data.i = *(gint32*)res_buf;
2677 sp->data.i = *(guint32*)res_buf;
2679 case MONO_TYPE_VALUETYPE:
2680 /* The result was written to vt_sp */
2683 case MONO_TYPE_GENERICINST:
2684 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2685 sp->data.p = *(gpointer*)res_buf;
2687 /* The result was written to vt_sp */
2692 printf ("%s\n", mono_type_full_name (rtype));
2693 g_assert_not_reached ();
2696 if (rtype->type != MONO_TYPE_VOID)
2701 MINT_IN_CASE(MINT_CALLVIRT) {
2702 stackval *endsp = sp;
2703 MonoObject *this_arg;
2708 token = * (unsigned short *)(ip + 1);
2710 child_frame.runtime_method = rtm->data_items [token];
2712 child_frame.retval = sp;
2714 /* decrement by the actual number of args */
2715 sp -= child_frame.runtime_method->param_count + 1;
2716 child_frame.stack_args = sp;
2717 this_arg = sp->data.p;
2719 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2720 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2722 MonoClass *this_class = this_arg->vtable->klass;
2723 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2725 gpointer *unboxed = mono_object_unbox (this_arg);
2726 sp [0].data.p = unboxed;
2729 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2731 context->current_frame = frame;
2733 if (context->has_resume_state) {
2734 if (frame == context->handler_frame)
2735 SET_RESUME_STATE (context);
2740 if (child_frame.ex) {
2742 * An exception occurred, need to run finally, fault and catch handlers..
2744 frame->ex = child_frame.ex;
2745 if (context->search_for_handler) {
2746 context->search_for_handler = 0;
2747 goto handle_exception;
2749 goto handle_finally;
2752 /* need to handle typedbyref ... */
2757 MINT_IN_CASE(MINT_VCALLVIRT) {
2758 MonoObject *this_arg;
2763 token = * (unsigned short *)(ip + 1);
2765 child_frame.runtime_method = rtm->data_items [token];
2767 child_frame.retval = sp;
2769 /* decrement by the actual number of args */
2770 sp -= child_frame.runtime_method->param_count + 1;
2771 child_frame.stack_args = sp;
2772 this_arg = sp->data.p;
2774 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2775 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2777 MonoClass *this_class = this_arg->vtable->klass;
2778 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2779 gpointer *unboxed = mono_object_unbox (this_arg);
2780 sp [0].data.p = unboxed;
2783 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2785 context->current_frame = frame;
2787 if (context->has_resume_state) {
2788 if (frame == context->handler_frame)
2789 SET_RESUME_STATE (context);
2794 if (child_frame.ex) {
2796 * An exception occurred, need to run finally, fault and catch handlers..
2798 frame->ex = child_frame.ex;
2799 if (context->search_for_handler) {
2800 context->search_for_handler = 0;
2801 goto handle_exception;
2803 goto handle_finally;
2807 MINT_IN_CASE(MINT_CALLRUN)
2808 ves_runtime_method (frame, context);
2811 goto handle_exception;
2814 MINT_IN_CASE(MINT_RET)
2816 *frame->retval = *sp;
2817 if (sp > frame->stack)
2818 g_warning ("ret: more values on stack: %d", sp-frame->stack);
2820 MINT_IN_CASE(MINT_RET_VOID)
2821 if (sp > frame->stack)
2822 g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
2824 MINT_IN_CASE(MINT_RET_VT)
2825 i32 = READ32(ip + 1);
2827 memcpy(frame->retval->data.p, sp->data.p, i32);
2828 if (sp > frame->stack)
2829 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2831 MINT_IN_CASE(MINT_BR_S)
2832 ip += (short) *(ip + 1);
2834 MINT_IN_CASE(MINT_BR)
2835 ip += (gint32) READ32(ip + 1);
2837 #define ZEROP_S(datamem, op) \
2839 if (sp->data.datamem op 0) \
2840 ip += * (gint16 *)(ip + 1); \
2844 #define ZEROP(datamem, op) \
2846 if (sp->data.datamem op 0) \
2847 ip += READ32(ip + 1); \
2851 MINT_IN_CASE(MINT_BRFALSE_I4_S)
2854 MINT_IN_CASE(MINT_BRFALSE_I8_S)
2857 MINT_IN_CASE(MINT_BRFALSE_R8_S)
2860 MINT_IN_CASE(MINT_BRFALSE_I4)
2863 MINT_IN_CASE(MINT_BRFALSE_I8)
2866 MINT_IN_CASE(MINT_BRFALSE_R8)
2869 MINT_IN_CASE(MINT_BRTRUE_I4_S)
2872 MINT_IN_CASE(MINT_BRTRUE_I8_S)
2875 MINT_IN_CASE(MINT_BRTRUE_R8_S)
2878 MINT_IN_CASE(MINT_BRTRUE_I4)
2881 MINT_IN_CASE(MINT_BRTRUE_I8)
2884 MINT_IN_CASE(MINT_BRTRUE_R8)
2887 #define CONDBR_S(cond) \
2890 ip += * (gint16 *)(ip + 1); \
2893 #define BRELOP_S(datamem, op) \
2894 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2896 #define CONDBR(cond) \
2899 ip += READ32(ip + 1); \
2903 #define BRELOP(datamem, op) \
2904 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2906 MINT_IN_CASE(MINT_BEQ_I4_S)
2909 MINT_IN_CASE(MINT_BEQ_I8_S)
2912 MINT_IN_CASE(MINT_BEQ_R8_S)
2913 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2915 MINT_IN_CASE(MINT_BEQ_I4)
2918 MINT_IN_CASE(MINT_BEQ_I8)
2921 MINT_IN_CASE(MINT_BEQ_R8)
2922 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2924 MINT_IN_CASE(MINT_BGE_I4_S)
2927 MINT_IN_CASE(MINT_BGE_I8_S)
2930 MINT_IN_CASE(MINT_BGE_R8_S)
2931 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2933 MINT_IN_CASE(MINT_BGE_I4)
2936 MINT_IN_CASE(MINT_BGE_I8)
2939 MINT_IN_CASE(MINT_BGE_R8)
2940 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2942 MINT_IN_CASE(MINT_BGT_I4_S)
2945 MINT_IN_CASE(MINT_BGT_I8_S)
2948 MINT_IN_CASE(MINT_BGT_R8_S)
2949 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2951 MINT_IN_CASE(MINT_BGT_I4)
2954 MINT_IN_CASE(MINT_BGT_I8)
2957 MINT_IN_CASE(MINT_BGT_R8)
2958 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2960 MINT_IN_CASE(MINT_BLT_I4_S)
2963 MINT_IN_CASE(MINT_BLT_I8_S)
2966 MINT_IN_CASE(MINT_BLT_R8_S)
2967 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2969 MINT_IN_CASE(MINT_BLT_I4)
2972 MINT_IN_CASE(MINT_BLT_I8)
2975 MINT_IN_CASE(MINT_BLT_R8)
2976 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2978 MINT_IN_CASE(MINT_BLE_I4_S)
2981 MINT_IN_CASE(MINT_BLE_I8_S)
2984 MINT_IN_CASE(MINT_BLE_R8_S)
2985 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2987 MINT_IN_CASE(MINT_BLE_I4)
2990 MINT_IN_CASE(MINT_BLE_I8)
2993 MINT_IN_CASE(MINT_BLE_R8)
2994 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2996 MINT_IN_CASE(MINT_BNE_UN_I4_S)
2999 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3002 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3003 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3005 MINT_IN_CASE(MINT_BNE_UN_I4)
3008 MINT_IN_CASE(MINT_BNE_UN_I8)
3011 MINT_IN_CASE(MINT_BNE_UN_R8)
3012 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3015 #define BRELOP_S_CAST(datamem, op, type) \
3017 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3018 ip += * (gint16 *)(ip + 1); \
3022 #define BRELOP_CAST(datamem, op, type) \
3024 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3025 ip += READ32(ip + 1); \
3029 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3030 BRELOP_S_CAST(i, >=, guint32);
3032 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3033 BRELOP_S_CAST(l, >=, guint64);
3035 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3036 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3038 MINT_IN_CASE(MINT_BGE_UN_I4)
3039 BRELOP_CAST(i, >=, guint32);
3041 MINT_IN_CASE(MINT_BGE_UN_I8)
3042 BRELOP_CAST(l, >=, guint64);
3044 MINT_IN_CASE(MINT_BGE_UN_R8)
3045 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3047 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3048 BRELOP_S_CAST(i, >, guint32);
3050 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3051 BRELOP_S_CAST(l, >, guint64);
3053 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3054 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3056 MINT_IN_CASE(MINT_BGT_UN_I4)
3057 BRELOP_CAST(i, >, guint32);
3059 MINT_IN_CASE(MINT_BGT_UN_I8)
3060 BRELOP_CAST(l, >, guint64);
3062 MINT_IN_CASE(MINT_BGT_UN_R8)
3063 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3065 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3066 BRELOP_S_CAST(i, <=, guint32);
3068 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3069 BRELOP_S_CAST(l, <=, guint64);
3071 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3072 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3074 MINT_IN_CASE(MINT_BLE_UN_I4)
3075 BRELOP_CAST(i, <=, guint32);
3077 MINT_IN_CASE(MINT_BLE_UN_I8)
3078 BRELOP_CAST(l, <=, guint64);
3080 MINT_IN_CASE(MINT_BLE_UN_R8)
3081 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3083 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3084 BRELOP_S_CAST(i, <, guint32);
3086 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3087 BRELOP_S_CAST(l, <, guint64);
3089 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3090 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3092 MINT_IN_CASE(MINT_BLT_UN_I4)
3093 BRELOP_CAST(i, <, guint32);
3095 MINT_IN_CASE(MINT_BLT_UN_I8)
3096 BRELOP_CAST(l, <, guint64);
3098 MINT_IN_CASE(MINT_BLT_UN_R8)
3099 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3101 MINT_IN_CASE(MINT_SWITCH) {
3103 const unsigned short *st;
3109 if ((guint32)sp->data.i < n) {
3111 ip += 2 * (guint32)sp->data.i;
3112 offset = READ32 (ip);
3119 MINT_IN_CASE(MINT_LDIND_I1)
3121 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3123 MINT_IN_CASE(MINT_LDIND_U1)
3125 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3127 MINT_IN_CASE(MINT_LDIND_I2)
3129 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3131 MINT_IN_CASE(MINT_LDIND_U2)
3133 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3135 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3136 MINT_IN_CASE(MINT_LDIND_U4)
3138 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3140 MINT_IN_CASE(MINT_LDIND_I8)
3142 sp[-1].data.l = *(gint64*)sp[-1].data.p;
3144 MINT_IN_CASE(MINT_LDIND_I) {
3145 guint16 offset = * (guint16 *)(ip + 1);
3146 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3150 MINT_IN_CASE(MINT_LDIND_R4)
3152 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3154 MINT_IN_CASE(MINT_LDIND_R8)
3156 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3158 MINT_IN_CASE(MINT_LDIND_REF)
3160 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3162 MINT_IN_CASE(MINT_STIND_REF)
3165 mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
3167 MINT_IN_CASE(MINT_STIND_I1)
3170 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3172 MINT_IN_CASE(MINT_STIND_I2)
3175 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3177 MINT_IN_CASE(MINT_STIND_I4)
3180 * (gint32 *) sp->data.p = sp[1].data.i;
3182 MINT_IN_CASE(MINT_STIND_I)
3185 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3187 MINT_IN_CASE(MINT_STIND_I8)
3190 * (gint64 *) sp->data.p = sp[1].data.l;
3192 MINT_IN_CASE(MINT_STIND_R4)
3195 * (float *) sp->data.p = (gfloat)sp[1].data.f;
3197 MINT_IN_CASE(MINT_STIND_R8)
3200 * (double *) sp->data.p = sp[1].data.f;
3202 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3205 InterlockedWrite ((gint32 *) sp->data.p, sp [1].data.i);
3207 #define BINOP(datamem, op) \
3209 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3211 MINT_IN_CASE(MINT_ADD_I4)
3214 MINT_IN_CASE(MINT_ADD_I8)
3217 MINT_IN_CASE(MINT_ADD_R8)
3220 MINT_IN_CASE(MINT_ADD1_I4)
3224 MINT_IN_CASE(MINT_SUB_I4)
3227 MINT_IN_CASE(MINT_SUB_I8)
3230 MINT_IN_CASE(MINT_SUB_R8)
3233 MINT_IN_CASE(MINT_SUB1_I4)
3237 MINT_IN_CASE(MINT_MUL_I4)
3240 MINT_IN_CASE(MINT_MUL_I8)
3243 MINT_IN_CASE(MINT_MUL_R8)
3246 MINT_IN_CASE(MINT_DIV_I4)
3247 if (sp [-1].data.i == 0)
3248 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3249 if (sp [-1].data.i == (-1))
3250 THROW_EX (mono_get_exception_overflow (), ip);
3253 MINT_IN_CASE(MINT_DIV_I8)
3254 if (sp [-1].data.l == 0)
3255 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3256 if (sp [-1].data.l == (-1))
3257 THROW_EX (mono_get_exception_overflow (), ip);
3260 MINT_IN_CASE(MINT_DIV_R8)
3264 #define BINOP_CAST(datamem, op, type) \
3266 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3268 MINT_IN_CASE(MINT_DIV_UN_I4)
3269 if (sp [-1].data.i == 0)
3270 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3271 BINOP_CAST(i, /, guint32);
3273 MINT_IN_CASE(MINT_DIV_UN_I8)
3274 if (sp [-1].data.l == 0)
3275 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3276 BINOP_CAST(l, /, guint64);
3278 MINT_IN_CASE(MINT_REM_I4)
3279 if (sp [-1].data.i == 0)
3280 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3281 if (sp [-1].data.i == (-1))
3282 THROW_EX (mono_get_exception_overflow (), ip);
3285 MINT_IN_CASE(MINT_REM_I8)
3286 if (sp [-1].data.l == 0)
3287 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3288 if (sp [-1].data.l == (-1))
3289 THROW_EX (mono_get_exception_overflow (), ip);
3292 MINT_IN_CASE(MINT_REM_R8)
3293 /* FIXME: what do we actually do here? */
3295 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3298 MINT_IN_CASE(MINT_REM_UN_I4)
3299 if (sp [-1].data.i == 0)
3300 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3301 BINOP_CAST(i, %, guint32);
3303 MINT_IN_CASE(MINT_REM_UN_I8)
3304 if (sp [-1].data.l == 0)
3305 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3306 BINOP_CAST(l, %, guint64);
3308 MINT_IN_CASE(MINT_AND_I4)
3311 MINT_IN_CASE(MINT_AND_I8)
3314 MINT_IN_CASE(MINT_OR_I4)
3317 MINT_IN_CASE(MINT_OR_I8)
3320 MINT_IN_CASE(MINT_XOR_I4)
3323 MINT_IN_CASE(MINT_XOR_I8)
3327 #define SHIFTOP(datamem, op) \
3329 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3332 MINT_IN_CASE(MINT_SHL_I4)
3335 MINT_IN_CASE(MINT_SHL_I8)
3338 MINT_IN_CASE(MINT_SHR_I4)
3341 MINT_IN_CASE(MINT_SHR_I8)
3344 MINT_IN_CASE(MINT_SHR_UN_I4)
3346 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3349 MINT_IN_CASE(MINT_SHR_UN_I8)
3351 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3354 MINT_IN_CASE(MINT_NEG_I4)
3355 sp [-1].data.i = - sp [-1].data.i;
3358 MINT_IN_CASE(MINT_NEG_I8)
3359 sp [-1].data.l = - sp [-1].data.l;
3362 MINT_IN_CASE(MINT_NEG_R8)
3363 sp [-1].data.f = - sp [-1].data.f;
3366 MINT_IN_CASE(MINT_NOT_I4)
3367 sp [-1].data.i = ~ sp [-1].data.i;
3370 MINT_IN_CASE(MINT_NOT_I8)
3371 sp [-1].data.l = ~ sp [-1].data.l;
3374 MINT_IN_CASE(MINT_CONV_I1_I4)
3375 sp [-1].data.i = (gint8)sp [-1].data.i;
3378 MINT_IN_CASE(MINT_CONV_I1_I8)
3379 sp [-1].data.i = (gint8)sp [-1].data.l;
3382 MINT_IN_CASE(MINT_CONV_I1_R8)
3383 sp [-1].data.i = (gint8)sp [-1].data.f;
3386 MINT_IN_CASE(MINT_CONV_U1_I4)
3387 sp [-1].data.i = (guint8)sp [-1].data.i;
3390 MINT_IN_CASE(MINT_CONV_U1_I8)
3391 sp [-1].data.i = (guint8)sp [-1].data.l;
3394 MINT_IN_CASE(MINT_CONV_U1_R8)
3395 sp [-1].data.i = (guint8)sp [-1].data.f;
3398 MINT_IN_CASE(MINT_CONV_I2_I4)
3399 sp [-1].data.i = (gint16)sp [-1].data.i;
3402 MINT_IN_CASE(MINT_CONV_I2_I8)
3403 sp [-1].data.i = (gint16)sp [-1].data.l;
3406 MINT_IN_CASE(MINT_CONV_I2_R8)
3407 sp [-1].data.i = (gint16)sp [-1].data.f;
3410 MINT_IN_CASE(MINT_CONV_U2_I4)
3411 sp [-1].data.i = (guint16)sp [-1].data.i;
3414 MINT_IN_CASE(MINT_CONV_U2_I8)
3415 sp [-1].data.i = (guint16)sp [-1].data.l;
3418 MINT_IN_CASE(MINT_CONV_U2_R8)
3419 sp [-1].data.i = (guint16)sp [-1].data.f;
3422 MINT_IN_CASE(MINT_CONV_I4_R8)
3423 sp [-1].data.i = (gint32)sp [-1].data.f;
3426 MINT_IN_CASE(MINT_CONV_U4_I8)
3427 MINT_IN_CASE(MINT_CONV_I4_I8)
3428 sp [-1].data.i = (gint32)sp [-1].data.l;
3431 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3432 sp [-2].data.i = (gint32)sp [-2].data.l;
3435 MINT_IN_CASE(MINT_CONV_U4_R8)
3436 /* needed on arm64 */
3437 if (isinf (sp [-1].data.f))
3440 sp [-1].data.i = (guint32)sp [-1].data.f;
3443 MINT_IN_CASE(MINT_CONV_I8_I4)
3444 sp [-1].data.l = sp [-1].data.i;
3447 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3448 sp [-2].data.l = sp [-2].data.i;
3451 MINT_IN_CASE(MINT_CONV_I8_U4)
3452 sp [-1].data.l = (guint32)sp [-1].data.i;
3455 MINT_IN_CASE(MINT_CONV_I8_R8)
3456 sp [-1].data.l = (gint64)sp [-1].data.f;
3459 MINT_IN_CASE(MINT_CONV_R4_I4)
3460 sp [-1].data.f = (float)sp [-1].data.i;
3463 MINT_IN_CASE(MINT_CONV_R4_I8)
3464 sp [-1].data.f = (float)sp [-1].data.l;
3467 MINT_IN_CASE(MINT_CONV_R4_R8)
3468 sp [-1].data.f = (float)sp [-1].data.f;
3471 MINT_IN_CASE(MINT_CONV_R8_I4)
3472 sp [-1].data.f = (double)sp [-1].data.i;
3475 MINT_IN_CASE(MINT_CONV_R8_I8)
3476 sp [-1].data.f = (double)sp [-1].data.l;
3479 MINT_IN_CASE(MINT_CONV_U8_I4)
3480 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3483 MINT_IN_CASE(MINT_CONV_U8_R8)
3484 sp [-1].data.l = (guint64)sp [-1].data.f;
3487 MINT_IN_CASE(MINT_CPOBJ) {
3488 c = rtm->data_items[* (guint16 *)(ip + 1)];
3489 g_assert (c->valuetype);
3490 /* if this assertion fails, we need to add a write barrier */
3491 g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
3492 if (c->byval_arg.type == MONO_TYPE_VALUETYPE)
3493 stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
3495 stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
3500 MINT_IN_CASE(MINT_LDOBJ) {
3502 c = rtm->data_items[* (guint16 *)(ip + 1)];
3505 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
3506 int size = mono_class_value_size (c, NULL);
3507 sp [-1].data.p = vt_sp;
3508 vt_sp += (size + 7) & ~7;
3510 stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
3513 MINT_IN_CASE(MINT_LDSTR)
3514 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3518 MINT_IN_CASE(MINT_NEWOBJ) {
3519 MonoClass *newobj_class;
3520 MonoMethodSignature *csig;
3521 stackval valuetype_this;
3527 token = * (guint16 *)(ip + 1);
3530 child_frame.ip = NULL;
3531 child_frame.ex = NULL;
3533 child_frame.runtime_method = rtm->data_items [token];
3534 csig = mono_method_signature (child_frame.runtime_method->method);
3535 newobj_class = child_frame.runtime_method->method->klass;
3536 /*if (profiling_classes) {
3537 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3539 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3542 if (newobj_class->parent == mono_defaults.array_class) {
3543 sp -= csig->param_count;
3544 child_frame.stack_args = sp;
3545 o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
3547 THROW_EX (child_frame.ex, ip);
3548 goto array_constructed;
3551 g_assert (csig->hasthis);
3552 if (csig->param_count) {
3553 sp -= csig->param_count;
3554 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3556 child_frame.stack_args = sp;
3559 * First arg is the object.
3561 if (newobj_class->valuetype) {
3562 MonoType *t = &newobj_class->byval_arg;
3563 memset (&valuetype_this, 0, sizeof (stackval));
3564 if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3566 valuetype_this.data.p = vt_sp;
3568 sp->data.p = &valuetype_this;
3571 if (newobj_class != mono_defaults.string_class) {
3572 context->managed_code = 0;
3573 o = mono_object_new_checked (context->domain, newobj_class, &error);
3574 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3575 context->managed_code = 1;
3576 if (*mono_thread_interruption_request_flag ())
3577 mono_thread_interruption_checkpoint ();
3581 child_frame.retval = &retval;
3585 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3587 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
3589 context->current_frame = frame;
3591 if (context->has_resume_state) {
3592 if (frame == context->handler_frame)
3593 SET_RESUME_STATE (context);
3598 if (child_frame.ex) {
3600 * An exception occurred, need to run finally, fault and catch handlers..
3602 frame->ex = child_frame.ex;
3603 goto handle_finally;
3606 * a constructor returns void, but we need to return the object we created
3609 if (newobj_class->valuetype && !newobj_class->enumtype) {
3610 *sp = valuetype_this;
3611 } else if (newobj_class == mono_defaults.string_class) {
3619 MINT_IN_CASE(MINT_CASTCLASS)
3620 c = rtm->data_items [*(guint16 *)(ip + 1)];
3621 if ((o = sp [-1].data.p)) {
3622 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3623 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3625 THROW_EX (mono_get_exception_invalid_cast (), ip);
3629 MINT_IN_CASE(MINT_ISINST)
3630 c = rtm->data_items [*(guint16 *)(ip + 1)];
3631 if ((o = sp [-1].data.p)) {
3632 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3633 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3635 sp [-1].data.p = NULL;
3639 MINT_IN_CASE(MINT_CONV_R_UN_I4)
3640 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3643 MINT_IN_CASE(MINT_CONV_R_UN_I8)
3644 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3647 MINT_IN_CASE(MINT_UNBOX)
3648 c = rtm->data_items[*(guint16 *)(ip + 1)];
3652 THROW_EX (mono_get_exception_null_reference (), ip);
3654 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3655 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3656 if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
3657 THROW_EX (mono_get_exception_invalid_cast (), ip);
3659 sp [-1].data.p = mono_object_unbox (o);
3662 MINT_IN_CASE(MINT_THROW)
3664 frame->ex_handler = NULL;
3666 sp->data.p = mono_get_exception_null_reference ();
3667 THROW_EX ((MonoException *)sp->data.p, ip);
3669 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
3671 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3674 MINT_IN_CASE(MINT_LDFLDA)
3677 THROW_EX (mono_get_exception_null_reference (), ip);
3678 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3681 MINT_IN_CASE(MINT_CKNULL)
3684 THROW_EX (mono_get_exception_null_reference (), ip);
3688 #define LDFLD(datamem, fieldtype) \
3689 o = sp [-1].data.p; \
3691 THROW_EX (mono_get_exception_null_reference (), ip); \
3692 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3695 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
3696 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
3697 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
3698 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
3699 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
3700 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
3701 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
3702 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
3703 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
3704 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
3706 MINT_IN_CASE(MINT_LDFLD_VT)
3709 THROW_EX (mono_get_exception_null_reference (), ip);
3710 i32 = READ32(ip + 2);
3711 sp [-1].data.p = vt_sp;
3712 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3713 vt_sp += (i32 + 7) & ~7;
3717 MINT_IN_CASE(MINT_LDRMFLD) {
3719 MonoClassField *field;
3724 THROW_EX (mono_get_exception_null_reference (), ip);
3725 field = rtm->data_items[* (guint16 *)(ip + 1)];
3727 if (mono_object_is_transparent_proxy (o)) {
3728 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3730 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3731 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3733 addr = (char*)o + field->offset;
3736 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3740 MINT_IN_CASE(MINT_LDRMFLD_VT) {
3741 MonoClassField *field;
3747 THROW_EX (mono_get_exception_null_reference (), ip);
3748 field = rtm->data_items[* (guint16 *)(ip + 1)];
3749 i32 = READ32(ip + 2);
3751 if (mono_object_is_transparent_proxy (o)) {
3752 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3753 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3754 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3756 addr = (char*)o + field->offset;
3759 sp [-1].data.p = vt_sp;
3760 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3761 vt_sp += (i32 + 7) & ~7;
3762 memcpy(sp [-1].data.p, addr, i32);
3766 #define STFLD(datamem, fieldtype) \
3767 o = sp [-2].data.p; \
3769 THROW_EX (mono_get_exception_null_reference (), ip); \
3771 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3774 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3775 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3776 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3777 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3778 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3779 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3780 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3781 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3782 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3783 MINT_IN_CASE(MINT_STFLD_O)
3786 THROW_EX (mono_get_exception_null_reference (), ip);
3788 mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
3792 MINT_IN_CASE(MINT_STFLD_VT)
3795 THROW_EX (mono_get_exception_null_reference (), ip);
3796 i32 = READ32(ip + 2);
3798 memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32);
3799 vt_sp -= (i32 + 7) & ~7;
3803 MINT_IN_CASE(MINT_STRMFLD) {
3804 MonoClassField *field;
3808 THROW_EX (mono_get_exception_null_reference (), ip);
3810 field = rtm->data_items[* (guint16 *)(ip + 1)];
3813 if (mono_object_is_transparent_proxy (o)) {
3814 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3815 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3816 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3818 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3823 MINT_IN_CASE(MINT_STRMFLD_VT) {
3824 MonoClassField *field;
3828 THROW_EX (mono_get_exception_null_reference (), ip);
3829 field = rtm->data_items[* (guint16 *)(ip + 1)];
3830 i32 = READ32(ip + 2);
3833 if (mono_object_is_transparent_proxy (o)) {
3834 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3835 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3836 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3838 memcpy((char*)o + field->offset, sp [-1].data.p, i32);
3841 vt_sp -= (i32 + 7) & ~7;
3844 MINT_IN_CASE(MINT_LDSFLDA) {
3845 MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3846 sp->data.p = mono_class_static_field_address (context->domain, field);
3851 MINT_IN_CASE(MINT_LDSFLD) {
3852 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3853 gpointer addr = mono_class_static_field_address (context->domain, field);
3854 stackval_from_data (field->type, sp, addr, FALSE);
3859 MINT_IN_CASE(MINT_LDSFLD_VT) {
3860 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3861 gpointer addr = mono_class_static_field_address (context->domain, field);
3862 int size = READ32 (ip + 2);
3866 vt_sp += (size + 7) & ~7;
3867 stackval_from_data (field->type, sp, addr, FALSE);
3871 MINT_IN_CASE(MINT_STSFLD) {
3872 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3873 gpointer addr = mono_class_static_field_address (context->domain, field);
3876 stackval_to_data (field->type, sp, addr, FALSE);
3879 MINT_IN_CASE(MINT_STSFLD_VT) {
3880 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3881 gpointer addr = mono_class_static_field_address (context->domain, field);
3882 int size = READ32 (ip + 2);
3886 stackval_to_data (field->type, sp, addr, FALSE);
3887 vt_sp -= (size + 7) & ~7;
3890 MINT_IN_CASE(MINT_STOBJ_VT) {
3892 c = rtm->data_items[* (guint16 *)(ip + 1)];
3894 size = mono_class_value_size (c, NULL);
3895 memcpy(sp [-2].data.p, sp [-1].data.p, size);
3896 vt_sp -= (size + 7) & ~7;
3900 MINT_IN_CASE(MINT_STOBJ) {
3901 c = rtm->data_items[* (guint16 *)(ip + 1)];
3904 g_assert (!c->byval_arg.byref);
3905 if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
3906 mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
3908 stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
3912 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3913 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3914 THROW_EX (mono_get_exception_overflow (), ip);
3915 sp [-1].data.i = (guint32)sp [-1].data.f;
3918 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3919 if (sp [-1].data.i < 0)
3920 THROW_EX (mono_get_exception_overflow (), ip);
3921 sp [-1].data.l = sp [-1].data.i;
3924 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
3925 if (sp [-1].data.l < 0)
3926 THROW_EX (mono_get_exception_overflow (), ip);
3929 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
3930 if ((guint64) sp [-1].data.l > MYGINT64_MAX)
3931 THROW_EX (mono_get_exception_overflow (), ip);
3934 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
3935 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
3936 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
3937 THROW_EX (mono_get_exception_overflow (), ip);
3938 sp [-1].data.l = (guint64)sp [-1].data.f;
3941 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
3942 if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
3943 THROW_EX (mono_get_exception_overflow (), ip);
3944 sp [-1].data.l = (gint64)sp [-1].data.f;
3947 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
3948 if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
3949 THROW_EX (mono_get_exception_overflow (), ip);
3950 sp [-1].data.i = (mono_u)sp [-1].data.l;
3953 MINT_IN_CASE(MINT_BOX) {
3954 c = rtm->data_items [* (guint16 *)(ip + 1)];
3955 guint16 offset = * (guint16 *)(ip + 2);
3957 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
3958 int size = mono_class_value_size (c, NULL);
3959 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error);
3960 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3961 size = (size + 7) & ~7;
3964 stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
3965 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error);
3966 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3971 MINT_IN_CASE(MINT_NEWARR)
3972 sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
3973 if (!mono_error_ok (&error)) {
3974 THROW_EX (mono_error_convert_to_exception (&error), ip);
3976 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3978 /*if (profiling_classes) {
3979 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3981 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3985 MINT_IN_CASE(MINT_LDLEN)
3988 THROW_EX (mono_get_exception_null_reference (), ip);
3989 sp [-1].data.nati = mono_array_length ((MonoArray *)o);
3992 MINT_IN_CASE(MINT_GETCHR) {
3996 THROW_EX (mono_get_exception_null_reference (), ip);
3997 i32 = sp [-1].data.i;
3998 if (i32 < 0 || i32 >= mono_string_length (s))
3999 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4001 sp [-1].data.i = mono_string_chars(s)[i32];
4005 MINT_IN_CASE(MINT_STRLEN)
4009 THROW_EX (mono_get_exception_null_reference (), ip);
4010 sp [-1].data.i = mono_string_length ((MonoString*) o);
4012 MINT_IN_CASE(MINT_ARRAY_RANK)
4015 THROW_EX (mono_get_exception_null_reference (), ip);
4016 sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
4019 MINT_IN_CASE(MINT_LDELEMA)
4020 MINT_IN_CASE(MINT_LDELEMA_TC) {
4021 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
4023 MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
4024 guint16 numargs = *(guint16 *) (ip + 2);
4029 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
4031 THROW_EX (frame->ex, ip);
4036 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4037 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4038 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4039 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4040 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4041 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4042 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
4043 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
4044 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4045 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4046 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4047 MINT_IN_CASE(MINT_LDELEM_VT) {
4055 THROW_EX (mono_get_exception_null_reference (), ip);
4057 aindex = sp [1].data.i;
4058 if (aindex >= mono_array_length (o))
4059 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4062 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4065 case MINT_LDELEM_I1:
4066 sp [0].data.i = mono_array_get (o, gint8, aindex);
4068 case MINT_LDELEM_U1:
4069 sp [0].data.i = mono_array_get (o, guint8, aindex);
4071 case MINT_LDELEM_I2:
4072 sp [0].data.i = mono_array_get (o, gint16, aindex);
4074 case MINT_LDELEM_U2:
4075 sp [0].data.i = mono_array_get (o, guint16, aindex);
4078 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
4080 case MINT_LDELEM_I4:
4081 sp [0].data.i = mono_array_get (o, gint32, aindex);
4083 case MINT_LDELEM_U4:
4084 sp [0].data.i = mono_array_get (o, guint32, aindex);
4086 case MINT_LDELEM_I8:
4087 sp [0].data.l = mono_array_get (o, guint64, aindex);
4089 case MINT_LDELEM_R4:
4090 sp [0].data.f = mono_array_get (o, float, aindex);
4092 case MINT_LDELEM_R8:
4093 sp [0].data.f = mono_array_get (o, double, aindex);
4095 case MINT_LDELEM_REF:
4096 sp [0].data.p = mono_array_get (o, gpointer, aindex);
4098 case MINT_LDELEM_VT: {
4099 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4100 i32 = READ32 (ip + 2);
4101 char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4102 sp [0].data.vt = vt_sp;
4103 stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
4104 vt_sp += (i32 + 7) & ~7;
4116 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
4117 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4118 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4119 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4120 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4121 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4122 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4123 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4124 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4125 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4126 MINT_IN_CASE(MINT_STELEM_VT) {
4133 THROW_EX (mono_get_exception_null_reference (), ip);
4135 aindex = sp [1].data.i;
4136 if (aindex >= mono_array_length ((MonoArray *)o))
4137 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4141 mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4143 case MINT_STELEM_I1:
4144 mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4146 case MINT_STELEM_U1:
4147 mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4149 case MINT_STELEM_I2:
4150 mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4152 case MINT_STELEM_U2:
4153 mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4155 case MINT_STELEM_I4:
4156 mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4158 case MINT_STELEM_I8:
4159 mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4161 case MINT_STELEM_R4:
4162 mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
4164 case MINT_STELEM_R8:
4165 mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
4167 case MINT_STELEM_REF: {
4168 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error);
4169 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4170 if (sp [2].data.p && !isinst_obj)
4171 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4172 mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
4175 case MINT_STELEM_VT: {
4176 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4177 i32 = READ32 (ip + 2);
4178 char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4180 stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
4181 vt_sp -= (i32 + 7) & ~7;
4192 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4193 if (sp [-1].data.i < 0)
4194 THROW_EX (mono_get_exception_overflow (), ip);
4197 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4198 if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
4199 THROW_EX (mono_get_exception_overflow (), ip);
4200 sp [-1].data.i = (gint32) sp [-1].data.l;
4203 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4204 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
4205 THROW_EX (mono_get_exception_overflow (), ip);
4206 sp [-1].data.i = (gint32) sp [-1].data.l;
4209 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4210 if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
4211 THROW_EX (mono_get_exception_overflow (), ip);
4212 sp [-1].data.i = (gint32) sp [-1].data.f;
4215 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4216 if (sp [-1].data.i < 0)
4217 THROW_EX (mono_get_exception_overflow (), ip);
4220 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4221 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
4222 THROW_EX (mono_get_exception_overflow (), ip);
4223 sp [-1].data.i = (guint32) sp [-1].data.l;
4226 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4227 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
4228 THROW_EX (mono_get_exception_overflow (), ip);
4229 sp [-1].data.i = (guint32) sp [-1].data.f;
4232 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4233 if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
4234 THROW_EX (mono_get_exception_overflow (), ip);
4237 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4238 if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
4239 THROW_EX (mono_get_exception_overflow (), ip);
4240 sp [-1].data.i = (gint16) sp [-1].data.l;
4243 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4244 if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
4245 THROW_EX (mono_get_exception_overflow (), ip);
4246 sp [-1].data.i = (gint16) sp [-1].data.f;
4249 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4250 if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
4251 THROW_EX (mono_get_exception_overflow (), ip);
4254 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4255 if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
4256 THROW_EX (mono_get_exception_overflow (), ip);
4257 sp [-1].data.i = (guint16) sp [-1].data.l;
4260 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4261 if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
4262 THROW_EX (mono_get_exception_overflow (), ip);
4263 sp [-1].data.i = (guint16) sp [-1].data.f;
4266 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4267 if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
4268 THROW_EX (mono_get_exception_overflow (), ip);
4271 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4272 if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
4273 THROW_EX (mono_get_exception_overflow (), ip);
4274 sp [-1].data.i = (gint8) sp [-1].data.l;
4277 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4278 if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
4279 THROW_EX (mono_get_exception_overflow (), ip);
4280 sp [-1].data.i = (gint8) sp [-1].data.f;
4283 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4284 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
4285 THROW_EX (mono_get_exception_overflow (), ip);
4288 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4289 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
4290 THROW_EX (mono_get_exception_overflow (), ip);
4291 sp [-1].data.i = (guint8) sp [-1].data.l;
4294 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4295 if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
4296 THROW_EX (mono_get_exception_overflow (), ip);
4297 sp [-1].data.i = (guint8) sp [-1].data.f;
4301 MINT_IN_CASE(MINT_LDELEM)
4302 MINT_IN_CASE(MINT_STELEM)
4303 MINT_IN_CASE(MINT_UNBOX_ANY)
4305 MINT_IN_CASE(MINT_CKFINITE)
4306 if (!isfinite(sp [-1].data.f))
4307 THROW_EX (mono_get_exception_arithmetic (), ip);
4310 MINT_IN_CASE(MINT_MKREFANY) {
4311 c = rtm->data_items [*(guint16 *)(ip + 1)];
4313 /* The value address is on the stack */
4314 gpointer addr = sp [-1].data.p;
4315 /* Push the typedref value on the stack */
4316 sp [-1].data.p = vt_sp;
4317 vt_sp += sizeof (MonoTypedRef);
4319 MonoTypedRef *tref = sp [-1].data.p;
4321 tref->type = &c->byval_arg;
4327 MINT_IN_CASE(MINT_REFANYTYPE) {
4328 MonoTypedRef *tref = sp [-1].data.p;
4329 MonoType *type = tref->type;
4331 vt_sp -= sizeof (MonoTypedRef);
4332 sp [-1].data.p = vt_sp;
4334 *(gpointer*)sp [-1].data.p = type;
4338 MINT_IN_CASE(MINT_REFANYVAL) {
4339 MonoTypedRef *tref = sp [-1].data.p;
4340 gpointer addr = tref->value;
4342 vt_sp -= sizeof (MonoTypedRef);
4344 sp [-1].data.p = addr;
4348 MINT_IN_CASE(MINT_LDTOKEN)
4351 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4355 MINT_IN_CASE(MINT_ADD_OVF_I4)
4356 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4357 THROW_EX (mono_get_exception_overflow (), ip);
4360 MINT_IN_CASE(MINT_ADD_OVF_I8)
4361 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4362 THROW_EX (mono_get_exception_overflow (), ip);
4365 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4366 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4367 THROW_EX (mono_get_exception_overflow (), ip);
4368 BINOP_CAST(i, +, guint32);
4370 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4371 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4372 THROW_EX (mono_get_exception_overflow (), ip);
4373 BINOP_CAST(l, +, guint64);
4375 MINT_IN_CASE(MINT_MUL_OVF_I4)
4376 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4377 THROW_EX (mono_get_exception_overflow (), ip);
4380 MINT_IN_CASE(MINT_MUL_OVF_I8)
4381 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4382 THROW_EX (mono_get_exception_overflow (), ip);
4385 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4386 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4387 THROW_EX (mono_get_exception_overflow (), ip);
4388 BINOP_CAST(i, *, guint32);
4390 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4391 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4392 THROW_EX (mono_get_exception_overflow (), ip);
4393 BINOP_CAST(l, *, guint64);
4395 MINT_IN_CASE(MINT_SUB_OVF_I4)
4396 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4397 THROW_EX (mono_get_exception_overflow (), ip);
4400 MINT_IN_CASE(MINT_SUB_OVF_I8)
4401 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4402 THROW_EX (mono_get_exception_overflow (), ip);
4405 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4406 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4407 THROW_EX (mono_get_exception_overflow (), ip);
4408 BINOP_CAST(i, -, guint32);
4410 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4411 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4412 THROW_EX (mono_get_exception_overflow (), ip);
4413 BINOP_CAST(l, -, guint64);
4415 MINT_IN_CASE(MINT_ENDFINALLY)
4417 int clause_index = *ip;
4418 if (clause_index == exit_at_finally)
4420 while (sp > frame->stack) {
4424 ip = finally_ips->data;
4425 finally_ips = g_slist_remove (finally_ips, ip);
4432 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4433 MINT_IN_CASE(MINT_LEAVE_S)
4434 while (sp > frame->stack) {
4438 if (*ip == MINT_LEAVE_S) {
4439 ip += (short) *(ip + 1);
4441 ip += (gint32) READ32 (ip + 1);
4444 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4445 frame->ex_handler = NULL;
4448 goto handle_finally;
4450 MINT_IN_CASE(MINT_ICALL_V_V)
4451 MINT_IN_CASE(MINT_ICALL_V_P)
4452 MINT_IN_CASE(MINT_ICALL_P_V)
4453 MINT_IN_CASE(MINT_ICALL_P_P)
4454 MINT_IN_CASE(MINT_ICALL_PP_V)
4455 MINT_IN_CASE(MINT_ICALL_PI_V)
4456 MINT_IN_CASE(MINT_ICALL_PP_P)
4457 MINT_IN_CASE(MINT_ICALL_PI_P)
4458 MINT_IN_CASE(MINT_ICALL_PPP_V)
4459 MINT_IN_CASE(MINT_ICALL_PPI_V)
4460 sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
4461 if (*mono_thread_interruption_request_flag ()) {
4462 MonoException *exc = mono_thread_interruption_checkpoint ();
4465 context->search_for_handler = 1;
4468 if (frame->ex != NULL)
4469 goto handle_exception;
4472 MINT_IN_CASE(MINT_MONO_LDPTR)
4473 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
4477 MINT_IN_CASE(MINT_MONO_NEWOBJ)
4478 sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
4479 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4483 MINT_IN_CASE(MINT_MONO_FREE)
4486 g_error ("that doesn't seem right");
4487 g_free (sp->data.p);
4489 MINT_IN_CASE(MINT_MONO_RETOBJ)
4492 stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p,
4493 mono_method_signature (frame->runtime_method->method)->pinvoke);
4494 if (sp > frame->stack)
4495 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
4497 MINT_IN_CASE(MINT_MONO_TLS) {
4498 MonoTlsKey key = *(gint32 *)(ip + 1);
4499 sp->data.p = ((gpointer (*)()) mono_tls_get_tls_getter (key, FALSE)) ();
4504 MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
4507 context->original_domain = NULL;
4508 MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4509 gpointer tls_jit = ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4511 if (tls_domain != context->domain || !tls_jit)
4512 context->original_domain = mono_jit_thread_attach (context->domain);
4515 MINT_IN_CASE(MINT_MONO_JIT_DETACH)
4517 mono_jit_set_domain (context->original_domain);
4520 #define RELOP(datamem, op) \
4522 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4524 MINT_IN_CASE(MINT_CEQ_I4)
4527 MINT_IN_CASE(MINT_CEQ0_I4)
4528 sp [-1].data.i = (sp [-1].data.i == 0);
4531 MINT_IN_CASE(MINT_CEQ_I8)
4534 MINT_IN_CASE(MINT_CEQ_R8)
4536 if (isunordered (sp [-1].data.f, sp [0].data.f))
4539 sp [-1].data.i = sp [-1].data.f == sp [0].data.f;
4542 MINT_IN_CASE(MINT_CGT_I4)
4545 MINT_IN_CASE(MINT_CGT_I8)
4548 MINT_IN_CASE(MINT_CGT_R8)
4550 if (isunordered (sp [-1].data.f, sp [0].data.f))
4553 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
4557 #define RELOP_CAST(datamem, op, type) \
4559 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4562 MINT_IN_CASE(MINT_CGT_UN_I4)
4563 RELOP_CAST(i, >, guint32);
4565 MINT_IN_CASE(MINT_CGT_UN_I8)
4566 RELOP_CAST(l, >, guint64);
4568 MINT_IN_CASE(MINT_CGT_UN_R8)
4570 if (isunordered (sp [-1].data.f, sp [0].data.f))
4573 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
4576 MINT_IN_CASE(MINT_CLT_I4)
4579 MINT_IN_CASE(MINT_CLT_I8)
4582 MINT_IN_CASE(MINT_CLT_R8)
4584 if (isunordered (sp [-1].data.f, sp [0].data.f))
4587 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
4590 MINT_IN_CASE(MINT_CLT_UN_I4)
4591 RELOP_CAST(i, <, guint32);
4593 MINT_IN_CASE(MINT_CLT_UN_I8)
4594 RELOP_CAST(l, <, guint64);
4596 MINT_IN_CASE(MINT_CLT_UN_R8)
4598 if (isunordered (sp [-1].data.f, sp [0].data.f))
4601 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
4604 MINT_IN_CASE(MINT_LDFTN) {
4605 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4610 MINT_IN_CASE(MINT_LDVIRTFTN) {
4611 RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
4615 THROW_EX (mono_get_exception_null_reference (), ip - 2);
4617 sp->data.p = get_virtual_method (context->domain, m, sp->data.p);
4622 #define LDARG(datamem, argtype) \
4623 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4627 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
4628 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
4629 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
4630 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
4631 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
4632 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
4633 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
4634 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
4635 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
4636 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
4638 MINT_IN_CASE(MINT_LDARG_VT)
4640 i32 = READ32(ip + 2);
4641 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
4642 vt_sp += (i32 + 7) & ~7;
4647 #define STARG(datamem, argtype) \
4649 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4652 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
4653 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
4654 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
4655 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
4656 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
4657 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
4658 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
4659 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
4660 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
4661 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
4663 MINT_IN_CASE(MINT_STARG_VT)
4664 i32 = READ32(ip + 2);
4666 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
4667 vt_sp -= (i32 + 7) & ~7;
4671 #define STINARG(datamem, argtype) \
4673 int n = * (guint16 *)(ip + 1); \
4674 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4678 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
4679 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
4680 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
4681 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
4682 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
4683 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
4684 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
4685 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
4686 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
4687 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
4689 MINT_IN_CASE(MINT_STINARG_VT) {
4690 int n = * (guint16 *)(ip + 1);
4691 i32 = READ32(ip + 2);
4692 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
4697 MINT_IN_CASE(MINT_LDARGA)
4698 sp->data.p = frame->args + * (guint16 *)(ip + 1);
4703 #define LDLOC(datamem, argtype) \
4704 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4708 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
4709 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
4710 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
4711 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
4712 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
4713 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
4714 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
4715 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
4716 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
4717 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
4719 MINT_IN_CASE(MINT_LDLOC_VT)
4721 i32 = READ32(ip + 2);
4722 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
4723 vt_sp += (i32 + 7) & ~7;
4728 MINT_IN_CASE(MINT_LDLOCA_S)
4729 sp->data.p = locals + * (guint16 *)(ip + 1);
4734 #define STLOC(datamem, argtype) \
4736 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4739 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
4740 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
4741 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
4742 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
4743 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
4744 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
4745 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
4746 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
4747 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
4748 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
4750 #define STLOC_NP(datamem, argtype) \
4751 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4754 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
4755 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
4757 MINT_IN_CASE(MINT_STLOC_VT)
4758 i32 = READ32(ip + 2);
4760 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
4761 vt_sp -= (i32 + 7) & ~7;
4765 MINT_IN_CASE(MINT_LOCALLOC) {
4766 if (sp != frame->stack + 1) /*FIX?*/
4767 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
4769 int len = sp [-1].data.i;
4770 sp [-1].data.p = alloca (len);
4771 MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
4772 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4773 if (header && header->init_locals)
4774 memset (sp [-1].data.p, 0, len);
4778 MINT_IN_CASE(MINT_ENDFILTER)
4779 /* top of stack is result of filter */
4780 frame->retval = &sp [-1];
4782 MINT_IN_CASE(MINT_INITOBJ)
4784 memset (sp->data.vt, 0, READ32(ip + 1));
4787 MINT_IN_CASE(MINT_CPBLK)
4789 if (!sp [0].data.p || !sp [1].data.p)
4790 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4792 /* FIXME: value and size may be int64... */
4793 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4796 MINT_IN_CASE(MINT_CONSTRAINED_) {
4798 /* FIXME: implement */
4800 token = READ32 (ip);
4805 MINT_IN_CASE(MINT_INITBLK)
4808 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4810 /* FIXME: value and size may be int64... */
4811 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4814 MINT_IN_CASE(MINT_NO_)
4815 /* FIXME: implement */
4819 MINT_IN_CASE(MINT_RETHROW)
4821 * need to clarify what this should actually do:
4822 * start the search from the last found handler in
4823 * this method or continue in the caller or what.
4824 * Also, do we need to run finally/fault handlers after a retrow?
4825 * Well, this implementation will follow the usual search
4826 * for an handler, considering the current ip as throw spot.
4827 * We need to NULL frame->ex_handler for the later code to
4828 * actually run the new found handler.
4830 frame->ex_handler = NULL;
4831 THROW_EX (frame->ex, ip - 1);
4834 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
4835 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
4839 g_assert_not_reached ();
4841 * Exception handling code.
4842 * The exception object is stored in frame->ex.
4849 MonoInvocation *inv;
4850 MonoExceptionClause *clause;
4856 g_print ("* Handling exception '%s' at IL_%04x\n",
4857 frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name,
4858 rtm == NULL ? 0 : frame->ip - rtm->code);
4860 if (die_on_exception)
4863 for (inv = frame; inv; inv = inv->parent) {
4865 if (inv->runtime_method == NULL)
4867 method = inv->runtime_method->method;
4868 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4870 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4872 if (inv->ip == NULL)
4874 ip_offset = inv->ip - inv->runtime_method->code;
4875 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4876 for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
4877 clause = &inv->runtime_method->clauses [i];
4879 g_print ("* clause [%d]: %p\n", i, clause);
4881 if (!MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4884 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4887 g_print ("* Filter found at '%s'\n", method->name);
4889 MonoInvocation dup_frame;
4891 memcpy (&dup_frame, inv, sizeof (MonoInvocation));
4892 dup_frame.retval = &retval;
4893 ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex, -1);
4894 if (dup_frame.retval->data.i) {
4897 g_print ("* Matched Filter at '%s'\n", method->name);
4899 inv->ex_handler = clause;
4900 goto handle_finally;
4902 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4903 MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
4904 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4907 * OK, we found an handler, now we need to execute the finally
4908 * and fault blocks before branching to the handler code.
4912 g_print ("* Found handler at '%s'\n", method->name);
4914 inv->ex_handler = clause;
4915 goto handle_finally;
4921 * If we get here, no handler was found: print a stack trace.
4923 for (inv = frame; inv; inv = inv->parent) {
4924 if (inv->invoke_trap)
4925 goto handle_finally;
4928 ex_obj = (MonoObject *) frame->ex;
4929 mono_unhandled_exception (ex_obj);
4930 MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls ();
4931 jit_tls->abort_func (ex_obj);
4932 g_assert_not_reached ();
4938 MonoExceptionClause *clause;
4939 GSList *old_list = finally_ips;
4940 MonoMethod *method = frame->runtime_method->method;
4941 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
4942 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4946 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
4948 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4949 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4952 ip_offset = frame->ip - rtm->code;
4954 if (endfinally_ip != NULL)
4955 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4956 for (i = 0; i < header->num_clauses; ++i)
4957 if (frame->ex_handler == &rtm->clauses [i])
4961 clause = &rtm->clauses [i];
4962 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
4963 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4964 ip = rtm->code + clause->handler_offset;
4965 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4968 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4974 endfinally_ip = NULL;
4976 if (old_list != finally_ips && finally_ips) {
4977 ip = finally_ips->data;
4978 finally_ips = g_slist_remove (finally_ips, ip);
4979 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4984 * If an exception is set, we need to execute the fault handler, too,
4985 * otherwise, we continue normally.
4995 MonoExceptionClause *clause;
4996 MonoMethod *method = frame->runtime_method->method;
4997 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
4998 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5002 g_print ("* Handle fault\n");
5004 ip_offset = frame->ip - rtm->code;
5005 for (i = 0; i < header->num_clauses; ++i) {
5006 clause = &rtm->clauses [i];
5007 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
5008 ip = rtm->code + clause->handler_offset;
5011 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
5017 * If the handler for the exception was found in this method, we jump
5018 * to it right away, otherwise we return and let the caller run
5019 * the finally, fault and catch blocks.
5020 * This same code should be present in the endfault opcode, but it
5021 * is corrently not assigned in the ECMA specs: LAMESPEC.
5023 if (frame->ex_handler) {
5026 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
5028 ip = rtm->code + frame->ex_handler->handler_offset;
5030 vt_sp = (unsigned char *) sp + rtm->stack_size;
5031 sp->data.p = frame->ex;
5042 ves_exec_method (MonoInvocation *frame)
5044 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5045 ThreadContext context_struct;
5052 mono_unhandled_exception ((MonoObject*)frame->ex);
5055 if (context == NULL) {
5056 context = &context_struct;
5057 context_struct.domain = mono_domain_get ();
5058 context_struct.base_frame = frame;
5059 context_struct.current_frame = NULL;
5060 context_struct.env_frame = frame;
5061 context_struct.current_env = &env;
5062 context_struct.search_for_handler = 0;
5063 context_struct.managed_code = 0;
5064 mono_native_tls_set_value (thread_context_id, context);
5067 frame->parent = context->current_frame;
5068 frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
5069 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5070 context->managed_code = 1;
5071 ves_exec_method_with_context (frame, context, NULL, NULL, -1);
5072 context->managed_code = 0;
5074 if (context != &context_struct && context->current_env) {
5075 context->env_frame->ex = frame->ex;
5076 longjmp (*context->current_env, 1);
5079 mono_unhandled_exception ((MonoObject*)frame->ex);
5081 if (context->base_frame == frame)
5082 mono_native_tls_set_value (thread_context_id, NULL);
5084 context->current_frame = frame->parent;
5088 mono_interp_parse_options (const char *options)
5092 args = g_strsplit (options, ",", -1);
5093 for (ptr = args; ptr && *ptr; ptr ++) {
5096 if (strncmp (arg, "jit=", 4) == 0)
5097 jit_classes = g_slist_prepend (jit_classes, arg + 4);
5104 mono_native_tls_alloc (&thread_context_id, NULL);
5105 mono_native_tls_set_value (thread_context_id, NULL);
5107 mono_interp_transform_init ();
5110 typedef int (*TestMethod) (void);
5113 interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain)
5115 int result, expected, failed, cfailed, run;
5116 double elapsed, transform_time;
5118 MonoObject *result_obj;
5119 static gboolean filter_method_init = FALSE;
5120 static const char *filter_method = NULL;
5122 g_print ("Test run: image=%s\n", mono_image_get_filename (image));
5123 cfailed = failed = run = 0;
5124 transform_time = elapsed = 0.0;
5126 g_timer_start (timer);
5127 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5128 MonoObject *exc = NULL;
5130 MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
5132 mono_error_cleanup (&error); /* FIXME don't swallow the error */
5136 if (!filter_method_init) {
5137 filter_method = g_getenv ("INTERP_FILTER_METHOD");
5138 filter_method_init = TRUE;
5140 gboolean filter = FALSE;
5141 if (filter_method) {
5142 const char *name = filter_method;
5144 if ((strchr (name, '.') > name) || strchr (name, ':')) {
5145 MonoMethodDesc *desc = mono_method_desc_new (name, TRUE);
5146 filter = mono_method_desc_full_match (desc, method);
5147 mono_method_desc_free (desc);
5149 filter = strcmp (method->name, name) == 0;
5151 } else { /* no filter, check for `Category' attribute on method */
5153 MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error);
5154 mono_error_cleanup (&error);
5158 for (j = 0; j < ainfo->num_attrs && filter; ++j) {
5159 MonoCustomAttrEntry *centry = &ainfo->attrs [j];
5160 if (centry->ctor == NULL)
5163 MonoClass *klass = centry->ctor->klass;
5164 if (strcmp (klass->name, "CategoryAttribute"))
5167 MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error);
5168 /* FIXME: there is an ordering problem if there're multiple attributes, do this instead:
5169 * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */
5170 mono_error_cleanup (&error);
5171 MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1);
5172 MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error);
5173 mono_error_cleanup (&error);
5174 char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error);
5175 mono_error_cleanup (&error);
5176 if (!strcmp (utf8_str, "!INTERPRETER")) {
5177 g_print ("skip %s...\n", method->name);
5183 if (strncmp (method->name, "test_", 5) == 0 && filter) {
5184 MonoError interp_error;
5185 MonoObject *exc = NULL;
5187 result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error);
5188 if (!mono_error_ok (&interp_error)) {
5190 g_print ("Test '%s' execution failed.\n", method->name);
5191 } else if (exc != NULL) {
5192 g_print ("Exception in Test '%s' occured:\n", method->name);
5193 mono_object_describe (exc);
5197 result = *(gint32 *) mono_object_unbox (result_obj);
5198 expected = atoi (method->name + 5); // FIXME: oh no.
5201 if (result != expected) {
5203 g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
5208 g_timer_stop (timer);
5209 elapsed = g_timer_elapsed (timer, NULL);
5210 if (failed > 0 || cfailed > 0){
5211 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
5212 run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
5214 g_print ("Results: total tests: %d, all pass \n", run);
5217 g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed,
5218 elapsed - transform_time, transform_time);
5219 *total += failed + cfailed;
5224 interp_regression (MonoImage *image, int verbose, int *total_run)
5227 GTimer *timer = g_timer_new ();
5228 MonoDomain *domain = mono_domain_get ();
5232 /* load the metadata */
5233 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5235 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
5237 mono_error_cleanup (&error);
5240 mono_class_init (method->klass);
5245 interp_regression_step (image, verbose, total_run, &total, timer, domain);
5247 g_timer_destroy (timer);
5252 mono_interp_regression_list (int verbose, int count, char *images [])
5254 int i, total, total_run, run;
5256 total_run = total = 0;
5257 for (i = 0; i < count; ++i) {
5258 MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL);
5260 g_warning ("failed to load assembly: %s", images [i]);
5263 total += interp_regression (mono_assembly_get_image (ass), verbose, &run);
5267 g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run);
5269 g_print ("Overall results: tests: %d, 100%% pass\n", total_run);
5276 * mono_interp_set_resume_state:
5278 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5281 mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip)
5283 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5285 context->has_resume_state = TRUE;
5286 context->handler_frame = frame->interp_frame;
5287 /* This is on the stack, so it doesn't need a wbarrier */
5288 context->handler_frame->ex = ex;
5289 context->handler_ip = handler_ip;
5293 * mono_interp_run_finally:
5295 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5296 * frame->interp_frame.
5299 mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5301 MonoInvocation *iframe = frame->interp_frame;
5302 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5304 ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index);
5308 MonoInvocation *current;
5312 * mono_interp_frame_iter_init:
5314 * Initialize an iterator for iterating through interpreted frames.
5317 mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5319 StackIter *stack_iter = (StackIter*)iter;
5321 stack_iter->current = (MonoInvocation*)interp_exit_data;
5325 mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5327 StackIter *stack_iter = (StackIter*)iter;
5328 MonoInvocation *iframe = stack_iter->current;
5330 memset (frame, 0, sizeof (StackFrameInfo));
5331 /* pinvoke frames doesn't have runtime_method set */
5332 while (iframe && !iframe->runtime_method)
5333 iframe = iframe->parent;
5337 frame->type = FRAME_TYPE_INTERP;
5338 frame->interp_frame = iframe;
5339 frame->method = iframe->runtime_method->method;
5340 frame->actual_method = frame->method;
5341 /* This is the offset in the interpreter IR */
5342 frame->native_offset = iframe->ip - iframe->runtime_method->code;
5343 frame->ji = iframe->runtime_method->jinfo;
5345 stack_iter->current = iframe->parent;