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>
69 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/mini-arm.h>
75 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
78 #define finite _finite
82 #define finite isfinite
87 init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *rmethod, stackval *method_args, stackval *method_retval)
89 frame->parent = parent_frame;
90 frame->stack_args = method_args;
91 frame->retval = method_retval;
92 frame->runtime_method = rmethod;
95 frame->invoke_trap = 0;
98 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
99 RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
100 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
104 * List of classes whose methods will be executed by transitioning to JITted code.
108 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
109 static gboolean ss_enabled;
111 void ves_exec_method (MonoInvocation *frame);
113 static char* dump_frame (MonoInvocation *inv);
114 static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
115 static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally);
117 typedef void (*ICallMethod) (MonoInvocation *frame);
119 static guint32 die_on_exception = 0;
120 static MonoNativeTlsKey thread_context_id;
122 static char* dump_args (MonoInvocation *inv);
124 #define DEBUG_INTERP 0
127 int mono_interp_traceopt = 2;
128 /* If true, then we output the opcodes as we interpret them */
129 static int global_tracing = 2;
131 static int debug_indent_level = 0;
133 static int break_on_method = 0;
134 static int nested_trace = 0;
135 static GList *db_methods = NULL;
142 for (h = 0; h < debug_indent_level; h++)
147 db_match_method (gpointer data, gpointer user_data)
149 MonoMethod *m = (MonoMethod*)user_data;
150 MonoMethodDesc *desc = data;
152 if (mono_method_desc_full_match (desc, m))
157 debug_enter (MonoInvocation *frame, int *tracing)
160 g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
162 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
166 MonoMethod *method = frame->runtime_method->method;
167 char *mn, *args = dump_args (frame);
168 debug_indent_level++;
170 mn = mono_method_full_name (method, FALSE);
171 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
173 g_print ("%s)\n", args);
176 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)
177 mono_profiler_method_enter (frame->runtime_method->method);
181 #define DEBUG_LEAVE() \
184 args = dump_retval (frame); \
186 mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
187 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
189 g_print (" => %s\n", args); \
191 debug_indent_level--; \
192 if (tracing == 3) global_tracing = 0; \
194 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
195 mono_profiler_method_leave (frame->runtime_method->method);
199 int mono_interp_traceopt = 0;
200 static void debug_enter (MonoInvocation *frame, int *tracing)
203 #define DEBUG_LEAVE()
207 /* Set the current execution state to the resume state in context */
208 #define SET_RESUME_STATE(context) do { \
209 ip = (context)->handler_ip; \
211 sp->data.p = frame->ex; \
215 (context)->has_resume_state = 0; \
216 (context)->handler_frame = NULL; \
221 set_context (ThreadContext *context)
223 MonoJitTlsData *jit_tls;
225 mono_native_tls_set_value (thread_context_id, context);
226 jit_tls = mono_tls_get_jit_tls ();
228 jit_tls->interp_context = context;
232 ves_real_abort (int line, MonoMethod *mh,
233 const unsigned short *ip, stackval *stack, stackval *sp)
236 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
237 fprintf (stderr, "Line=%d IP=0x%04lx, Aborted execution\n", line,
238 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code);
239 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
240 g_print ("0x%04x %02x\n",
241 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code, *ip);
242 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
244 printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
247 #define ves_abort() \
249 ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
250 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
253 static RuntimeMethod*
254 lookup_runtime_method (MonoDomain *domain, MonoMethod *method)
257 MonoJitDomainInfo *info;
259 info = domain_jit_info (domain);
260 mono_domain_jit_code_hash_lock (domain);
261 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
262 mono_domain_jit_code_hash_unlock (domain);
267 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
270 MonoJitDomainInfo *info;
271 MonoMethodSignature *sig;
276 info = domain_jit_info (domain);
277 mono_domain_jit_code_hash_lock (domain);
278 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
279 mono_domain_jit_code_hash_unlock (domain);
283 sig = mono_method_signature (method);
285 rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
286 rtm->method = method;
287 rtm->param_count = sig->param_count;
288 rtm->hasthis = sig->hasthis;
289 rtm->rtype = mini_get_underlying_type (sig->ret);
290 rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
291 for (i = 0; i < sig->param_count; ++i)
292 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
294 mono_domain_jit_code_hash_lock (domain);
295 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
296 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
297 mono_domain_jit_code_hash_unlock (domain);
303 mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
305 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
306 method = mono_marshal_get_synchronized_wrapper (method);
307 return mono_interp_get_runtime_method (domain, method, error);
313 * Push an LMF frame on the LMF stack
314 * to mark the transition to native code.
315 * This is needed for the native code to
316 * be able to do stack walks.
319 interp_push_lmf (MonoLMFExt *ext, MonoInvocation *frame)
321 memset (ext, 0, sizeof (MonoLMFExt));
322 ext->interp_exit = TRUE;
323 ext->interp_exit_data = frame;
329 interp_pop_lmf (MonoLMFExt *ext)
331 mono_pop_lmf (&ext->lmf);
334 static inline RuntimeMethod*
335 get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
337 MonoMethod *m = runtime_method->method;
340 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
341 RuntimeMethod *ret = NULL;
342 #ifndef DISABLE_REMOTING
343 if (mono_object_is_transparent_proxy (obj)) {
344 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
345 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
348 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
349 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
350 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
352 ret = runtime_method;
357 mono_class_setup_vtable (obj->vtable->klass);
359 int slot = mono_method_get_vtable_slot (m);
360 if (mono_class_is_interface (m->klass)) {
361 g_assert (obj->vtable->klass != m->klass);
362 /* TODO: interface offset lookup is slow, go through IMT instead */
363 gboolean non_exact_match;
364 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
367 MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
368 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
369 MonoGenericContext context = { NULL, NULL };
371 if (mono_class_is_ginst (virtual_method->klass))
372 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
373 else if (mono_class_is_gtd (virtual_method->klass))
374 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
375 context.method_inst = mono_method_get_context (m)->method_inst;
377 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
378 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
381 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
382 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
385 RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
386 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
387 return virtual_runtime_method;
391 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
394 switch (type->type) {
395 case MONO_TYPE_OBJECT:
396 case MONO_TYPE_CLASS:
397 case MONO_TYPE_STRING:
398 case MONO_TYPE_ARRAY:
399 case MONO_TYPE_SZARRAY:
404 result->data.p = *(gpointer*)data;
407 switch (type->type) {
411 result->data.i = *(gint8*)data;
414 case MONO_TYPE_BOOLEAN:
415 result->data.i = *(guint8*)data;
418 result->data.i = *(gint16*)data;
422 result->data.i = *(guint16*)data;
425 result->data.i = *(gint32*)data;
429 result->data.nati = *(mono_i*)data;
432 result->data.p = *(gpointer*)data;
435 result->data.i = *(guint32*)data;
439 /* memmove handles unaligned case */
440 memmove (&tmp, data, sizeof (float));
441 result->data.f = tmp;
446 memmove (&result->data.l, data, sizeof (gint64));
449 memmove (&result->data.f, data, sizeof (double));
451 case MONO_TYPE_STRING:
452 case MONO_TYPE_SZARRAY:
453 case MONO_TYPE_CLASS:
454 case MONO_TYPE_OBJECT:
455 case MONO_TYPE_ARRAY:
456 result->data.p = *(gpointer*)data;
458 case MONO_TYPE_VALUETYPE:
459 if (type->data.klass->enumtype) {
460 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
463 mono_value_copy (result->data.vt, data, type->data.klass);
465 case MONO_TYPE_GENERICINST: {
466 if (mono_type_generic_inst_is_valuetype (type)) {
467 mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
470 stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
474 g_warning ("got type 0x%02x", type->type);
475 g_assert_not_reached ();
480 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
483 gpointer *p = (gpointer*)data;
487 /* printf ("TODAT0 %p\n", data); */
488 switch (type->type) {
491 guint8 *p = (guint8*)data;
495 case MONO_TYPE_BOOLEAN: {
496 guint8 *p = (guint8*)data;
497 *p = (val->data.i != 0);
502 case MONO_TYPE_CHAR: {
503 guint16 *p = (guint16*)data;
508 mono_i *p = (mono_i*)data;
509 /* In theory the value used by stloc should match the local var type
510 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
511 a native int - both by csc and mcs). Not sure what to do about sign extension
512 as it is outside the spec... doing the obvious */
513 *p = (mono_i)val->data.nati;
517 mono_u *p = (mono_u*)data;
519 *p = (mono_u)val->data.nati;
524 gint32 *p = (gint32*)data;
530 gint64 *p = (gint64*)data;
535 float *p = (float*)data;
540 double *p = (double*)data;
544 case MONO_TYPE_STRING:
545 case MONO_TYPE_SZARRAY:
546 case MONO_TYPE_CLASS:
547 case MONO_TYPE_OBJECT:
548 case MONO_TYPE_ARRAY: {
549 gpointer *p = (gpointer *) data;
550 mono_gc_wbarrier_generic_store (p, val->data.p);
553 case MONO_TYPE_PTR: {
554 gpointer *p = (gpointer *) data;
558 case MONO_TYPE_VALUETYPE:
559 if (type->data.klass->enumtype) {
560 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
563 mono_value_copy (data, val->data.vt, type->data.klass);
565 case MONO_TYPE_GENERICINST: {
566 MonoClass *container_class = type->data.generic_class->container_class;
568 if (container_class->valuetype && !container_class->enumtype) {
569 mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
572 stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
576 g_warning ("got type %x", type->type);
577 g_assert_not_reached ();
582 fill_in_trace (MonoException *exception, MonoInvocation *frame)
585 char *stack_trace = dump_frame (frame);
586 MonoDomain *domain = mono_domain_get();
587 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
588 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
589 (exception)->trace_ips = get_trace_ips (domain, frame);
590 g_free (stack_trace);
593 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
595 #define THROW_EX(exception,ex_ip) \
597 frame->ip = (ex_ip); \
598 frame->ex = (MonoException*)(exception); \
599 FILL_IN_TRACE(frame->ex, frame); \
600 goto handle_exception; \
604 ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
607 intptr_t *lower_bounds;
612 lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
613 for (i = 0; i < sig->param_count; ++i) {
614 lengths [i] = values->data.i;
617 if (klass->rank == sig->param_count) {
618 /* Only lengths provided. */
621 /* lower bounds are first. */
622 lower_bounds = (intptr_t *) lengths;
623 lengths += klass->rank;
625 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
626 if (!mono_error_ok (&error)) {
627 frame->ex = mono_error_convert_to_exception (&error);
628 FILL_IN_TRACE (frame->ex, frame);
630 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
635 ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame, gboolean safe)
637 g_assert (!frame->ex);
638 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
642 for (gint32 i = 0; i < ac->rank; i++) {
643 guint32 idx = sp [i].data.i;
644 guint32 lower = ao->bounds [i].lower_bound;
645 guint32 len = ao->bounds [i].length;
646 if (safe && (idx < lower || (idx - lower) >= len)) {
647 frame->ex = mono_get_exception_index_out_of_range ();
648 FILL_IN_TRACE (frame->ex, frame);
651 pos = (pos * len) + idx - lower;
655 if (safe && pos >= ao->max_length) {
656 frame->ex = mono_get_exception_index_out_of_range ();
657 FILL_IN_TRACE (frame->ex, frame);
665 ves_array_set (MonoInvocation *frame)
667 stackval *sp = frame->stack_args + 1;
669 MonoObject *o = frame->stack_args->data.p;
670 MonoArray *ao = (MonoArray *) o;
671 MonoClass *ac = o->vtable->klass;
673 g_assert (ac->rank >= 1);
675 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
679 if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
681 MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
682 mono_error_cleanup (&error);
684 frame->ex = mono_get_exception_array_type_mismatch ();
685 FILL_IN_TRACE (frame->ex, frame);
690 gint32 esize = mono_array_element_size (ac);
691 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
693 MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
694 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
698 ves_array_get (MonoInvocation *frame, gboolean safe)
700 stackval *sp = frame->stack_args + 1;
702 MonoObject *o = frame->stack_args->data.p;
703 MonoArray *ao = (MonoArray *) o;
704 MonoClass *ac = o->vtable->klass;
706 g_assert (ac->rank >= 1);
708 gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
712 gint32 esize = mono_array_element_size (ac);
713 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
715 MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret;
716 stackval_from_data (mt, frame->retval, ea, FALSE);
720 ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
722 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
724 g_assert (ac->rank >= 1);
726 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
730 if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
731 frame->ex = mono_get_exception_array_type_mismatch ();
732 FILL_IN_TRACE (frame->ex, frame);
735 gint32 esize = mono_array_element_size (ac);
736 return mono_array_addr_with_size (ao, esize, pos);
740 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
743 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
748 MonoInvocation *frame = context->current_frame;
751 MonoStackFrameInfo fi;
752 memset (&fi, 0, sizeof (MonoStackFrameInfo));
754 /* TODO: hack to make some asserts happy. */
755 fi.ji = (MonoJitInfo *) frame->runtime_method;
757 if (frame->runtime_method)
758 fi.method = fi.actual_method = frame->runtime_method->method;
760 if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
762 fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
764 MonoMethodHeader *hd = mono_method_get_header_checked (fi.method, &error);
765 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
766 fi.type = FRAME_TYPE_MANAGED;
767 fi.il_offset = frame->ip - (const unsigned short *) hd->code;
768 if (!fi.method->wrapper_type)
772 if (func (&fi, ctx, user_data))
774 frame = frame->parent;
778 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
780 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
782 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
785 g_assert (mono_arm_eabi_supported ());
786 int i8_align = mono_arm_i8_align ();
792 for (int i = 0; i < sig->param_count; i++) {
793 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
795 case MONO_TYPE_BOOLEAN:
806 case MONO_TYPE_SZARRAY:
807 case MONO_TYPE_CLASS:
808 case MONO_TYPE_OBJECT:
809 case MONO_TYPE_STRING:
810 case MONO_TYPE_VALUETYPE:
811 case MONO_TYPE_GENERICINST:
812 #if SIZEOF_VOID_P == 8
817 #if SIZEOF_VOID_P == 4
820 /* pairs begin at even registers */
821 if (i8_align == 8 && margs->ilen & 1)
828 #if SIZEOF_VOID_P == 8
833 #if SIZEOF_VOID_P == 4
839 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
844 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
847 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
849 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
850 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
852 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
853 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
860 margs->iargs [0] = frame->stack_args->data.p;
864 for (int i = 0; i < sig->param_count; i++) {
865 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
867 case MONO_TYPE_BOOLEAN:
878 case MONO_TYPE_SZARRAY:
879 case MONO_TYPE_CLASS:
880 case MONO_TYPE_OBJECT:
881 case MONO_TYPE_STRING:
882 case MONO_TYPE_VALUETYPE:
883 case MONO_TYPE_GENERICINST:
884 #if SIZEOF_VOID_P == 8
887 margs->iargs [int_i] = frame->stack_args [i].data.p;
889 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
893 #if SIZEOF_VOID_P == 4
895 stackval *sarg = &frame->stack_args [i];
897 /* pairs begin at even registers */
898 if (i8_align == 8 && int_i & 1)
901 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
903 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
905 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);
913 if (ptype == MONO_TYPE_R4)
914 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
916 margs->fargs [int_f] = frame->stack_args [i].data.f;
918 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);
920 #if SIZEOF_VOID_P == 4
927 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
931 switch (sig->ret->type) {
932 case MONO_TYPE_BOOLEAN:
943 case MONO_TYPE_SZARRAY:
944 case MONO_TYPE_CLASS:
945 case MONO_TYPE_OBJECT:
946 case MONO_TYPE_STRING:
948 case MONO_TYPE_VALUETYPE:
949 case MONO_TYPE_GENERICINST:
950 margs->retval = &(frame->retval->data.p);
951 margs->is_float_ret = 0;
955 margs->retval = &(frame->retval->data.p);
956 margs->is_float_ret = 1;
959 margs->retval = NULL;
962 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
969 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
972 MonoInvocation *old_frame = context->current_frame;
973 MonoInvocation *old_env_frame = context->env_frame;
974 jmp_buf *old_env = context->current_env;
978 context->current_frame = old_frame;
979 context->env_frame = old_env_frame;
980 context->current_env = old_env;
981 context->managed_code = 1;
986 context->env_frame = frame;
987 context->current_env = &env;
989 g_assert (!frame->runtime_method);
990 if (!mono_interp_enter_icall_trampoline) {
992 mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
994 // mono_tramp_info_register (info, NULL);
997 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
999 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
1000 g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
1003 context->current_frame = frame;
1004 context->managed_code = 0;
1006 interp_push_lmf (&ext, frame);
1008 mono_interp_enter_icall_trampoline (addr, margs);
1010 interp_pop_lmf (&ext);
1012 context->managed_code = 1;
1013 /* domain can only be changed by native code */
1014 context->domain = mono_domain_get ();
1016 if (*mono_thread_interruption_request_flag ()) {
1017 MonoException *exc = mono_thread_interruption_checkpoint ();
1020 context->search_for_handler = 1;
1024 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1025 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1027 context->current_frame = old_frame;
1028 context->env_frame = old_env_frame;
1029 context->current_env = old_env;
1031 g_free (margs->iargs);
1032 g_free (margs->fargs);
1037 mono_interp_init_delegate (MonoDelegate *del)
1041 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
1042 del->method = ((RuntimeMethod *) del->method_ptr)->method;
1047 * runtime specifies that the implementation of the method is automatically
1048 * provided by the runtime and is primarily used for the methods of delegates.
1051 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
1053 MonoMethod *method = frame->runtime_method->method;
1054 const char *name = method->name;
1055 MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
1056 MonoObject *isinst_obj;
1059 mono_class_init (method->klass);
1061 if (method->klass == mono_defaults.array_class) {
1062 if (!strcmp (method->name, "UnsafeMov")) {
1063 /* TODO: layout checks */
1064 MonoType *mt = mono_method_signature (method)->ret;
1065 stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
1068 if (!strcmp (method->name, "UnsafeLoad")) {
1069 ves_array_get (frame, FALSE);
1074 isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
1075 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1076 if (obj && isinst_obj) {
1077 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1078 ves_array_set (frame);
1081 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1082 ves_array_get (frame, TRUE);
1087 g_error ("Don't know how to exec runtime method %s.%s::%s",
1088 method->klass->name_space, method->klass->name,
1094 dump_stack (stackval *stack, stackval *sp)
1096 stackval *s = stack;
1097 GString *str = g_string_new ("");
1100 return g_string_free (str, FALSE);
1103 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1106 return g_string_free (str, FALSE);
1111 dump_stackval (GString *str, stackval *s, MonoType *type)
1113 switch (type->type) {
1120 case MONO_TYPE_CHAR:
1121 case MONO_TYPE_BOOLEAN:
1122 g_string_append_printf (str, "[%d] ", s->data.i);
1124 case MONO_TYPE_STRING:
1125 case MONO_TYPE_SZARRAY:
1126 case MONO_TYPE_CLASS:
1127 case MONO_TYPE_OBJECT:
1128 case MONO_TYPE_ARRAY:
1132 g_string_append_printf (str, "[%p] ", s->data.p);
1134 case MONO_TYPE_VALUETYPE:
1135 if (type->data.klass->enumtype)
1136 g_string_append_printf (str, "[%d] ", s->data.i);
1138 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1142 g_string_append_printf (str, "[%g] ", s->data.f);
1147 GString *res = g_string_new ("");
1148 mono_type_get_desc (res, type, TRUE);
1149 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1150 g_string_free (res, TRUE);
1158 dump_retval (MonoInvocation *inv)
1160 GString *str = g_string_new ("");
1161 MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
1163 if (ret->type != MONO_TYPE_VOID)
1164 dump_stackval (str, inv->retval, ret);
1166 return g_string_free (str, FALSE);
1171 dump_args (MonoInvocation *inv)
1173 GString *str = g_string_new ("");
1175 MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method);
1177 if (signature->param_count == 0 && !signature->hasthis)
1178 return g_string_free (str, FALSE);
1180 if (signature->hasthis) {
1181 MonoMethod *method = inv->runtime_method->method;
1182 dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1185 for (i = 0; i < signature->param_count; ++i)
1186 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1188 return g_string_free (str, FALSE);
1192 dump_frame (MonoInvocation *inv)
1194 GString *str = g_string_new ("");
1199 for (i = 0; inv; inv = inv->parent) {
1200 if (inv->runtime_method != NULL) {
1201 MonoMethod *method = inv->runtime_method->method;
1205 const char * opname = "";
1207 gchar *source = NULL;
1211 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1212 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1213 MonoMethodHeader *hd = mono_method_get_header_checked (method, &error);
1214 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1218 opname = mono_interp_opname [*inv->ip];
1219 codep = inv->ip - inv->runtime_method->code;
1220 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1225 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1226 source = mono_debug_method_lookup_location (minfo, codep);
1230 args = dump_args (inv);
1231 name = mono_method_full_name (method, TRUE);
1233 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1235 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1242 return g_string_free (str, FALSE);
1246 get_trace_ips (MonoDomain *domain, MonoInvocation *top)
1250 MonoInvocation *inv;
1253 for (i = 0, inv = top; inv; inv = inv->parent)
1254 if (inv->runtime_method != NULL)
1257 res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error);
1258 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1260 for (i = 0, inv = top; inv; inv = inv->parent)
1261 if (inv->runtime_method != NULL) {
1262 mono_array_set (res, gpointer, i, inv->runtime_method);
1264 mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1272 #define MYGUINT64_MAX 18446744073709551615ULL
1273 #define MYGINT64_MAX 9223372036854775807LL
1274 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1276 #define MYGUINT32_MAX 4294967295U
1277 #define MYGINT32_MAX 2147483647
1278 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1280 #define CHECK_ADD_OVERFLOW(a,b) \
1281 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1282 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1284 #define CHECK_SUB_OVERFLOW(a,b) \
1285 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1286 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1288 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1289 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1291 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1292 (guint32)(a) < (guint32)(b) ? -1 : 0
1294 #define CHECK_ADD_OVERFLOW64(a,b) \
1295 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1296 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1298 #define CHECK_SUB_OVERFLOW64(a,b) \
1299 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1300 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1302 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1303 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1305 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1306 (guint64)(a) < (guint64)(b) ? -1 : 0
1308 #if SIZEOF_VOID_P == 4
1309 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1310 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1312 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1313 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1316 /* Resolves to TRUE if the operands would overflow */
1317 #define CHECK_MUL_OVERFLOW(a,b) \
1318 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1319 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1320 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1321 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1322 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1323 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1324 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1326 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1327 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1328 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1330 #define CHECK_MUL_OVERFLOW64(a,b) \
1331 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1332 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1333 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1334 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1335 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1336 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1337 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1339 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1340 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1341 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1343 #if SIZEOF_VOID_P == 4
1344 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1345 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1347 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1348 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1352 mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1354 MonoInvocation frame;
1355 ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1356 MonoObject *retval = NULL;
1357 MonoMethodSignature *sig = mono_method_signature (method);
1358 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1359 int i, type, isobject = 0;
1363 ThreadContext context_struct;
1364 MonoInvocation *old_frame = NULL;
1374 if (context != &context_struct) {
1375 context->domain = mono_domain_get ();
1376 context->current_frame = old_frame;
1377 context->managed_code = 0;
1381 *exc = (MonoObject *)frame.ex;
1385 if (context == NULL) {
1386 context = &context_struct;
1387 memset (context, 0, sizeof (ThreadContext));
1388 context_struct.base_frame = &frame;
1389 context_struct.env_frame = &frame;
1390 context_struct.current_env = &env;
1391 set_context (context);
1394 old_frame = context->current_frame;
1396 context->domain = mono_domain_get ();
1398 switch (sig->ret->type) {
1399 case MONO_TYPE_VOID:
1401 case MONO_TYPE_STRING:
1402 case MONO_TYPE_OBJECT:
1403 case MONO_TYPE_CLASS:
1404 case MONO_TYPE_ARRAY:
1405 case MONO_TYPE_SZARRAY:
1408 case MONO_TYPE_VALUETYPE:
1409 retval = mono_object_new_checked (context->domain, klass, error);
1410 ret = mono_object_unbox (retval);
1411 if (!sig->ret->data.klass->enumtype)
1412 result.data.vt = ret;
1414 result.data.vt = alloca (mono_class_instance_size (klass));
1416 case MONO_TYPE_GENERICINST:
1417 if (!MONO_TYPE_IS_REFERENCE (sig->ret)) {
1418 retval = mono_object_new_checked (context->domain, klass, error);
1419 ret = mono_object_unbox (retval);
1420 if (!sig->ret->data.klass->enumtype)
1421 result.data.vt = ret;
1423 result.data.vt = alloca (mono_class_instance_size (klass));
1430 retval = mono_object_new_checked (context->domain, mono_defaults.int_class, error);
1431 ret = mono_object_unbox (retval);
1434 retval = mono_object_new_checked (context->domain, klass, error);
1435 ret = mono_object_unbox (retval);
1439 args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
1441 args [0].data.p = obj;
1443 for (i = 0; i < sig->param_count; ++i) {
1444 int a_index = i + !!sig->hasthis;
1445 if (sig->params [i]->byref) {
1446 args [a_index].data.p = params [i];
1449 type = sig->params [i]->type;
1454 case MONO_TYPE_BOOLEAN:
1455 args [a_index].data.i = *(MonoBoolean*)params [i];
1459 case MONO_TYPE_CHAR:
1460 args [a_index].data.i = *(gint16*)params [i];
1462 #if SIZEOF_VOID_P == 4
1463 case MONO_TYPE_U: /* use VAL_POINTER? */
1468 args [a_index].data.i = *(gint32*)params [i];
1470 #if SIZEOF_VOID_P == 8
1476 args [a_index].data.l = *(gint64*)params [i];
1479 args [a_index].data.f = *(gfloat *) params [i];
1482 args [a_index].data.f = *(gdouble *) params [i];
1484 case MONO_TYPE_VALUETYPE:
1485 if (sig->params [i]->data.klass->enumtype) {
1486 type = mono_class_enum_basetype (sig->params [i]->data.klass)->type;
1489 args [a_index].data.p = params [i];
1492 case MONO_TYPE_STRING:
1494 case MONO_TYPE_CLASS:
1495 case MONO_TYPE_ARRAY:
1496 case MONO_TYPE_SZARRAY:
1497 case MONO_TYPE_OBJECT:
1498 case MONO_TYPE_GENERICINST:
1499 args [a_index].data.p = params [i];
1502 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1506 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1507 method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
1508 INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
1511 frame.invoke_trap = 1;
1512 context->managed_code = 1;
1513 ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
1514 context->managed_code = 0;
1515 if (context == &context_struct)
1518 context->current_frame = old_frame;
1519 if (frame.ex != NULL) {
1521 *exc = (MonoObject*) frame.ex;
1524 if (context->current_env != NULL) {
1525 context->env_frame->ex = frame.ex;
1526 longjmp(*context->current_env, 1);
1529 printf("dropped exception...\n");
1531 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1533 if (isobject || method->string_ctor)
1534 return result.data.p;
1535 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1540 RuntimeMethod *rmethod;
1544 gpointer *many_args;
1547 /* Main function for entering the interpreter from compiled code */
1549 interp_entry (InterpEntryData *data)
1551 MonoInvocation frame;
1552 RuntimeMethod *rmethod = data->rmethod;
1553 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
1554 ThreadContext context_struct;
1555 MonoInvocation *old_frame;
1559 MonoMethodSignature *sig;
1563 method = rmethod->method;
1564 sig = mono_method_signature (method);
1566 // FIXME: Optimize this
1568 //printf ("%s\n", mono_method_full_name (method, 1));
1571 if (context == NULL) {
1572 context = &context_struct;
1573 memset (context, 0, sizeof (ThreadContext));
1574 context_struct.base_frame = &frame;
1575 context_struct.env_frame = &frame;
1576 set_context (context);
1578 old_frame = context->current_frame;
1580 context->domain = mono_domain_get ();
1582 args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
1584 args [0].data.p = data->this_arg;
1587 if (data->many_args)
1588 params = data->many_args;
1590 params = data->args;
1591 for (i = 0; i < sig->param_count; ++i) {
1592 int a_index = i + (sig->hasthis ? 1 : 0);
1593 if (sig->params [i]->byref) {
1594 args [a_index].data.p = params [i];
1597 type = rmethod->param_types [i];
1598 switch (type->type) {
1601 args [a_index].data.i = *(MonoBoolean*)params [i];
1605 args [a_index].data.i = *(gint16*)params [i];
1608 #if SIZEOF_VOID_P == 4
1609 args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
1611 args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
1615 #if SIZEOF_VOID_P == 4
1616 args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
1618 args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
1622 args [a_index].data.i = *(guint32*)params [i];
1625 args [a_index].data.i = *(gint32*)params [i];
1628 args [a_index].data.l = *(guint64*)params [i];
1631 args [a_index].data.l = *(gint64*)params [i];
1634 case MONO_TYPE_OBJECT:
1635 args [a_index].data.p = *(MonoObject**)params [i];
1637 case MONO_TYPE_VALUETYPE:
1638 args [a_index].data.p = params [i];
1640 case MONO_TYPE_GENERICINST:
1641 if (MONO_TYPE_IS_REFERENCE (type))
1642 args [a_index].data.p = params [i];
1644 args [a_index].data.vt = params [i];
1647 printf ("%s\n", mono_type_full_name (sig->params [i]));
1653 init_frame (&frame, NULL, data->rmethod, args, &result);
1654 context->managed_code = 1;
1656 type = rmethod->rtype;
1657 switch (type->type) {
1658 case MONO_TYPE_GENERICINST:
1659 if (!MONO_TYPE_IS_REFERENCE (type))
1660 frame.retval->data.vt = data->res;
1662 case MONO_TYPE_VALUETYPE:
1663 frame.retval->data.vt = data->res;
1669 ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
1670 context->managed_code = 0;
1671 if (context == &context_struct)
1674 context->current_frame = old_frame;
1677 g_assert (frame.ex == NULL);
1679 type = rmethod->rtype;
1680 switch (type->type) {
1681 case MONO_TYPE_VOID:
1684 *(gint8*)data->res = frame.retval->data.i;
1687 *(guint8*)data->res = frame.retval->data.i;
1690 *(gint16*)data->res = frame.retval->data.i;
1693 *(guint16*)data->res = frame.retval->data.i;
1696 *(gint32*)data->res = frame.retval->data.i;
1699 *(guint64*)data->res = frame.retval->data.i;
1702 *(gint64*)data->res = frame.retval->data.i;
1705 *(guint64*)data->res = frame.retval->data.i;
1708 #if SIZEOF_VOID_P == 8
1709 *(gint64*)data->res = (gint64)frame.retval->data.p;
1711 *(gint32*)data->res = (gint32)frame.retval->data.p;
1715 #if SIZEOF_VOID_P == 8
1716 *(guint64*)data->res = (guint64)frame.retval->data.p;
1718 *(guint32*)data->res = (guint32)frame.retval->data.p;
1721 case MONO_TYPE_OBJECT:
1722 /* No need for a write barrier */
1723 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1725 case MONO_TYPE_GENERICINST:
1726 if (MONO_TYPE_IS_REFERENCE (type)) {
1727 *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
1729 /* Already set before the call */
1732 case MONO_TYPE_VALUETYPE:
1733 /* Already set before the call */
1736 printf ("%s\n", mono_type_full_name (sig->ret));
1743 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1745 MonoInvocation *old_frame = context->current_frame;
1746 MonoInvocation *old_env_frame = context->env_frame;
1747 jmp_buf *old_env = context->current_env;
1751 context->current_frame = old_frame;
1752 context->env_frame = old_env_frame;
1753 context->current_env = old_env;
1754 context->managed_code = 1;
1758 context->env_frame = context->current_frame;
1759 context->current_env = &env;
1760 context->managed_code = 0;
1763 case MINT_ICALL_V_V: {
1764 void (*func)(void) = ptr;
1768 case MINT_ICALL_V_P: {
1769 gpointer (*func)(void) = ptr;
1771 sp [-1].data.p = func ();
1774 case MINT_ICALL_P_V: {
1775 void (*func)(gpointer) = ptr;
1776 func (sp [-1].data.p);
1780 case MINT_ICALL_P_P: {
1781 gpointer (*func)(gpointer) = ptr;
1782 sp [-1].data.p = func (sp [-1].data.p);
1785 case MINT_ICALL_PP_V: {
1786 void (*func)(gpointer,gpointer) = ptr;
1788 func (sp [0].data.p, sp [1].data.p);
1791 case MINT_ICALL_PI_V: {
1792 void (*func)(gpointer,int) = ptr;
1794 func (sp [0].data.p, sp [1].data.i);
1797 case MINT_ICALL_PP_P: {
1798 gpointer (*func)(gpointer,gpointer) = ptr;
1800 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1803 case MINT_ICALL_PI_P: {
1804 gpointer (*func)(gpointer,int) = ptr;
1806 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1809 case MINT_ICALL_PPP_V: {
1810 void (*func)(gpointer,gpointer,gpointer) = ptr;
1812 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1815 case MINT_ICALL_PPI_V: {
1816 void (*func)(gpointer,gpointer,int) = ptr;
1818 func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1822 g_assert_not_reached ();
1825 context->env_frame = old_env_frame;
1826 context->current_env = old_env;
1832 * These functions are the entry points into the interpreter from compiled code.
1833 * They are called by the interp_in wrappers. They have the following signature:
1834 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1835 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1836 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1837 * more wrappers then these functions.
1838 * this/static * ret/void * 16 arguments -> 64 functions.
1841 #define MAX_INTERP_ENTRY_ARGS 8
1843 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1844 InterpEntryData data; \
1845 (data).rmethod = (_method); \
1846 (data).res = (_res); \
1847 (data).this_arg = (_this_arg); \
1848 (data).many_args = NULL;
1850 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
1851 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1852 interp_entry (&data); \
1854 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
1855 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1856 (data).args [0] = arg1; \
1857 interp_entry (&data); \
1859 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
1860 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1861 (data).args [0] = arg1; \
1862 (data).args [1] = arg2; \
1863 interp_entry (&data); \
1865 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
1866 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1867 (data).args [0] = arg1; \
1868 (data).args [1] = arg2; \
1869 (data).args [2] = arg3; \
1870 interp_entry (&data); \
1872 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
1873 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1874 (data).args [0] = arg1; \
1875 (data).args [1] = arg2; \
1876 (data).args [2] = arg3; \
1877 (data).args [3] = arg4; \
1878 interp_entry (&data); \
1880 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
1881 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1882 (data).args [0] = arg1; \
1883 (data).args [1] = arg2; \
1884 (data).args [2] = arg3; \
1885 (data).args [3] = arg4; \
1886 (data).args [4] = arg5; \
1887 interp_entry (&data); \
1889 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
1890 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1891 (data).args [0] = arg1; \
1892 (data).args [1] = arg2; \
1893 (data).args [2] = arg3; \
1894 (data).args [3] = arg4; \
1895 (data).args [4] = arg5; \
1896 (data).args [5] = arg6; \
1897 interp_entry (&data); \
1899 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
1900 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1901 (data).args [0] = arg1; \
1902 (data).args [1] = arg2; \
1903 (data).args [2] = arg3; \
1904 (data).args [3] = arg4; \
1905 (data).args [4] = arg5; \
1906 (data).args [5] = arg6; \
1907 (data).args [6] = arg7; \
1908 interp_entry (&data); \
1910 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
1911 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1912 (data).args [0] = arg1; \
1913 (data).args [1] = arg2; \
1914 (data).args [2] = arg3; \
1915 (data).args [3] = arg4; \
1916 (data).args [4] = arg5; \
1917 (data).args [5] = arg6; \
1918 (data).args [6] = arg7; \
1919 (data).args [7] = arg8; \
1920 interp_entry (&data); \
1923 #define ARGLIST0 RuntimeMethod *rmethod
1924 #define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
1925 #define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
1926 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
1927 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
1928 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
1929 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
1930 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
1931 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *rmethod
1933 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
1934 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
1935 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
1936 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
1937 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
1938 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
1939 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
1940 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
1941 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
1942 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
1943 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
1944 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
1945 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
1946 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
1947 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
1948 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
1949 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
1950 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
1951 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
1952 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
1953 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
1954 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
1955 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
1956 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
1957 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
1958 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
1959 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
1960 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
1961 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
1962 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
1963 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
1964 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
1965 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
1966 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
1967 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod)
1968 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod)
1970 #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
1972 gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
1973 gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
1974 gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
1975 gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
1977 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
1979 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1981 INTERP_ENTRY_BASE (rmethod, this_arg, res);
1982 data.many_args = args;
1983 interp_entry (&data);
1987 * mono_interp_create_method_pointer:
1989 * Return a function pointer which can be used to call METHOD using the
1990 * interpreter. Return NULL for methods which are not supported.
1993 mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
1996 MonoMethodSignature *sig = mono_method_signature (method);
1997 MonoMethod *wrapper;
1998 RuntimeMethod *rmethod;
2000 /* HACK: method_ptr of delegate should point to a runtime method*/
2001 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2002 return mono_interp_get_runtime_method (mono_domain_get (), method, error);
2004 rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
2005 if (rmethod->jit_entry)
2006 return rmethod->jit_entry;
2007 wrapper = mini_get_interp_in_wrapper (sig);
2009 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2010 mono_error_assert_ok (error);
2012 //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2013 gpointer entry_func;
2014 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2015 entry_func = interp_entry_general;
2016 } else if (sig->hasthis) {
2017 if (sig->ret->type == MONO_TYPE_VOID)
2018 entry_func = entry_funcs_instance [sig->param_count];
2020 entry_func = entry_funcs_instance_ret [sig->param_count];
2022 if (sig->ret->type == MONO_TYPE_VOID)
2023 entry_func = entry_funcs_static [sig->param_count];
2025 entry_func = entry_funcs_static_ret [sig->param_count];
2027 g_assert (entry_func);
2029 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2030 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2031 ftndesc->addr = entry_func;
2032 ftndesc->arg = rmethod;
2033 mono_error_assert_ok (error);
2036 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2037 * rgctx register using a trampoline.
2041 g_assert (!mono_aot_only);
2042 addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2044 mono_memory_barrier ();
2045 rmethod->jit_entry = addr;
2051 static int opcode_counts[512];
2053 #define COUNT_OP(op) opcode_counts[op]++
2055 #define COUNT_OP(op)
2059 #define DUMP_INSTR() \
2060 if (tracing > 1) { \
2062 if (sp > frame->stack) { \
2063 ins = dump_stack (frame->stack, sp); \
2065 ins = g_strdup (""); \
2069 char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
2070 g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
2072 mono_interp_dis_mintop(rtm->code, ip); \
2073 g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
2077 #define DUMP_INSTR()
2081 #define USE_COMPUTED_GOTO 1
2083 #if USE_COMPUTED_GOTO
2084 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2085 #define MINT_IN_CASE(x) LAB_ ## x:
2087 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2089 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2091 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2093 #define MINT_IN_SWITCH(op) switch (op)
2094 #define MINT_IN_CASE(x) case x:
2095 #define MINT_IN_BREAK break
2096 #define MINT_IN_DEFAULT default:
2100 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2103 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally)
2105 MonoInvocation child_frame;
2106 GSList *finally_ips = NULL;
2107 const unsigned short *endfinally_ip = NULL;
2108 const unsigned short *ip = NULL;
2109 register stackval *sp;
2112 gint tracing = global_tracing;
2113 unsigned char *vtalloc;
2118 unsigned char *vt_sp;
2119 unsigned char *locals;
2121 MonoObject *o = NULL;
2123 #if USE_COMPUTED_GOTO
2124 static void *in_labels[] = {
2125 #define OPDEF(a,b,c,d) \
2127 #include "mintops.def"
2132 frame->ex_handler = NULL;
2134 context->current_frame = frame;
2136 debug_enter (frame, &tracing);
2138 if (!frame->runtime_method->transformed) {
2139 context->managed_code = 0;
2141 char *mn = mono_method_full_name (frame->runtime_method->method, TRUE);
2142 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2148 /* Use the parent frame as the current frame is not complete yet */
2149 interp_push_lmf (&ext, frame->parent);
2151 frame->ex = mono_interp_transform_method (frame->runtime_method, context);
2152 context->managed_code = 1;
2154 interp_pop_lmf (&ext);
2163 rtm = frame->runtime_method;
2164 if (!start_with_ip ) {
2165 frame->args = alloca (rtm->alloca_size);
2166 memset (frame->args, 0, rtm->alloca_size);
2172 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2173 vt_sp = (unsigned char *) sp + rtm->stack_size;
2177 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2178 frame->locals = locals;
2179 child_frame.parent = frame;
2181 if (filter_exception) {
2182 sp->data.p = filter_exception;
2187 * using while (ip < end) may result in a 15% performance drop,
2188 * but it may be useful for debug
2192 /* g_assert (sp >= frame->stack); */
2193 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2195 MINT_IN_SWITCH (*ip) {
2196 MINT_IN_CASE(MINT_INITLOCALS)
2197 memset (locals, 0, rtm->locals_size);
2200 MINT_IN_CASE(MINT_NOP)
2203 MINT_IN_CASE(MINT_BREAK) {
2208 interp_push_lmf (&ext, frame);
2210 mono_debugger_agent_user_break ();
2212 interp_pop_lmf (&ext);
2215 MINT_IN_CASE(MINT_LDNULL)
2220 MINT_IN_CASE(MINT_VTRESULT) {
2221 int ret_size = * (guint16 *)(ip + 1);
2222 unsigned char *ret_vt_sp = vt_sp;
2223 vt_sp -= READ32(ip + 2);
2225 memmove (vt_sp, ret_vt_sp, ret_size);
2226 sp [-1].data.p = vt_sp;
2227 vt_sp += (ret_size + 7) & ~7;
2232 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2233 MINT_IN_CASE(MINT_LDC_I4_M1)
2236 MINT_IN_CASE(MINT_LDC_I4_0)
2239 MINT_IN_CASE(MINT_LDC_I4_1)
2242 MINT_IN_CASE(MINT_LDC_I4_2)
2245 MINT_IN_CASE(MINT_LDC_I4_3)
2248 MINT_IN_CASE(MINT_LDC_I4_4)
2251 MINT_IN_CASE(MINT_LDC_I4_5)
2254 MINT_IN_CASE(MINT_LDC_I4_6)
2257 MINT_IN_CASE(MINT_LDC_I4_7)
2260 MINT_IN_CASE(MINT_LDC_I4_8)
2263 MINT_IN_CASE(MINT_LDC_I4_S)
2264 sp->data.i = *(const short *)(ip + 1);
2268 MINT_IN_CASE(MINT_LDC_I4)
2270 sp->data.i = READ32 (ip);
2274 MINT_IN_CASE(MINT_LDC_I8)
2276 sp->data.l = READ64 (ip);
2280 MINT_IN_CASE(MINT_LDC_R4) {
2284 sp->data.f = * (float *)&val;
2289 MINT_IN_CASE(MINT_LDC_R8)
2290 sp->data.l = READ64 (ip + 1); /* note union usage */
2294 MINT_IN_CASE(MINT_DUP)
2299 MINT_IN_CASE(MINT_DUP_VT)
2300 i32 = READ32 (ip + 1);
2302 memcpy(sp->data.p, sp [-1].data.p, i32);
2303 vt_sp += (i32 + 7) & ~7;
2307 MINT_IN_CASE(MINT_POP) {
2308 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2310 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2315 MINT_IN_CASE(MINT_JMP) {
2316 RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
2317 if (!new_method->transformed) {
2319 frame->ex = mono_interp_transform_method (new_method, context);
2324 if (new_method->alloca_size > rtm->alloca_size)
2325 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size);
2326 rtm = frame->runtime_method = new_method;
2327 vt_sp = (unsigned char *) sp + rtm->stack_size;
2331 locals = vt_sp + rtm->vt_stack_size;
2332 frame->locals = locals;
2333 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2336 MINT_IN_CASE(MINT_CALLI) {
2337 MonoMethodSignature *csignature;
2338 stackval *endsp = sp;
2342 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2346 child_frame.runtime_method = sp->data.p;
2349 child_frame.retval = sp;
2350 /* decrement by the actual number of args */
2351 sp -= csignature->param_count;
2352 if (csignature->hasthis)
2354 child_frame.stack_args = sp;
2356 #ifndef DISABLE_REMOTING
2357 /* `this' can be NULL for string:.ctor */
2358 if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
2359 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2360 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2363 if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2364 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
2365 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2368 if (csignature->hasthis) {
2369 MonoObject *this_arg = sp->data.p;
2371 if (this_arg->vtable->klass->valuetype) {
2372 gpointer *unboxed = mono_object_unbox (this_arg);
2373 sp [0].data.p = unboxed;
2377 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2379 context->current_frame = frame;
2381 if (context->has_resume_state) {
2382 if (frame == context->handler_frame)
2383 SET_RESUME_STATE (context);
2388 if (child_frame.ex) {
2390 * An exception occurred, need to run finally, fault and catch handlers..
2392 frame->ex = child_frame.ex;
2393 goto handle_finally;
2396 /* need to handle typedbyref ... */
2397 if (csignature->ret->type != MONO_TYPE_VOID) {
2403 MINT_IN_CASE(MINT_CALLI_NAT) {
2404 MonoMethodSignature *csignature;
2405 stackval *endsp = sp;
2406 unsigned char *code = NULL;
2410 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2415 child_frame.runtime_method = NULL;
2418 child_frame.retval = sp;
2419 /* decrement by the actual number of args */
2420 sp -= csignature->param_count;
2421 if (csignature->hasthis)
2423 child_frame.stack_args = sp;
2424 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2426 context->current_frame = frame;
2428 if (context->has_resume_state) {
2429 if (frame == context->handler_frame)
2430 SET_RESUME_STATE (context);
2435 if (child_frame.ex) {
2437 * An exception occurred, need to run finally, fault and catch handlers..
2439 frame->ex = child_frame.ex;
2440 if (context->search_for_handler) {
2441 context->search_for_handler = 0;
2442 goto handle_exception;
2444 goto handle_finally;
2447 /* need to handle typedbyref ... */
2448 if (csignature->ret->type != MONO_TYPE_VOID) {
2454 MINT_IN_CASE(MINT_CALL) {
2455 stackval *endsp = sp;
2459 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
2462 child_frame.retval = sp;
2463 /* decrement by the actual number of args */
2464 sp -= child_frame.runtime_method->param_count;
2465 if (child_frame.runtime_method->hasthis)
2467 child_frame.stack_args = sp;
2469 #ifndef DISABLE_REMOTING
2470 /* `this' can be NULL for string:.ctor */
2471 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
2472 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2473 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2477 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2479 context->current_frame = frame;
2481 if (context->has_resume_state) {
2482 if (frame == context->handler_frame)
2483 SET_RESUME_STATE (context);
2488 if (child_frame.ex) {
2490 * An exception occurred, need to run finally, fault and catch handlers..
2492 frame->ex = child_frame.ex;
2493 goto handle_exception;;
2496 /* need to handle typedbyref ... */
2501 MINT_IN_CASE(MINT_VCALL) {
2504 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
2508 child_frame.retval = sp;
2509 /* decrement by the actual number of args */
2510 sp -= child_frame.runtime_method->param_count;
2511 if (child_frame.runtime_method->hasthis) {
2513 MonoObject *this_arg = sp->data.p;
2515 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2517 child_frame.stack_args = sp;
2519 #ifndef DISABLE_REMOTING
2520 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
2521 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2522 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2526 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2528 context->current_frame = frame;
2530 if (context->has_resume_state) {
2531 if (frame == context->handler_frame)
2532 SET_RESUME_STATE (context);
2537 if (child_frame.ex) {
2539 * An exception occurred, need to run finally, fault and catch handlers..
2541 frame->ex = child_frame.ex;
2542 goto handle_finally;
2547 MINT_IN_CASE(MINT_JIT_CALL) {
2548 MonoMethodSignature *sig;
2549 RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
2550 MonoFtnDesc ftndesc;
2551 guint8 res_buf [256];
2555 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
2558 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2559 * by ref and return a return value using an explicit return value argument.
2561 if (!rmethod->jit_wrapper) {
2562 MonoMethod *method = rmethod->method;
2565 sig = mono_method_signature (method);
2568 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2569 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2571 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
2572 mono_error_assert_ok (&error);
2574 gpointer addr = mono_jit_compile_method_jit_only (method, &error);
2576 mono_error_assert_ok (&error);
2578 rmethod->jit_addr = addr;
2579 rmethod->jit_sig = sig;
2580 mono_memory_barrier ();
2581 rmethod->jit_wrapper = jit_wrapper;
2584 sig = rmethod->jit_sig;
2589 sp -= sig->param_count;
2593 ftndesc.addr = rmethod->jit_addr;
2596 // FIXME: Optimize this
2600 int stack_index = 0;
2601 if (rmethod->hasthis) {
2602 args [pindex ++] = sp [0].data.p;
2605 type = rmethod->rtype;
2606 if (type->type != MONO_TYPE_VOID) {
2607 if (MONO_TYPE_ISSTRUCT (type))
2608 args [pindex ++] = vt_sp;
2610 args [pindex ++] = res_buf;
2612 for (int i = 0; i < rmethod->param_count; ++i) {
2613 MonoType *t = rmethod->param_types [i];
2614 stackval *sval = &sp [stack_index + i];
2615 if (sig->params [i]->byref) {
2616 args [pindex ++] = sval->data.p;
2617 } else if (MONO_TYPE_ISSTRUCT (t)) {
2618 args [pindex ++] = sval->data.p;
2619 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2620 args [pindex ++] = &sval->data.p;
2629 case MONO_TYPE_VALUETYPE:
2630 args [pindex ++] = &sval->data.i;
2633 case MONO_TYPE_FNPTR:
2636 case MONO_TYPE_OBJECT:
2637 args [pindex ++] = &sval->data.p;
2641 args [pindex ++] = &sval->data.l;
2644 printf ("%s\n", mono_type_full_name (t));
2645 g_assert_not_reached ();
2650 interp_push_lmf (&ext, frame);
2654 void (*func)(gpointer) = rmethod->jit_wrapper;
2660 void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
2662 func (args [0], &ftndesc);
2666 void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2668 func (args [0], args [1], &ftndesc);
2672 void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2674 func (args [0], args [1], args [2], &ftndesc);
2678 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2680 func (args [0], args [1], args [2], args [3], &ftndesc);
2684 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2686 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2690 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2692 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2696 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2698 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2702 g_assert_not_reached ();
2706 interp_pop_lmf (&ext);
2708 if (context->has_resume_state) {
2710 * If this bit is set, it means the call has thrown the exception, and we
2711 * reached this point because the EH code in mono_handle_exception ()
2712 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2713 * has set the fields in context to indicate where we have to resume execution.
2715 if (frame == context->handler_frame)
2716 SET_RESUME_STATE (context);
2721 MonoType *rtype = rmethod->rtype;
2722 switch (rtype->type) {
2723 case MONO_TYPE_VOID:
2724 case MONO_TYPE_OBJECT:
2725 case MONO_TYPE_STRING:
2726 case MONO_TYPE_CLASS:
2727 case MONO_TYPE_ARRAY:
2728 case MONO_TYPE_SZARRAY:
2731 sp->data.p = *(gpointer*)res_buf;
2734 sp->data.i = *(gint8*)res_buf;
2737 sp->data.i = *(guint8*)res_buf;
2740 sp->data.i = *(gint16*)res_buf;
2743 sp->data.i = *(guint16*)res_buf;
2746 sp->data.i = *(gint32*)res_buf;
2749 sp->data.i = *(guint32*)res_buf;
2751 case MONO_TYPE_VALUETYPE:
2752 /* The result was written to vt_sp */
2755 case MONO_TYPE_GENERICINST:
2756 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2757 sp->data.p = *(gpointer*)res_buf;
2759 /* The result was written to vt_sp */
2764 printf ("%s\n", mono_type_full_name (rtype));
2765 g_assert_not_reached ();
2768 if (rtype->type != MONO_TYPE_VOID)
2773 MINT_IN_CASE(MINT_CALLVIRT) {
2774 stackval *endsp = sp;
2775 MonoObject *this_arg;
2780 token = * (unsigned short *)(ip + 1);
2782 child_frame.runtime_method = rtm->data_items [token];
2784 child_frame.retval = sp;
2786 /* decrement by the actual number of args */
2787 sp -= child_frame.runtime_method->param_count + 1;
2788 child_frame.stack_args = sp;
2789 this_arg = sp->data.p;
2791 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2792 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2794 MonoClass *this_class = this_arg->vtable->klass;
2795 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2797 gpointer *unboxed = mono_object_unbox (this_arg);
2798 sp [0].data.p = unboxed;
2801 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2803 context->current_frame = frame;
2805 if (context->has_resume_state) {
2806 if (frame == context->handler_frame)
2807 SET_RESUME_STATE (context);
2812 if (child_frame.ex) {
2814 * An exception occurred, need to run finally, fault and catch handlers..
2816 frame->ex = child_frame.ex;
2817 if (context->search_for_handler) {
2818 context->search_for_handler = 0;
2819 goto handle_exception;
2821 goto handle_finally;
2824 /* need to handle typedbyref ... */
2829 MINT_IN_CASE(MINT_VCALLVIRT) {
2830 MonoObject *this_arg;
2835 token = * (unsigned short *)(ip + 1);
2837 child_frame.runtime_method = rtm->data_items [token];
2839 child_frame.retval = sp;
2841 /* decrement by the actual number of args */
2842 sp -= child_frame.runtime_method->param_count + 1;
2843 child_frame.stack_args = sp;
2844 this_arg = sp->data.p;
2846 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2847 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2849 MonoClass *this_class = this_arg->vtable->klass;
2850 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2851 gpointer *unboxed = mono_object_unbox (this_arg);
2852 sp [0].data.p = unboxed;
2855 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2857 context->current_frame = frame;
2859 if (context->has_resume_state) {
2860 if (frame == context->handler_frame)
2861 SET_RESUME_STATE (context);
2866 if (child_frame.ex) {
2868 * An exception occurred, need to run finally, fault and catch handlers..
2870 frame->ex = child_frame.ex;
2871 if (context->search_for_handler) {
2872 context->search_for_handler = 0;
2873 goto handle_exception;
2875 goto handle_finally;
2879 MINT_IN_CASE(MINT_CALLRUN)
2880 ves_runtime_method (frame, context);
2883 goto handle_exception;
2886 MINT_IN_CASE(MINT_RET)
2888 *frame->retval = *sp;
2889 if (sp > frame->stack)
2890 g_warning ("ret: more values on stack: %d", sp-frame->stack);
2892 MINT_IN_CASE(MINT_RET_VOID)
2893 if (sp > frame->stack)
2894 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->runtime_method->method, TRUE));
2896 MINT_IN_CASE(MINT_RET_VT)
2897 i32 = READ32(ip + 1);
2899 memcpy(frame->retval->data.p, sp->data.p, i32);
2900 if (sp > frame->stack)
2901 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2903 MINT_IN_CASE(MINT_BR_S)
2904 ip += (short) *(ip + 1);
2906 MINT_IN_CASE(MINT_BR)
2907 ip += (gint32) READ32(ip + 1);
2909 #define ZEROP_S(datamem, op) \
2911 if (sp->data.datamem op 0) \
2912 ip += * (gint16 *)(ip + 1); \
2916 #define ZEROP(datamem, op) \
2918 if (sp->data.datamem op 0) \
2919 ip += READ32(ip + 1); \
2923 MINT_IN_CASE(MINT_BRFALSE_I4_S)
2926 MINT_IN_CASE(MINT_BRFALSE_I8_S)
2929 MINT_IN_CASE(MINT_BRFALSE_R8_S)
2932 MINT_IN_CASE(MINT_BRFALSE_I4)
2935 MINT_IN_CASE(MINT_BRFALSE_I8)
2938 MINT_IN_CASE(MINT_BRFALSE_R8)
2941 MINT_IN_CASE(MINT_BRTRUE_I4_S)
2944 MINT_IN_CASE(MINT_BRTRUE_I8_S)
2947 MINT_IN_CASE(MINT_BRTRUE_R8_S)
2950 MINT_IN_CASE(MINT_BRTRUE_I4)
2953 MINT_IN_CASE(MINT_BRTRUE_I8)
2956 MINT_IN_CASE(MINT_BRTRUE_R8)
2959 #define CONDBR_S(cond) \
2962 ip += * (gint16 *)(ip + 1); \
2965 #define BRELOP_S(datamem, op) \
2966 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2968 #define CONDBR(cond) \
2971 ip += READ32(ip + 1); \
2975 #define BRELOP(datamem, op) \
2976 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2978 MINT_IN_CASE(MINT_BEQ_I4_S)
2981 MINT_IN_CASE(MINT_BEQ_I8_S)
2984 MINT_IN_CASE(MINT_BEQ_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_BEQ_I4)
2990 MINT_IN_CASE(MINT_BEQ_I8)
2993 MINT_IN_CASE(MINT_BEQ_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_BGE_I4_S)
2999 MINT_IN_CASE(MINT_BGE_I8_S)
3002 MINT_IN_CASE(MINT_BGE_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_BGE_I4)
3008 MINT_IN_CASE(MINT_BGE_I8)
3011 MINT_IN_CASE(MINT_BGE_R8)
3012 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3014 MINT_IN_CASE(MINT_BGT_I4_S)
3017 MINT_IN_CASE(MINT_BGT_I8_S)
3020 MINT_IN_CASE(MINT_BGT_R8_S)
3021 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3023 MINT_IN_CASE(MINT_BGT_I4)
3026 MINT_IN_CASE(MINT_BGT_I8)
3029 MINT_IN_CASE(MINT_BGT_R8)
3030 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3032 MINT_IN_CASE(MINT_BLT_I4_S)
3035 MINT_IN_CASE(MINT_BLT_I8_S)
3038 MINT_IN_CASE(MINT_BLT_R8_S)
3039 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3041 MINT_IN_CASE(MINT_BLT_I4)
3044 MINT_IN_CASE(MINT_BLT_I8)
3047 MINT_IN_CASE(MINT_BLT_R8)
3048 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3050 MINT_IN_CASE(MINT_BLE_I4_S)
3053 MINT_IN_CASE(MINT_BLE_I8_S)
3056 MINT_IN_CASE(MINT_BLE_R8_S)
3057 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3059 MINT_IN_CASE(MINT_BLE_I4)
3062 MINT_IN_CASE(MINT_BLE_I8)
3065 MINT_IN_CASE(MINT_BLE_R8)
3066 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3068 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3071 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3074 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3075 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3077 MINT_IN_CASE(MINT_BNE_UN_I4)
3080 MINT_IN_CASE(MINT_BNE_UN_I8)
3083 MINT_IN_CASE(MINT_BNE_UN_R8)
3084 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3087 #define BRELOP_S_CAST(datamem, op, type) \
3089 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3090 ip += * (gint16 *)(ip + 1); \
3094 #define BRELOP_CAST(datamem, op, type) \
3096 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3097 ip += READ32(ip + 1); \
3101 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3102 BRELOP_S_CAST(i, >=, guint32);
3104 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3105 BRELOP_S_CAST(l, >=, guint64);
3107 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3108 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3110 MINT_IN_CASE(MINT_BGE_UN_I4)
3111 BRELOP_CAST(i, >=, guint32);
3113 MINT_IN_CASE(MINT_BGE_UN_I8)
3114 BRELOP_CAST(l, >=, guint64);
3116 MINT_IN_CASE(MINT_BGE_UN_R8)
3117 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3119 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3120 BRELOP_S_CAST(i, >, guint32);
3122 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3123 BRELOP_S_CAST(l, >, guint64);
3125 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3126 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3128 MINT_IN_CASE(MINT_BGT_UN_I4)
3129 BRELOP_CAST(i, >, guint32);
3131 MINT_IN_CASE(MINT_BGT_UN_I8)
3132 BRELOP_CAST(l, >, guint64);
3134 MINT_IN_CASE(MINT_BGT_UN_R8)
3135 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3137 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3138 BRELOP_S_CAST(i, <=, guint32);
3140 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3141 BRELOP_S_CAST(l, <=, guint64);
3143 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3144 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3146 MINT_IN_CASE(MINT_BLE_UN_I4)
3147 BRELOP_CAST(i, <=, guint32);
3149 MINT_IN_CASE(MINT_BLE_UN_I8)
3150 BRELOP_CAST(l, <=, guint64);
3152 MINT_IN_CASE(MINT_BLE_UN_R8)
3153 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3155 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3156 BRELOP_S_CAST(i, <, guint32);
3158 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3159 BRELOP_S_CAST(l, <, guint64);
3161 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3162 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3164 MINT_IN_CASE(MINT_BLT_UN_I4)
3165 BRELOP_CAST(i, <, guint32);
3167 MINT_IN_CASE(MINT_BLT_UN_I8)
3168 BRELOP_CAST(l, <, guint64);
3170 MINT_IN_CASE(MINT_BLT_UN_R8)
3171 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3173 MINT_IN_CASE(MINT_SWITCH) {
3175 const unsigned short *st;
3181 if ((guint32)sp->data.i < n) {
3183 ip += 2 * (guint32)sp->data.i;
3184 offset = READ32 (ip);
3191 MINT_IN_CASE(MINT_LDIND_I1)
3193 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3195 MINT_IN_CASE(MINT_LDIND_U1)
3197 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3199 MINT_IN_CASE(MINT_LDIND_I2)
3201 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3203 MINT_IN_CASE(MINT_LDIND_U2)
3205 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3207 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3208 MINT_IN_CASE(MINT_LDIND_U4)
3210 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3212 MINT_IN_CASE(MINT_LDIND_I8)
3214 /* memmove handles unaligned case */
3215 memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3217 MINT_IN_CASE(MINT_LDIND_I) {
3218 guint16 offset = * (guint16 *)(ip + 1);
3219 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3223 MINT_IN_CASE(MINT_LDIND_R4)
3225 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3227 MINT_IN_CASE(MINT_LDIND_R8)
3229 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3231 MINT_IN_CASE(MINT_LDIND_REF)
3233 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3235 MINT_IN_CASE(MINT_STIND_REF)
3238 mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
3240 MINT_IN_CASE(MINT_STIND_I1)
3243 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3245 MINT_IN_CASE(MINT_STIND_I2)
3248 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3250 MINT_IN_CASE(MINT_STIND_I4)
3253 * (gint32 *) sp->data.p = sp[1].data.i;
3255 MINT_IN_CASE(MINT_STIND_I)
3258 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3260 MINT_IN_CASE(MINT_STIND_I8)
3263 * (gint64 *) sp->data.p = sp[1].data.l;
3265 MINT_IN_CASE(MINT_STIND_R4)
3268 * (float *) sp->data.p = (gfloat)sp[1].data.f;
3270 MINT_IN_CASE(MINT_STIND_R8)
3273 * (double *) sp->data.p = sp[1].data.f;
3275 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3278 InterlockedWrite ((gint32 *) sp->data.p, sp [1].data.i);
3280 #define BINOP(datamem, op) \
3282 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3284 MINT_IN_CASE(MINT_ADD_I4)
3287 MINT_IN_CASE(MINT_ADD_I8)
3290 MINT_IN_CASE(MINT_ADD_R8)
3293 MINT_IN_CASE(MINT_ADD1_I4)
3297 MINT_IN_CASE(MINT_SUB_I4)
3300 MINT_IN_CASE(MINT_SUB_I8)
3303 MINT_IN_CASE(MINT_SUB_R8)
3306 MINT_IN_CASE(MINT_SUB1_I4)
3310 MINT_IN_CASE(MINT_MUL_I4)
3313 MINT_IN_CASE(MINT_MUL_I8)
3316 MINT_IN_CASE(MINT_MUL_R8)
3319 MINT_IN_CASE(MINT_DIV_I4)
3320 if (sp [-1].data.i == 0)
3321 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3322 if (sp [-1].data.i == (-1))
3323 THROW_EX (mono_get_exception_overflow (), ip);
3326 MINT_IN_CASE(MINT_DIV_I8)
3327 if (sp [-1].data.l == 0)
3328 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3329 if (sp [-1].data.l == (-1))
3330 THROW_EX (mono_get_exception_overflow (), ip);
3333 MINT_IN_CASE(MINT_DIV_R8)
3337 #define BINOP_CAST(datamem, op, type) \
3339 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3341 MINT_IN_CASE(MINT_DIV_UN_I4)
3342 if (sp [-1].data.i == 0)
3343 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3344 BINOP_CAST(i, /, guint32);
3346 MINT_IN_CASE(MINT_DIV_UN_I8)
3347 if (sp [-1].data.l == 0)
3348 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3349 BINOP_CAST(l, /, guint64);
3351 MINT_IN_CASE(MINT_REM_I4)
3352 if (sp [-1].data.i == 0)
3353 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3354 if (sp [-1].data.i == (-1))
3355 THROW_EX (mono_get_exception_overflow (), ip);
3358 MINT_IN_CASE(MINT_REM_I8)
3359 if (sp [-1].data.l == 0)
3360 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3361 if (sp [-1].data.l == (-1))
3362 THROW_EX (mono_get_exception_overflow (), ip);
3365 MINT_IN_CASE(MINT_REM_R8)
3366 /* FIXME: what do we actually do here? */
3368 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3371 MINT_IN_CASE(MINT_REM_UN_I4)
3372 if (sp [-1].data.i == 0)
3373 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3374 BINOP_CAST(i, %, guint32);
3376 MINT_IN_CASE(MINT_REM_UN_I8)
3377 if (sp [-1].data.l == 0)
3378 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3379 BINOP_CAST(l, %, guint64);
3381 MINT_IN_CASE(MINT_AND_I4)
3384 MINT_IN_CASE(MINT_AND_I8)
3387 MINT_IN_CASE(MINT_OR_I4)
3390 MINT_IN_CASE(MINT_OR_I8)
3393 MINT_IN_CASE(MINT_XOR_I4)
3396 MINT_IN_CASE(MINT_XOR_I8)
3400 #define SHIFTOP(datamem, op) \
3402 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3405 MINT_IN_CASE(MINT_SHL_I4)
3408 MINT_IN_CASE(MINT_SHL_I8)
3411 MINT_IN_CASE(MINT_SHR_I4)
3414 MINT_IN_CASE(MINT_SHR_I8)
3417 MINT_IN_CASE(MINT_SHR_UN_I4)
3419 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3422 MINT_IN_CASE(MINT_SHR_UN_I8)
3424 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3427 MINT_IN_CASE(MINT_NEG_I4)
3428 sp [-1].data.i = - sp [-1].data.i;
3431 MINT_IN_CASE(MINT_NEG_I8)
3432 sp [-1].data.l = - sp [-1].data.l;
3435 MINT_IN_CASE(MINT_NEG_R8)
3436 sp [-1].data.f = - sp [-1].data.f;
3439 MINT_IN_CASE(MINT_NOT_I4)
3440 sp [-1].data.i = ~ sp [-1].data.i;
3443 MINT_IN_CASE(MINT_NOT_I8)
3444 sp [-1].data.l = ~ sp [-1].data.l;
3447 MINT_IN_CASE(MINT_CONV_I1_I4)
3448 sp [-1].data.i = (gint8)sp [-1].data.i;
3451 MINT_IN_CASE(MINT_CONV_I1_I8)
3452 sp [-1].data.i = (gint8)sp [-1].data.l;
3455 MINT_IN_CASE(MINT_CONV_I1_R8)
3456 sp [-1].data.i = (gint8)sp [-1].data.f;
3459 MINT_IN_CASE(MINT_CONV_U1_I4)
3460 sp [-1].data.i = (guint8)sp [-1].data.i;
3463 MINT_IN_CASE(MINT_CONV_U1_I8)
3464 sp [-1].data.i = (guint8)sp [-1].data.l;
3467 MINT_IN_CASE(MINT_CONV_U1_R8)
3468 sp [-1].data.i = (guint8)sp [-1].data.f;
3471 MINT_IN_CASE(MINT_CONV_I2_I4)
3472 sp [-1].data.i = (gint16)sp [-1].data.i;
3475 MINT_IN_CASE(MINT_CONV_I2_I8)
3476 sp [-1].data.i = (gint16)sp [-1].data.l;
3479 MINT_IN_CASE(MINT_CONV_I2_R8)
3480 sp [-1].data.i = (gint16)sp [-1].data.f;
3483 MINT_IN_CASE(MINT_CONV_U2_I4)
3484 sp [-1].data.i = (guint16)sp [-1].data.i;
3487 MINT_IN_CASE(MINT_CONV_U2_I8)
3488 sp [-1].data.i = (guint16)sp [-1].data.l;
3491 MINT_IN_CASE(MINT_CONV_U2_R8)
3492 sp [-1].data.i = (guint16)sp [-1].data.f;
3495 MINT_IN_CASE(MINT_CONV_I4_R8)
3496 sp [-1].data.i = (gint32)sp [-1].data.f;
3499 MINT_IN_CASE(MINT_CONV_U4_I8)
3500 MINT_IN_CASE(MINT_CONV_I4_I8)
3501 sp [-1].data.i = (gint32)sp [-1].data.l;
3504 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3505 sp [-2].data.i = (gint32)sp [-2].data.l;
3508 MINT_IN_CASE(MINT_CONV_U4_R8)
3509 /* needed on arm64 */
3510 if (isinf (sp [-1].data.f))
3513 sp [-1].data.i = (guint32)sp [-1].data.f;
3516 MINT_IN_CASE(MINT_CONV_I8_I4)
3517 sp [-1].data.l = sp [-1].data.i;
3520 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3521 sp [-2].data.l = sp [-2].data.i;
3524 MINT_IN_CASE(MINT_CONV_I8_U4)
3525 sp [-1].data.l = (guint32)sp [-1].data.i;
3528 MINT_IN_CASE(MINT_CONV_I8_R8)
3529 sp [-1].data.l = (gint64)sp [-1].data.f;
3532 MINT_IN_CASE(MINT_CONV_R4_I4)
3533 sp [-1].data.f = (float)sp [-1].data.i;
3536 MINT_IN_CASE(MINT_CONV_R4_I8)
3537 sp [-1].data.f = (float)sp [-1].data.l;
3540 MINT_IN_CASE(MINT_CONV_R4_R8)
3541 sp [-1].data.f = (float)sp [-1].data.f;
3544 MINT_IN_CASE(MINT_CONV_R8_I4)
3545 sp [-1].data.f = (double)sp [-1].data.i;
3548 MINT_IN_CASE(MINT_CONV_R8_I8)
3549 sp [-1].data.f = (double)sp [-1].data.l;
3552 MINT_IN_CASE(MINT_CONV_U8_I4)
3553 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3556 MINT_IN_CASE(MINT_CONV_U8_R8)
3557 sp [-1].data.l = (guint64)sp [-1].data.f;
3560 MINT_IN_CASE(MINT_CPOBJ) {
3561 c = rtm->data_items[* (guint16 *)(ip + 1)];
3562 g_assert (c->valuetype);
3563 /* if this assertion fails, we need to add a write barrier */
3564 g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
3565 if (c->byval_arg.type == MONO_TYPE_VALUETYPE)
3566 stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
3568 stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
3573 MINT_IN_CASE(MINT_LDOBJ) {
3575 c = rtm->data_items[* (guint16 *)(ip + 1)];
3578 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
3579 int size = mono_class_value_size (c, NULL);
3580 sp [-1].data.p = vt_sp;
3581 vt_sp += (size + 7) & ~7;
3583 stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
3586 MINT_IN_CASE(MINT_LDSTR)
3587 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3591 MINT_IN_CASE(MINT_NEWOBJ) {
3592 MonoClass *newobj_class;
3593 MonoMethodSignature *csig;
3594 stackval valuetype_this;
3600 token = * (guint16 *)(ip + 1);
3603 child_frame.ip = NULL;
3604 child_frame.ex = NULL;
3606 child_frame.runtime_method = rtm->data_items [token];
3607 csig = mono_method_signature (child_frame.runtime_method->method);
3608 newobj_class = child_frame.runtime_method->method->klass;
3609 /*if (profiling_classes) {
3610 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3612 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3615 if (newobj_class->parent == mono_defaults.array_class) {
3616 sp -= csig->param_count;
3617 child_frame.stack_args = sp;
3618 o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
3620 THROW_EX (child_frame.ex, ip);
3621 goto array_constructed;
3624 g_assert (csig->hasthis);
3625 if (csig->param_count) {
3626 sp -= csig->param_count;
3627 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3629 child_frame.stack_args = sp;
3632 * First arg is the object.
3634 if (newobj_class->valuetype) {
3635 MonoType *t = &newobj_class->byval_arg;
3636 memset (&valuetype_this, 0, sizeof (stackval));
3637 if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3639 valuetype_this.data.p = vt_sp;
3641 sp->data.p = &valuetype_this;
3644 if (newobj_class != mono_defaults.string_class) {
3645 context->managed_code = 0;
3646 o = mono_object_new_checked (context->domain, newobj_class, &error);
3647 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3648 context->managed_code = 1;
3649 if (*mono_thread_interruption_request_flag ())
3650 mono_thread_interruption_checkpoint ();
3654 child_frame.retval = &retval;
3658 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3660 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
3662 context->current_frame = frame;
3664 if (context->has_resume_state) {
3665 if (frame == context->handler_frame)
3666 SET_RESUME_STATE (context);
3671 if (child_frame.ex) {
3673 * An exception occurred, need to run finally, fault and catch handlers..
3675 frame->ex = child_frame.ex;
3676 goto handle_finally;
3679 * a constructor returns void, but we need to return the object we created
3682 if (newobj_class->valuetype && !newobj_class->enumtype) {
3683 *sp = valuetype_this;
3684 } else if (newobj_class == mono_defaults.string_class) {
3692 MINT_IN_CASE(MINT_CASTCLASS)
3693 c = rtm->data_items [*(guint16 *)(ip + 1)];
3694 if ((o = sp [-1].data.p)) {
3695 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3696 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3698 THROW_EX (mono_get_exception_invalid_cast (), ip);
3702 MINT_IN_CASE(MINT_ISINST)
3703 c = rtm->data_items [*(guint16 *)(ip + 1)];
3704 if ((o = sp [-1].data.p)) {
3705 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3706 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3708 sp [-1].data.p = NULL;
3712 MINT_IN_CASE(MINT_CONV_R_UN_I4)
3713 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3716 MINT_IN_CASE(MINT_CONV_R_UN_I8)
3717 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3720 MINT_IN_CASE(MINT_UNBOX)
3721 c = rtm->data_items[*(guint16 *)(ip + 1)];
3725 THROW_EX (mono_get_exception_null_reference (), ip);
3727 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3728 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3729 if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
3730 THROW_EX (mono_get_exception_invalid_cast (), ip);
3732 sp [-1].data.p = mono_object_unbox (o);
3735 MINT_IN_CASE(MINT_THROW)
3737 frame->ex_handler = NULL;
3739 sp->data.p = mono_get_exception_null_reference ();
3741 THROW_EX ((MonoException *)sp->data.p, ip);
3743 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
3745 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3748 MINT_IN_CASE(MINT_LDFLDA)
3751 THROW_EX (mono_get_exception_null_reference (), ip);
3752 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3755 MINT_IN_CASE(MINT_CKNULL)
3758 THROW_EX (mono_get_exception_null_reference (), ip);
3762 #define LDFLD(datamem, fieldtype) \
3763 o = sp [-1].data.p; \
3765 THROW_EX (mono_get_exception_null_reference (), ip); \
3766 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3769 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
3770 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
3771 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
3772 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
3773 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
3774 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
3775 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
3776 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
3777 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
3778 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
3780 MINT_IN_CASE(MINT_LDFLD_VT)
3783 THROW_EX (mono_get_exception_null_reference (), ip);
3784 i32 = READ32(ip + 2);
3785 sp [-1].data.p = vt_sp;
3786 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3787 vt_sp += (i32 + 7) & ~7;
3791 MINT_IN_CASE(MINT_LDRMFLD) {
3793 MonoClassField *field;
3798 THROW_EX (mono_get_exception_null_reference (), ip);
3799 field = rtm->data_items[* (guint16 *)(ip + 1)];
3801 #ifndef DISABLE_REMOTING
3802 if (mono_object_is_transparent_proxy (o)) {
3803 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3805 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3806 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3809 addr = (char*)o + field->offset;
3811 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3815 MINT_IN_CASE(MINT_LDRMFLD_VT) {
3816 MonoClassField *field;
3822 THROW_EX (mono_get_exception_null_reference (), ip);
3823 field = rtm->data_items[* (guint16 *)(ip + 1)];
3824 i32 = READ32(ip + 2);
3826 #ifndef DISABLE_REMOTING
3827 if (mono_object_is_transparent_proxy (o)) {
3828 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3829 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3830 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3833 addr = (char*)o + field->offset;
3835 sp [-1].data.p = vt_sp;
3836 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3837 vt_sp += (i32 + 7) & ~7;
3838 memcpy(sp [-1].data.p, addr, i32);
3842 #define STFLD(datamem, fieldtype) \
3843 o = sp [-2].data.p; \
3845 THROW_EX (mono_get_exception_null_reference (), ip); \
3847 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3850 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3851 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3852 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3853 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3854 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3855 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3856 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3857 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3858 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3859 MINT_IN_CASE(MINT_STFLD_O)
3862 THROW_EX (mono_get_exception_null_reference (), ip);
3864 mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
3868 MINT_IN_CASE(MINT_STFLD_VT)
3871 THROW_EX (mono_get_exception_null_reference (), ip);
3872 i32 = READ32(ip + 2);
3874 memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32);
3875 vt_sp -= (i32 + 7) & ~7;
3879 MINT_IN_CASE(MINT_STRMFLD) {
3880 MonoClassField *field;
3884 THROW_EX (mono_get_exception_null_reference (), ip);
3886 field = rtm->data_items[* (guint16 *)(ip + 1)];
3889 #ifndef DISABLE_REMOTING
3890 if (mono_object_is_transparent_proxy (o)) {
3891 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3892 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3893 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3896 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3901 MINT_IN_CASE(MINT_STRMFLD_VT) {
3902 MonoClassField *field;
3906 THROW_EX (mono_get_exception_null_reference (), ip);
3907 field = rtm->data_items[* (guint16 *)(ip + 1)];
3908 i32 = READ32(ip + 2);
3911 #ifndef DISABLE_REMOTING
3912 if (mono_object_is_transparent_proxy (o)) {
3913 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3914 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3915 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3918 memcpy((char*)o + field->offset, sp [-1].data.p, i32);
3921 vt_sp -= (i32 + 7) & ~7;
3924 MINT_IN_CASE(MINT_LDSFLDA) {
3925 MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3926 sp->data.p = mono_class_static_field_address (context->domain, field);
3931 MINT_IN_CASE(MINT_LDSFLD) {
3932 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3933 gpointer addr = mono_class_static_field_address (context->domain, field);
3934 stackval_from_data (field->type, sp, addr, FALSE);
3939 MINT_IN_CASE(MINT_LDSFLD_VT) {
3940 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3941 gpointer addr = mono_class_static_field_address (context->domain, field);
3942 int size = READ32 (ip + 2);
3946 vt_sp += (size + 7) & ~7;
3947 stackval_from_data (field->type, sp, addr, FALSE);
3951 MINT_IN_CASE(MINT_STSFLD) {
3952 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3953 gpointer addr = mono_class_static_field_address (context->domain, field);
3956 stackval_to_data (field->type, sp, addr, FALSE);
3959 MINT_IN_CASE(MINT_STSFLD_VT) {
3960 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3961 gpointer addr = mono_class_static_field_address (context->domain, field);
3962 int size = READ32 (ip + 2);
3966 stackval_to_data (field->type, sp, addr, FALSE);
3967 vt_sp -= (size + 7) & ~7;
3970 MINT_IN_CASE(MINT_STOBJ_VT) {
3972 c = rtm->data_items[* (guint16 *)(ip + 1)];
3974 size = mono_class_value_size (c, NULL);
3975 memcpy(sp [-2].data.p, sp [-1].data.p, size);
3976 vt_sp -= (size + 7) & ~7;
3980 MINT_IN_CASE(MINT_STOBJ) {
3981 c = rtm->data_items[* (guint16 *)(ip + 1)];
3984 g_assert (!c->byval_arg.byref);
3985 if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
3986 mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
3988 stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
3992 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3993 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3994 THROW_EX (mono_get_exception_overflow (), ip);
3995 sp [-1].data.i = (guint32)sp [-1].data.f;
3998 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3999 if (sp [-1].data.i < 0)
4000 THROW_EX (mono_get_exception_overflow (), ip);
4001 sp [-1].data.l = sp [-1].data.i;
4004 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
4005 if (sp [-1].data.l < 0)
4006 THROW_EX (mono_get_exception_overflow (), ip);
4009 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
4010 if ((guint64) sp [-1].data.l > MYGINT64_MAX)
4011 THROW_EX (mono_get_exception_overflow (), ip);
4014 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
4015 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
4016 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
4017 THROW_EX (mono_get_exception_overflow (), ip);
4018 sp [-1].data.l = (guint64)sp [-1].data.f;
4021 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
4022 if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
4023 THROW_EX (mono_get_exception_overflow (), ip);
4024 sp [-1].data.l = (gint64)sp [-1].data.f;
4027 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
4028 if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
4029 THROW_EX (mono_get_exception_overflow (), ip);
4030 sp [-1].data.i = (mono_u)sp [-1].data.l;
4033 MINT_IN_CASE(MINT_BOX) {
4034 c = rtm->data_items [* (guint16 *)(ip + 1)];
4035 guint16 offset = * (guint16 *)(ip + 2);
4037 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
4038 int size = mono_class_value_size (c, NULL);
4039 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error);
4040 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4041 size = (size + 7) & ~7;
4044 stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
4045 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error);
4046 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4051 MINT_IN_CASE(MINT_NEWARR)
4052 sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
4053 if (!mono_error_ok (&error)) {
4054 THROW_EX (mono_error_convert_to_exception (&error), ip);
4056 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4058 /*if (profiling_classes) {
4059 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
4061 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
4065 MINT_IN_CASE(MINT_LDLEN)
4068 THROW_EX (mono_get_exception_null_reference (), ip);
4069 sp [-1].data.nati = mono_array_length ((MonoArray *)o);
4072 MINT_IN_CASE(MINT_GETCHR) {
4076 THROW_EX (mono_get_exception_null_reference (), ip);
4077 i32 = sp [-1].data.i;
4078 if (i32 < 0 || i32 >= mono_string_length (s))
4079 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4081 sp [-1].data.i = mono_string_chars(s)[i32];
4085 MINT_IN_CASE(MINT_STRLEN)
4089 THROW_EX (mono_get_exception_null_reference (), ip);
4090 sp [-1].data.i = mono_string_length ((MonoString*) o);
4092 MINT_IN_CASE(MINT_ARRAY_RANK)
4095 THROW_EX (mono_get_exception_null_reference (), ip);
4096 sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
4099 MINT_IN_CASE(MINT_LDELEMA)
4100 MINT_IN_CASE(MINT_LDELEMA_TC) {
4101 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
4103 MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
4104 guint16 numargs = *(guint16 *) (ip + 2);
4109 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
4111 THROW_EX (frame->ex, ip);
4116 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4117 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4118 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4119 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4120 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4121 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4122 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
4123 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
4124 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4125 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4126 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4127 MINT_IN_CASE(MINT_LDELEM_VT) {
4135 THROW_EX (mono_get_exception_null_reference (), ip);
4137 aindex = sp [1].data.i;
4138 if (aindex >= mono_array_length (o))
4139 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4142 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4145 case MINT_LDELEM_I1:
4146 sp [0].data.i = mono_array_get (o, gint8, aindex);
4148 case MINT_LDELEM_U1:
4149 sp [0].data.i = mono_array_get (o, guint8, aindex);
4151 case MINT_LDELEM_I2:
4152 sp [0].data.i = mono_array_get (o, gint16, aindex);
4154 case MINT_LDELEM_U2:
4155 sp [0].data.i = mono_array_get (o, guint16, aindex);
4158 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
4160 case MINT_LDELEM_I4:
4161 sp [0].data.i = mono_array_get (o, gint32, aindex);
4163 case MINT_LDELEM_U4:
4164 sp [0].data.i = mono_array_get (o, guint32, aindex);
4166 case MINT_LDELEM_I8:
4167 sp [0].data.l = mono_array_get (o, guint64, aindex);
4169 case MINT_LDELEM_R4:
4170 sp [0].data.f = mono_array_get (o, float, aindex);
4172 case MINT_LDELEM_R8:
4173 sp [0].data.f = mono_array_get (o, double, aindex);
4175 case MINT_LDELEM_REF:
4176 sp [0].data.p = mono_array_get (o, gpointer, aindex);
4178 case MINT_LDELEM_VT: {
4179 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4180 i32 = READ32 (ip + 2);
4181 char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4182 sp [0].data.vt = vt_sp;
4183 stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
4184 vt_sp += (i32 + 7) & ~7;
4196 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
4197 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4198 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4199 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4200 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4201 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4202 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4203 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4204 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4205 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4206 MINT_IN_CASE(MINT_STELEM_VT) {
4213 THROW_EX (mono_get_exception_null_reference (), ip);
4215 aindex = sp [1].data.i;
4216 if (aindex >= mono_array_length ((MonoArray *)o))
4217 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4221 mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4223 case MINT_STELEM_I1:
4224 mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4226 case MINT_STELEM_U1:
4227 mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4229 case MINT_STELEM_I2:
4230 mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4232 case MINT_STELEM_U2:
4233 mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4235 case MINT_STELEM_I4:
4236 mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4238 case MINT_STELEM_I8:
4239 mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4241 case MINT_STELEM_R4:
4242 mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
4244 case MINT_STELEM_R8:
4245 mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
4247 case MINT_STELEM_REF: {
4248 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error);
4249 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4250 if (sp [2].data.p && !isinst_obj)
4251 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4252 mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
4255 case MINT_STELEM_VT: {
4256 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4257 i32 = READ32 (ip + 2);
4258 char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4260 stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
4261 vt_sp -= (i32 + 7) & ~7;
4272 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4273 if (sp [-1].data.i < 0)
4274 THROW_EX (mono_get_exception_overflow (), ip);
4277 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4278 if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
4279 THROW_EX (mono_get_exception_overflow (), ip);
4280 sp [-1].data.i = (gint32) sp [-1].data.l;
4283 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4284 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
4285 THROW_EX (mono_get_exception_overflow (), ip);
4286 sp [-1].data.i = (gint32) sp [-1].data.l;
4289 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4290 if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
4291 THROW_EX (mono_get_exception_overflow (), ip);
4292 sp [-1].data.i = (gint32) sp [-1].data.f;
4295 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4296 if (sp [-1].data.i < 0)
4297 THROW_EX (mono_get_exception_overflow (), ip);
4300 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4301 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
4302 THROW_EX (mono_get_exception_overflow (), ip);
4303 sp [-1].data.i = (guint32) sp [-1].data.l;
4306 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4307 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
4308 THROW_EX (mono_get_exception_overflow (), ip);
4309 sp [-1].data.i = (guint32) sp [-1].data.f;
4312 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4313 if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
4314 THROW_EX (mono_get_exception_overflow (), ip);
4317 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4318 if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
4319 THROW_EX (mono_get_exception_overflow (), ip);
4320 sp [-1].data.i = (gint16) sp [-1].data.l;
4323 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4324 if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
4325 THROW_EX (mono_get_exception_overflow (), ip);
4326 sp [-1].data.i = (gint16) sp [-1].data.f;
4329 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4330 if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
4331 THROW_EX (mono_get_exception_overflow (), ip);
4334 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4335 if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
4336 THROW_EX (mono_get_exception_overflow (), ip);
4337 sp [-1].data.i = (guint16) sp [-1].data.l;
4340 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4341 if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
4342 THROW_EX (mono_get_exception_overflow (), ip);
4343 sp [-1].data.i = (guint16) sp [-1].data.f;
4346 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4347 if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
4348 THROW_EX (mono_get_exception_overflow (), ip);
4351 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4352 if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
4353 THROW_EX (mono_get_exception_overflow (), ip);
4354 sp [-1].data.i = (gint8) sp [-1].data.l;
4357 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4358 if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
4359 THROW_EX (mono_get_exception_overflow (), ip);
4360 sp [-1].data.i = (gint8) sp [-1].data.f;
4363 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4364 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
4365 THROW_EX (mono_get_exception_overflow (), ip);
4368 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4369 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
4370 THROW_EX (mono_get_exception_overflow (), ip);
4371 sp [-1].data.i = (guint8) sp [-1].data.l;
4374 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4375 if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
4376 THROW_EX (mono_get_exception_overflow (), ip);
4377 sp [-1].data.i = (guint8) sp [-1].data.f;
4381 MINT_IN_CASE(MINT_LDELEM)
4382 MINT_IN_CASE(MINT_STELEM)
4383 MINT_IN_CASE(MINT_UNBOX_ANY)
4385 MINT_IN_CASE(MINT_CKFINITE)
4386 if (!isfinite(sp [-1].data.f))
4387 THROW_EX (mono_get_exception_arithmetic (), ip);
4390 MINT_IN_CASE(MINT_MKREFANY) {
4391 c = rtm->data_items [*(guint16 *)(ip + 1)];
4393 /* The value address is on the stack */
4394 gpointer addr = sp [-1].data.p;
4395 /* Push the typedref value on the stack */
4396 sp [-1].data.p = vt_sp;
4397 vt_sp += sizeof (MonoTypedRef);
4399 MonoTypedRef *tref = sp [-1].data.p;
4401 tref->type = &c->byval_arg;
4407 MINT_IN_CASE(MINT_REFANYTYPE) {
4408 MonoTypedRef *tref = sp [-1].data.p;
4409 MonoType *type = tref->type;
4411 vt_sp -= sizeof (MonoTypedRef);
4412 sp [-1].data.p = vt_sp;
4414 *(gpointer*)sp [-1].data.p = type;
4418 MINT_IN_CASE(MINT_REFANYVAL) {
4419 MonoTypedRef *tref = sp [-1].data.p;
4420 gpointer addr = tref->value;
4422 vt_sp -= sizeof (MonoTypedRef);
4424 sp [-1].data.p = addr;
4428 MINT_IN_CASE(MINT_LDTOKEN)
4431 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4435 MINT_IN_CASE(MINT_ADD_OVF_I4)
4436 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4437 THROW_EX (mono_get_exception_overflow (), ip);
4440 MINT_IN_CASE(MINT_ADD_OVF_I8)
4441 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4442 THROW_EX (mono_get_exception_overflow (), ip);
4445 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4446 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4447 THROW_EX (mono_get_exception_overflow (), ip);
4448 BINOP_CAST(i, +, guint32);
4450 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4451 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4452 THROW_EX (mono_get_exception_overflow (), ip);
4453 BINOP_CAST(l, +, guint64);
4455 MINT_IN_CASE(MINT_MUL_OVF_I4)
4456 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4457 THROW_EX (mono_get_exception_overflow (), ip);
4460 MINT_IN_CASE(MINT_MUL_OVF_I8)
4461 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4462 THROW_EX (mono_get_exception_overflow (), ip);
4465 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4466 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4467 THROW_EX (mono_get_exception_overflow (), ip);
4468 BINOP_CAST(i, *, guint32);
4470 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4471 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4472 THROW_EX (mono_get_exception_overflow (), ip);
4473 BINOP_CAST(l, *, guint64);
4475 MINT_IN_CASE(MINT_SUB_OVF_I4)
4476 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4477 THROW_EX (mono_get_exception_overflow (), ip);
4480 MINT_IN_CASE(MINT_SUB_OVF_I8)
4481 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4482 THROW_EX (mono_get_exception_overflow (), ip);
4485 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4486 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4487 THROW_EX (mono_get_exception_overflow (), ip);
4488 BINOP_CAST(i, -, guint32);
4490 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4491 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4492 THROW_EX (mono_get_exception_overflow (), ip);
4493 BINOP_CAST(l, -, guint64);
4495 MINT_IN_CASE(MINT_ENDFINALLY)
4497 int clause_index = *ip;
4498 if (clause_index == exit_at_finally)
4500 while (sp > frame->stack) {
4504 ip = finally_ips->data;
4505 finally_ips = g_slist_remove (finally_ips, ip);
4512 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4513 MINT_IN_CASE(MINT_LEAVE_S)
4514 while (sp > frame->stack) {
4518 if (*ip == MINT_LEAVE_S) {
4519 ip += (short) *(ip + 1);
4521 ip += (gint32) READ32 (ip + 1);
4524 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4525 frame->ex_handler = NULL;
4528 goto handle_finally;
4530 MINT_IN_CASE(MINT_ICALL_V_V)
4531 MINT_IN_CASE(MINT_ICALL_V_P)
4532 MINT_IN_CASE(MINT_ICALL_P_V)
4533 MINT_IN_CASE(MINT_ICALL_P_P)
4534 MINT_IN_CASE(MINT_ICALL_PP_V)
4535 MINT_IN_CASE(MINT_ICALL_PI_V)
4536 MINT_IN_CASE(MINT_ICALL_PP_P)
4537 MINT_IN_CASE(MINT_ICALL_PI_P)
4538 MINT_IN_CASE(MINT_ICALL_PPP_V)
4539 MINT_IN_CASE(MINT_ICALL_PPI_V)
4540 sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
4541 if (*mono_thread_interruption_request_flag ()) {
4542 MonoException *exc = mono_thread_interruption_checkpoint ();
4545 context->search_for_handler = 1;
4548 if (frame->ex != NULL)
4549 goto handle_exception;
4552 MINT_IN_CASE(MINT_MONO_LDPTR)
4553 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
4557 MINT_IN_CASE(MINT_MONO_NEWOBJ)
4558 sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
4559 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4563 MINT_IN_CASE(MINT_MONO_FREE)
4566 g_error ("that doesn't seem right");
4567 g_free (sp->data.p);
4569 MINT_IN_CASE(MINT_MONO_RETOBJ)
4572 stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p,
4573 mono_method_signature (frame->runtime_method->method)->pinvoke);
4574 if (sp > frame->stack)
4575 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
4577 MINT_IN_CASE(MINT_MONO_TLS) {
4578 MonoTlsKey key = *(gint32 *)(ip + 1);
4579 sp->data.p = ((gpointer (*)()) mono_tls_get_tls_getter (key, FALSE)) ();
4584 MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
4587 context->original_domain = NULL;
4588 MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4589 gpointer tls_jit = ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4591 if (tls_domain != context->domain || !tls_jit)
4592 context->original_domain = mono_jit_thread_attach (context->domain);
4595 MINT_IN_CASE(MINT_MONO_JIT_DETACH)
4597 mono_jit_set_domain (context->original_domain);
4599 MINT_IN_CASE(MINT_SDB_INTR_LOC)
4600 if (G_UNLIKELY (ss_enabled)) {
4602 static void (*ss_tramp) (void);
4605 void *tramp = mini_get_single_step_trampoline ();
4606 mono_memory_barrier ();
4611 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
4612 * the address of that instruction is stored as the seq point address.
4616 interp_push_lmf (&ext, frame);
4618 * Use the same trampoline as the JIT. This ensures that
4619 * the debugger has the context for the last interpreter
4623 interp_pop_lmf (&ext);
4625 if (context->has_resume_state) {
4626 if (frame == context->handler_frame)
4627 SET_RESUME_STATE (context);
4634 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
4635 /* Just a placeholder for a breakpoint */
4638 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
4641 static void (*bp_tramp) (void);
4643 void *tramp = mini_get_breakpoint_trampoline ();
4644 mono_memory_barrier ();
4650 interp_push_lmf (&ext, frame);
4651 /* Use the same trampoline as the JIT */
4653 interp_pop_lmf (&ext);
4655 if (context->has_resume_state) {
4656 if (frame == context->handler_frame)
4657 SET_RESUME_STATE (context);
4666 #define RELOP(datamem, op) \
4668 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4670 MINT_IN_CASE(MINT_CEQ_I4)
4673 MINT_IN_CASE(MINT_CEQ0_I4)
4674 sp [-1].data.i = (sp [-1].data.i == 0);
4677 MINT_IN_CASE(MINT_CEQ_I8)
4680 MINT_IN_CASE(MINT_CEQ_R8)
4682 if (isunordered (sp [-1].data.f, sp [0].data.f))
4685 sp [-1].data.i = sp [-1].data.f == sp [0].data.f;
4688 MINT_IN_CASE(MINT_CGT_I4)
4691 MINT_IN_CASE(MINT_CGT_I8)
4694 MINT_IN_CASE(MINT_CGT_R8)
4696 if (isunordered (sp [-1].data.f, sp [0].data.f))
4699 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
4703 #define RELOP_CAST(datamem, op, type) \
4705 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4708 MINT_IN_CASE(MINT_CGT_UN_I4)
4709 RELOP_CAST(i, >, guint32);
4711 MINT_IN_CASE(MINT_CGT_UN_I8)
4712 RELOP_CAST(l, >, guint64);
4714 MINT_IN_CASE(MINT_CGT_UN_R8)
4716 if (isunordered (sp [-1].data.f, sp [0].data.f))
4719 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
4722 MINT_IN_CASE(MINT_CLT_I4)
4725 MINT_IN_CASE(MINT_CLT_I8)
4728 MINT_IN_CASE(MINT_CLT_R8)
4730 if (isunordered (sp [-1].data.f, sp [0].data.f))
4733 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
4736 MINT_IN_CASE(MINT_CLT_UN_I4)
4737 RELOP_CAST(i, <, guint32);
4739 MINT_IN_CASE(MINT_CLT_UN_I8)
4740 RELOP_CAST(l, <, guint64);
4742 MINT_IN_CASE(MINT_CLT_UN_R8)
4744 if (isunordered (sp [-1].data.f, sp [0].data.f))
4747 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
4750 MINT_IN_CASE(MINT_LDFTN) {
4751 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4756 MINT_IN_CASE(MINT_LDVIRTFTN) {
4757 RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
4761 THROW_EX (mono_get_exception_null_reference (), ip - 2);
4763 sp->data.p = get_virtual_method (context->domain, m, sp->data.p);
4768 #define LDARG(datamem, argtype) \
4769 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4773 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
4774 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
4775 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
4776 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
4777 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
4778 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
4779 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
4780 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
4781 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
4782 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_LDARG_VT)
4786 i32 = READ32(ip + 2);
4787 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
4788 vt_sp += (i32 + 7) & ~7;
4793 #define STARG(datamem, argtype) \
4795 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4798 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
4799 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
4800 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
4801 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
4802 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
4803 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
4804 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
4805 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
4806 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
4807 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
4809 MINT_IN_CASE(MINT_STARG_VT)
4810 i32 = READ32(ip + 2);
4812 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
4813 vt_sp -= (i32 + 7) & ~7;
4817 #define STINARG(datamem, argtype) \
4819 int n = * (guint16 *)(ip + 1); \
4820 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4824 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
4825 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
4826 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
4827 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
4828 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
4829 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
4830 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
4831 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
4832 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
4833 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
4835 MINT_IN_CASE(MINT_STINARG_VT) {
4836 int n = * (guint16 *)(ip + 1);
4837 i32 = READ32(ip + 2);
4838 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
4843 MINT_IN_CASE(MINT_LDARGA)
4844 sp->data.p = frame->args + * (guint16 *)(ip + 1);
4849 #define LDLOC(datamem, argtype) \
4850 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4854 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
4855 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
4856 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
4857 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
4858 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
4859 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
4860 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
4861 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
4862 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
4863 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
4865 MINT_IN_CASE(MINT_LDLOC_VT)
4867 i32 = READ32(ip + 2);
4868 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
4869 vt_sp += (i32 + 7) & ~7;
4874 MINT_IN_CASE(MINT_LDLOCA_S)
4875 sp->data.p = locals + * (guint16 *)(ip + 1);
4880 #define STLOC(datamem, argtype) \
4882 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4885 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
4886 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
4887 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
4889 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
4890 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
4892 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
4893 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
4894 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
4896 #define STLOC_NP(datamem, argtype) \
4897 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4900 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
4901 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
4903 MINT_IN_CASE(MINT_STLOC_VT)
4904 i32 = READ32(ip + 2);
4906 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
4907 vt_sp -= (i32 + 7) & ~7;
4911 MINT_IN_CASE(MINT_LOCALLOC) {
4912 if (sp != frame->stack + 1) /*FIX?*/
4913 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
4915 int len = sp [-1].data.i;
4916 sp [-1].data.p = alloca (len);
4917 MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
4918 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4919 if (header && header->init_locals)
4920 memset (sp [-1].data.p, 0, len);
4924 MINT_IN_CASE(MINT_ENDFILTER)
4925 /* top of stack is result of filter */
4926 frame->retval = &sp [-1];
4928 MINT_IN_CASE(MINT_INITOBJ)
4930 memset (sp->data.vt, 0, READ32(ip + 1));
4933 MINT_IN_CASE(MINT_CPBLK)
4935 if (!sp [0].data.p || !sp [1].data.p)
4936 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4938 /* FIXME: value and size may be int64... */
4939 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4942 MINT_IN_CASE(MINT_CONSTRAINED_) {
4944 /* FIXME: implement */
4946 token = READ32 (ip);
4951 MINT_IN_CASE(MINT_INITBLK)
4954 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4956 /* FIXME: value and size may be int64... */
4957 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4960 MINT_IN_CASE(MINT_NO_)
4961 /* FIXME: implement */
4965 MINT_IN_CASE(MINT_RETHROW)
4967 * need to clarify what this should actually do:
4968 * start the search from the last found handler in
4969 * this method or continue in the caller or what.
4970 * Also, do we need to run finally/fault handlers after a retrow?
4971 * Well, this implementation will follow the usual search
4972 * for an handler, considering the current ip as throw spot.
4973 * We need to NULL frame->ex_handler for the later code to
4974 * actually run the new found handler.
4976 frame->ex_handler = NULL;
4977 THROW_EX (frame->ex, ip - 1);
4980 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
4981 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
4985 g_assert_not_reached ();
4987 * Exception handling code.
4988 * The exception object is stored in frame->ex.
4995 MonoInvocation *inv;
4996 MonoExceptionClause *clause;
5002 g_print ("* Handling exception '%s' at IL_%04x\n",
5003 frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name,
5004 rtm == NULL ? 0 : frame->ip - rtm->code);
5006 if (die_on_exception)
5009 for (inv = frame; inv; inv = inv->parent) {
5011 if (inv->runtime_method == NULL)
5013 method = inv->runtime_method->method;
5014 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5016 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
5018 if (inv->ip == NULL)
5020 ip_offset = inv->ip - inv->runtime_method->code;
5021 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
5022 for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
5023 clause = &inv->runtime_method->clauses [i];
5025 g_print ("* clause [%d]: %p\n", i, clause);
5027 if (!MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
5030 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5033 g_print ("* Filter found at '%s'\n", method->name);
5035 MonoInvocation dup_frame;
5037 memcpy (&dup_frame, inv, sizeof (MonoInvocation));
5038 dup_frame.retval = &retval;
5039 ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex, -1);
5040 if (dup_frame.retval->data.i) {
5043 g_print ("* Matched Filter at '%s'\n", method->name);
5045 inv->ex_handler = clause;
5046 goto handle_finally;
5048 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
5049 MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
5050 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5053 * OK, we found an handler, now we need to execute the finally
5054 * and fault blocks before branching to the handler code.
5058 g_print ("* Found handler at '%s'\n", method->name);
5060 inv->ex_handler = clause;
5061 goto handle_finally;
5067 * If we get here, no handler was found: print a stack trace.
5069 for (inv = frame; inv; inv = inv->parent) {
5070 if (inv->invoke_trap)
5071 goto handle_finally;
5074 ex_obj = (MonoObject *) frame->ex;
5075 mono_unhandled_exception (ex_obj);
5076 MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls ();
5077 jit_tls->abort_func (ex_obj);
5078 g_assert_not_reached ();
5084 MonoExceptionClause *clause;
5085 GSList *old_list = finally_ips;
5086 MonoMethod *method = frame->runtime_method->method;
5087 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
5088 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5092 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
5094 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5095 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5098 ip_offset = frame->ip - rtm->code;
5100 if (endfinally_ip != NULL)
5101 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
5102 for (i = 0; i < header->num_clauses; ++i)
5103 if (frame->ex_handler == &rtm->clauses [i])
5107 clause = &rtm->clauses [i];
5108 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
5109 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5110 ip = rtm->code + clause->handler_offset;
5111 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5114 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5120 endfinally_ip = NULL;
5122 if (old_list != finally_ips && finally_ips) {
5123 ip = finally_ips->data;
5124 finally_ips = g_slist_remove (finally_ips, ip);
5125 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5130 * If an exception is set, we need to execute the fault handler, too,
5131 * otherwise, we continue normally.
5141 MonoExceptionClause *clause;
5142 MonoMethod *method = frame->runtime_method->method;
5143 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
5144 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5148 g_print ("* Handle fault\n");
5150 ip_offset = frame->ip - rtm->code;
5151 for (i = 0; i < header->num_clauses; ++i) {
5152 clause = &rtm->clauses [i];
5153 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
5154 ip = rtm->code + clause->handler_offset;
5157 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
5163 * If the handler for the exception was found in this method, we jump
5164 * to it right away, otherwise we return and let the caller run
5165 * the finally, fault and catch blocks.
5166 * This same code should be present in the endfault opcode, but it
5167 * is corrently not assigned in the ECMA specs: LAMESPEC.
5169 if (frame->ex_handler) {
5172 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
5174 ip = rtm->code + frame->ex_handler->handler_offset;
5176 vt_sp = (unsigned char *) sp + rtm->stack_size;
5177 sp->data.p = frame->ex;
5188 ves_exec_method (MonoInvocation *frame)
5190 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5191 ThreadContext context_struct;
5198 mono_unhandled_exception ((MonoObject*)frame->ex);
5201 if (context == NULL) {
5202 context = &context_struct;
5203 context_struct.domain = mono_domain_get ();
5204 context_struct.base_frame = frame;
5205 context_struct.current_frame = NULL;
5206 context_struct.env_frame = frame;
5207 context_struct.current_env = &env;
5208 context_struct.search_for_handler = 0;
5209 context_struct.managed_code = 0;
5210 set_context (context);
5213 frame->parent = context->current_frame;
5214 frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
5215 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5216 context->managed_code = 1;
5217 ves_exec_method_with_context (frame, context, NULL, NULL, -1);
5218 context->managed_code = 0;
5220 if (context != &context_struct && context->current_env) {
5221 context->env_frame->ex = frame->ex;
5222 longjmp (*context->current_env, 1);
5225 mono_unhandled_exception ((MonoObject*)frame->ex);
5227 if (context->base_frame == frame)
5230 context->current_frame = frame->parent;
5234 mono_interp_parse_options (const char *options)
5238 args = g_strsplit (options, ",", -1);
5239 for (ptr = args; ptr && *ptr; ptr ++) {
5242 if (strncmp (arg, "jit=", 4) == 0)
5243 jit_classes = g_slist_prepend (jit_classes, arg + 4);
5250 mono_native_tls_alloc (&thread_context_id, NULL);
5253 mono_interp_transform_init ();
5256 typedef int (*TestMethod) (void);
5259 interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain)
5261 int result, expected, failed, cfailed, run;
5262 double elapsed, transform_time;
5264 MonoObject *result_obj;
5265 static gboolean filter_method_init = FALSE;
5266 static const char *filter_method = NULL;
5268 g_print ("Test run: image=%s\n", mono_image_get_filename (image));
5269 cfailed = failed = run = 0;
5270 transform_time = elapsed = 0.0;
5272 g_timer_start (timer);
5273 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5274 MonoObject *exc = NULL;
5276 MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
5278 mono_error_cleanup (&error); /* FIXME don't swallow the error */
5282 if (!filter_method_init) {
5283 filter_method = g_getenv ("INTERP_FILTER_METHOD");
5284 filter_method_init = TRUE;
5286 gboolean filter = FALSE;
5287 if (filter_method) {
5288 const char *name = filter_method;
5290 if ((strchr (name, '.') > name) || strchr (name, ':')) {
5291 MonoMethodDesc *desc = mono_method_desc_new (name, TRUE);
5292 filter = mono_method_desc_full_match (desc, method);
5293 mono_method_desc_free (desc);
5295 filter = strcmp (method->name, name) == 0;
5297 } else { /* no filter, check for `Category' attribute on method */
5299 MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error);
5300 mono_error_cleanup (&error);
5304 for (j = 0; j < ainfo->num_attrs && filter; ++j) {
5305 MonoCustomAttrEntry *centry = &ainfo->attrs [j];
5306 if (centry->ctor == NULL)
5309 MonoClass *klass = centry->ctor->klass;
5310 if (strcmp (klass->name, "CategoryAttribute"))
5313 MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error);
5314 /* FIXME: there is an ordering problem if there're multiple attributes, do this instead:
5315 * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */
5316 mono_error_cleanup (&error);
5317 MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1);
5318 MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error);
5319 mono_error_cleanup (&error);
5320 char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error);
5321 mono_error_cleanup (&error);
5322 if (!strcmp (utf8_str, "!INTERPRETER")) {
5323 g_print ("skip %s...\n", method->name);
5329 if (strncmp (method->name, "test_", 5) == 0 && filter) {
5330 MonoError interp_error;
5331 MonoObject *exc = NULL;
5333 result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error);
5334 if (!mono_error_ok (&interp_error)) {
5336 g_print ("Test '%s' execution failed.\n", method->name);
5337 } else if (exc != NULL) {
5338 g_print ("Exception in Test '%s' occured:\n", method->name);
5339 mono_object_describe (exc);
5343 result = *(gint32 *) mono_object_unbox (result_obj);
5344 expected = atoi (method->name + 5); // FIXME: oh no.
5347 if (result != expected) {
5349 g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
5354 g_timer_stop (timer);
5355 elapsed = g_timer_elapsed (timer, NULL);
5356 if (failed > 0 || cfailed > 0){
5357 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
5358 run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
5360 g_print ("Results: total tests: %d, all pass \n", run);
5363 g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed,
5364 elapsed - transform_time, transform_time);
5365 *total += failed + cfailed;
5370 interp_regression (MonoImage *image, int verbose, int *total_run)
5373 GTimer *timer = g_timer_new ();
5374 MonoDomain *domain = mono_domain_get ();
5378 /* load the metadata */
5379 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5381 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
5383 mono_error_cleanup (&error);
5386 mono_class_init (method->klass);
5391 interp_regression_step (image, verbose, total_run, &total, timer, domain);
5393 g_timer_destroy (timer);
5398 mono_interp_regression_list (int verbose, int count, char *images [])
5400 int i, total, total_run, run;
5402 total_run = total = 0;
5403 for (i = 0; i < count; ++i) {
5404 MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL);
5406 g_warning ("failed to load assembly: %s", images [i]);
5409 total += interp_regression (mono_assembly_get_image (ass), verbose, &run);
5413 g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run);
5415 g_print ("Overall results: tests: %d, 100%% pass\n", total_run);
5422 * mono_interp_set_resume_state:
5424 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5427 mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
5429 ThreadContext *context;
5432 context = jit_tls->interp_context;
5435 context->has_resume_state = TRUE;
5436 context->handler_frame = interp_frame;
5437 /* This is on the stack, so it doesn't need a wbarrier */
5438 context->handler_frame->ex = ex;
5439 context->handler_ip = handler_ip;
5443 * mono_interp_run_finally:
5445 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5446 * frame->interp_frame.
5449 mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5451 MonoInvocation *iframe = frame->interp_frame;
5452 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5454 ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index);
5458 MonoInvocation *current;
5462 * mono_interp_frame_iter_init:
5464 * Initialize an iterator for iterating through interpreted frames.
5467 mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5469 StackIter *stack_iter = (StackIter*)iter;
5471 stack_iter->current = (MonoInvocation*)interp_exit_data;
5475 mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5477 StackIter *stack_iter = (StackIter*)iter;
5478 MonoInvocation *iframe = stack_iter->current;
5480 memset (frame, 0, sizeof (StackFrameInfo));
5481 /* pinvoke frames doesn't have runtime_method set */
5482 while (iframe && !(iframe->runtime_method && iframe->runtime_method->code))
5483 iframe = iframe->parent;
5487 frame->type = FRAME_TYPE_INTERP;
5489 frame->domain = mono_domain_get ();
5490 frame->interp_frame = iframe;
5491 frame->method = iframe->runtime_method->method;
5492 frame->actual_method = frame->method;
5493 /* This is the offset in the interpreter IR */
5494 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->runtime_method->code;
5495 frame->ji = iframe->runtime_method->jinfo;
5497 stack_iter->current = iframe->parent;
5503 mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
5507 rtm = lookup_runtime_method (domain, method);
5515 mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5517 guint16 *code = (guint16*)ip;
5518 g_assert (*code == MINT_SDB_SEQ_POINT);
5519 *code = MINT_SDB_BREAKPOINT;
5523 mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5525 guint16 *code = (guint16*)ip;
5526 g_assert (*code == MINT_SDB_BREAKPOINT);
5527 *code = MINT_SDB_SEQ_POINT;
5531 mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
5533 MonoInvocation *iframe = (MonoInvocation*)frame;
5535 g_assert (iframe->runtime_method);
5536 return iframe->runtime_method->jinfo;
5540 mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
5542 MonoInvocation *iframe = (MonoInvocation*)frame;
5544 g_assert (iframe->runtime_method);
5545 return (gpointer)iframe->ip;
5549 mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
5551 MonoInvocation *iframe = (MonoInvocation*)frame;
5553 g_assert (iframe->runtime_method);
5555 int arg_offset = iframe->runtime_method->arg_offsets [pos + (iframe->runtime_method->hasthis ? 1 : 0)];
5557 return iframe->args + arg_offset;
5561 mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
5563 MonoInvocation *iframe = (MonoInvocation*)frame;
5565 g_assert (iframe->runtime_method);
5567 return iframe->locals + iframe->runtime_method->local_offsets [pos];
5571 mono_interp_frame_get_this (MonoInterpFrameHandle frame)
5573 MonoInvocation *iframe = (MonoInvocation*)frame;
5575 g_assert (iframe->runtime_method);
5576 g_assert (iframe->runtime_method->hasthis);
5578 int arg_offset = iframe->runtime_method->arg_offsets [0];
5580 return iframe->args + arg_offset;
5584 mono_interp_start_single_stepping (void)
5590 mono_interp_stop_single_stepping (void)