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/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/metadata/gc-internals.h>
60 #include <mono/utils/atomic.h>
63 #include "interp-internals.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/mini-runtime.h>
69 #include <mono/mini/aot-runtime.h>
70 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
75 #include <mono/mini/mini-arm.h>
78 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
81 #define finite _finite
85 #define finite isfinite
90 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
92 frame
->parent
= parent_frame
;
93 frame
->stack_args
= method_args
;
94 frame
->retval
= method_retval
;
95 frame
->imethod
= rmethod
;
98 frame
->invoke_trap
= 0;
101 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
102 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
103 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
107 * List of classes whose methods will be executed by transitioning to JITted code.
111 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
112 static gboolean ss_enabled
;
114 static gboolean interp_init_done
= FALSE
;
116 static char* dump_frame (InterpFrame
*inv
);
117 static MonoArray
*get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
);
118 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, guint16
*start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
, InterpFrame
*base_frame
);
119 static void interp_exec_method (InterpFrame
*frame
, ThreadContext
*context
);
121 typedef void (*ICallMethod
) (InterpFrame
*frame
);
123 static MonoNativeTlsKey thread_context_id
;
125 static char* dump_args (InterpFrame
*inv
);
127 #define DEBUG_INTERP 0
130 int mono_interp_traceopt
= 2;
131 /* If true, then we output the opcodes as we interpret them */
132 static int global_tracing
= 2;
134 static int debug_indent_level
= 0;
136 static int break_on_method
= 0;
137 static int nested_trace
= 0;
138 static GList
*db_methods
= NULL
;
145 for (h
= 0; h
< debug_indent_level
; h
++)
150 db_match_method (gpointer data
, gpointer user_data
)
152 MonoMethod
*m
= (MonoMethod
*)user_data
;
153 MonoMethodDesc
*desc
= data
;
155 if (mono_method_desc_full_match (desc
, m
))
160 debug_enter (InterpFrame
*frame
, int *tracing
)
163 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
165 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
169 MonoMethod
*method
= frame
->imethod
->method
;
170 char *mn
, *args
= dump_args (frame
);
171 debug_indent_level
++;
173 mn
= mono_method_full_name (method
, FALSE
);
174 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
176 g_print ("%s)\n", args
);
182 #define DEBUG_LEAVE() \
185 args = dump_retval (frame); \
187 mn = mono_method_full_name (frame->imethod->method, FALSE); \
188 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
190 g_print (" => %s\n", args); \
192 debug_indent_level--; \
193 if (tracing == 3) global_tracing = 0; \
198 int mono_interp_traceopt
= 0;
199 static void debug_enter (InterpFrame
*frame
, int *tracing
)
202 #define DEBUG_LEAVE()
207 set_resume_state (ThreadContext
*context
, InterpFrame
*frame
)
210 context
->has_resume_state
= 0;
211 context
->handler_frame
= NULL
;
214 /* Set the current execution state to the resume state in context */
215 #define SET_RESUME_STATE(context) do { \
216 ip = (context)->handler_ip; \
217 /* spec says stack should be empty at endfinally so it should be at the start too */ \
219 vt_sp = (unsigned char *) sp + rtm->stack_size; \
221 sp->data.p = frame->ex; \
224 set_resume_state ((context), (frame)); \
229 set_context (ThreadContext
*context
)
231 MonoJitTlsData
*jit_tls
;
233 mono_native_tls_set_value (thread_context_id
, context
);
234 jit_tls
= mono_tls_get_jit_tls ();
236 jit_tls
->interp_context
= context
;
240 ves_real_abort (int line
, MonoMethod
*mh
,
241 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
244 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
245 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
246 g_printerr ("Execution aborted in method: %s::%s\n", mh
->klass
->name
, mh
->name
);
247 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
248 g_print ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
249 mono_metadata_free_mh (header
);
251 printf ("\t[%ld] 0x%08x %0.5f\n", sp
-stack
, sp
[-1].data
.i
, sp
[-1].data
.f
);
254 #define ves_abort() \
256 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
257 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
261 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
264 MonoJitDomainInfo
*info
;
266 info
= domain_jit_info (domain
);
267 mono_domain_jit_code_hash_lock (domain
);
268 rtm
= mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
269 mono_domain_jit_code_hash_unlock (domain
);
274 interp_get_remoting_invoke (gpointer imethod
, MonoError
*error
)
276 #ifndef DISABLE_REMOTING
277 InterpMethod
*imethod_cast
= (InterpMethod
*) imethod
;
279 g_assert (mono_use_interpreter
);
281 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod_cast
->method
, error
);
282 return_val_if_nok (error
, NULL
);
283 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
285 g_assert_not_reached ();
291 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
294 MonoJitDomainInfo
*info
;
295 MonoMethodSignature
*sig
;
300 info
= domain_jit_info (domain
);
301 mono_domain_jit_code_hash_lock (domain
);
302 rtm
= mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
303 mono_domain_jit_code_hash_unlock (domain
);
307 sig
= mono_method_signature (method
);
309 rtm
= mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
310 rtm
->method
= method
;
311 rtm
->domain
= domain
;
312 rtm
->param_count
= sig
->param_count
;
313 rtm
->hasthis
= sig
->hasthis
;
314 rtm
->rtype
= mini_get_underlying_type (sig
->ret
);
315 rtm
->param_types
= mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
316 for (i
= 0; i
< sig
->param_count
; ++i
)
317 rtm
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
319 mono_domain_jit_code_hash_lock (domain
);
320 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
321 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, rtm
);
322 mono_domain_jit_code_hash_unlock (domain
);
324 rtm
->prof_flags
= mono_profiler_get_call_instrumentation_flags (rtm
->method
);
330 interp_create_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
332 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
333 method
= mono_marshal_get_synchronized_wrapper (method
);
334 return mono_interp_get_imethod (domain
, method
, error
);
340 * Push an LMF frame on the LMF stack
341 * to mark the transition to native code.
342 * This is needed for the native code to
343 * be able to do stack walks.
346 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
348 memset (ext
, 0, sizeof (MonoLMFExt
));
349 ext
->interp_exit
= TRUE
;
350 ext
->interp_exit_data
= frame
;
356 interp_pop_lmf (MonoLMFExt
*ext
)
358 mono_pop_lmf (&ext
->lmf
);
362 get_virtual_method (InterpMethod
*imethod
, MonoObject
*obj
)
364 MonoMethod
*m
= imethod
->method
;
365 MonoDomain
*domain
= imethod
->domain
;
366 InterpMethod
*ret
= NULL
;
369 #ifndef DISABLE_REMOTING
370 if (mono_object_is_transparent_proxy (obj
)) {
371 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
372 mono_error_assert_ok (error
);
373 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
374 mono_error_assert_ok (error
);
379 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
380 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
381 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
382 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
389 mono_class_setup_vtable (obj
->vtable
->klass
);
391 int slot
= mono_method_get_vtable_slot (m
);
392 if (mono_class_is_interface (m
->klass
)) {
393 g_assert (obj
->vtable
->klass
!= m
->klass
);
394 /* TODO: interface offset lookup is slow, go through IMT instead */
395 gboolean non_exact_match
;
396 slot
+= mono_class_interface_offset_with_variance (obj
->vtable
->klass
, m
->klass
, &non_exact_match
);
399 MonoMethod
*virtual_method
= obj
->vtable
->klass
->vtable
[slot
];
400 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
401 MonoGenericContext context
= { NULL
, NULL
};
403 if (mono_class_is_ginst (virtual_method
->klass
))
404 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
405 else if (mono_class_is_gtd (virtual_method
->klass
))
406 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
407 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
409 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
410 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
413 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
414 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
417 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
418 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
419 return virtual_imethod
;
423 stackval_from_data (MonoType
*type_
, stackval
*result
, char *data
, gboolean pinvoke
)
425 MonoType
*type
= mini_native_type_replace_type (type_
);
427 switch (type
->type
) {
428 case MONO_TYPE_OBJECT
:
429 case MONO_TYPE_CLASS
:
430 case MONO_TYPE_STRING
:
431 case MONO_TYPE_ARRAY
:
432 case MONO_TYPE_SZARRAY
:
437 result
->data
.p
= *(gpointer
*)data
;
440 switch (type
->type
) {
444 result
->data
.i
= *(gint8
*)data
;
447 case MONO_TYPE_BOOLEAN
:
448 result
->data
.i
= *(guint8
*)data
;
451 result
->data
.i
= *(gint16
*)data
;
455 result
->data
.i
= *(guint16
*)data
;
458 result
->data
.i
= *(gint32
*)data
;
462 result
->data
.nati
= *(mono_i
*)data
;
465 result
->data
.p
= *(gpointer
*)data
;
468 result
->data
.i
= *(guint32
*)data
;
472 /* memmove handles unaligned case */
473 memmove (&tmp
, data
, sizeof (float));
474 result
->data
.f
= tmp
;
479 memmove (&result
->data
.l
, data
, sizeof (gint64
));
482 memmove (&result
->data
.f
, data
, sizeof (double));
484 case MONO_TYPE_STRING
:
485 case MONO_TYPE_SZARRAY
:
486 case MONO_TYPE_CLASS
:
487 case MONO_TYPE_OBJECT
:
488 case MONO_TYPE_ARRAY
:
489 result
->data
.p
= *(gpointer
*)data
;
491 case MONO_TYPE_VALUETYPE
:
492 if (type
->data
.klass
->enumtype
) {
493 stackval_from_data (mono_class_enum_basetype (type
->data
.klass
), result
, data
, pinvoke
);
495 } else if (pinvoke
) {
496 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
498 mono_value_copy (result
->data
.vt
, data
, type
->data
.klass
);
501 case MONO_TYPE_GENERICINST
: {
502 if (mono_type_generic_inst_is_valuetype (type
)) {
503 mono_value_copy (result
->data
.vt
, data
, mono_class_from_mono_type (type
));
506 stackval_from_data (&type
->data
.generic_class
->container_class
->byval_arg
, result
, data
, pinvoke
);
510 g_error ("got type 0x%02x", type
->type
);
515 stackval_to_data (MonoType
*type_
, stackval
*val
, char *data
, gboolean pinvoke
)
517 MonoType
*type
= mini_native_type_replace_type (type_
);
519 gpointer
*p
= (gpointer
*)data
;
523 /* printf ("TODAT0 %p\n", data); */
524 switch (type
->type
) {
527 guint8
*p
= (guint8
*)data
;
531 case MONO_TYPE_BOOLEAN
: {
532 guint8
*p
= (guint8
*)data
;
533 *p
= (val
->data
.i
!= 0);
538 case MONO_TYPE_CHAR
: {
539 guint16
*p
= (guint16
*)data
;
544 mono_i
*p
= (mono_i
*)data
;
545 /* In theory the value used by stloc should match the local var type
546 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
547 a native int - both by csc and mcs). Not sure what to do about sign extension
548 as it is outside the spec... doing the obvious */
549 *p
= (mono_i
)val
->data
.nati
;
553 mono_u
*p
= (mono_u
*)data
;
555 *p
= (mono_u
)val
->data
.nati
;
560 gint32
*p
= (gint32
*)data
;
566 gint64
*p
= (gint64
*)data
;
571 float *p
= (float*)data
;
576 double *p
= (double*)data
;
580 case MONO_TYPE_STRING
:
581 case MONO_TYPE_SZARRAY
:
582 case MONO_TYPE_CLASS
:
583 case MONO_TYPE_OBJECT
:
584 case MONO_TYPE_ARRAY
: {
585 gpointer
*p
= (gpointer
*) data
;
586 mono_gc_wbarrier_generic_store (p
, val
->data
.p
);
589 case MONO_TYPE_PTR
: {
590 gpointer
*p
= (gpointer
*) data
;
594 case MONO_TYPE_VALUETYPE
:
595 if (type
->data
.klass
->enumtype
) {
596 stackval_to_data (mono_class_enum_basetype (type
->data
.klass
), val
, data
, pinvoke
);
598 } else if (pinvoke
) {
599 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
601 mono_value_copy (data
, val
->data
.vt
, type
->data
.klass
);
604 case MONO_TYPE_GENERICINST
: {
605 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
607 if (container_class
->valuetype
&& !container_class
->enumtype
) {
608 mono_value_copy (data
, val
->data
.vt
, mono_class_from_mono_type (type
));
611 stackval_to_data (&type
->data
.generic_class
->container_class
->byval_arg
, val
, data
, pinvoke
);
615 g_error ("got type %x", type
->type
);
620 * Same as stackval_to_data but return address of storage instead
621 * of copying the value.
624 stackval_to_data_addr (MonoType
*type_
, stackval
*val
)
626 MonoType
*type
= mini_native_type_replace_type (type_
);
630 switch (type
->type
) {
633 case MONO_TYPE_BOOLEAN
:
642 return &val
->data
.nati
;
649 case MONO_TYPE_STRING
:
650 case MONO_TYPE_SZARRAY
:
651 case MONO_TYPE_CLASS
:
652 case MONO_TYPE_OBJECT
:
653 case MONO_TYPE_ARRAY
:
656 case MONO_TYPE_VALUETYPE
:
657 if (type
->data
.klass
->enumtype
)
658 return stackval_to_data_addr (mono_class_enum_basetype (type
->data
.klass
), val
);
661 case MONO_TYPE_GENERICINST
: {
662 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
664 if (container_class
->valuetype
&& !container_class
->enumtype
)
666 return stackval_to_data_addr (&type
->data
.generic_class
->container_class
->byval_arg
, val
);
669 g_error ("got type %x", type
->type
);
675 * Throw an exception from the interpreter.
677 static MONO_NEVER_INLINE
void
678 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, gconstpointer ip
, gboolean rethrow
)
682 interp_push_lmf (&ext
, frame
);
687 ex
->stack_trace
= NULL
;
688 ex
->trace_ips
= NULL
;
692 memset (&ctx
, 0, sizeof (MonoContext
));
693 MONO_CONTEXT_SET_SP (&ctx
, frame
);
696 * Call the JIT EH code. The EH code will call back to us using:
697 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
698 * Since ctx.ip is 0, this will start unwinding from the LMF frame
699 * pushed above, which points to our frames.
701 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
703 interp_pop_lmf (&ext
);
705 g_assert (context
->has_resume_state
);
709 fill_in_trace (MonoException
*exception
, InterpFrame
*frame
)
712 char *stack_trace
= dump_frame (frame
);
713 MonoDomain
*domain
= frame
->imethod
->domain
;
714 (exception
)->stack_trace
= mono_string_new_checked (domain
, stack_trace
, error
);
715 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
716 (exception
)->trace_ips
= get_trace_ips (domain
, frame
);
717 g_free (stack_trace
);
720 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
722 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
724 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
725 if (frame == context->handler_frame) \
726 SET_RESUME_STATE (context); \
731 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
734 * Its possible for child_frame.ex to contain an unthrown exception, if the transform phase
737 #define CHECK_CHILD_EX(child_frame, ip) do { \
738 if ((child_frame).ex) \
739 THROW_EX ((child_frame).ex, (ip)); \
742 #define EXCEPTION_CHECKPOINT \
744 if (*mono_thread_interruption_request_flag ()) { \
745 MonoException *exc = mono_thread_interruption_checkpoint (); \
747 THROW_EX (exc, ip); \
753 ves_array_create (InterpFrame
*frame
, MonoDomain
*domain
, MonoClass
*klass
, MonoMethodSignature
*sig
, stackval
*values
)
756 intptr_t *lower_bounds
;
761 lengths
= alloca (sizeof (uintptr_t) * klass
->rank
* 2);
762 for (i
= 0; i
< sig
->param_count
; ++i
) {
763 lengths
[i
] = values
->data
.i
;
766 if (klass
->rank
== sig
->param_count
) {
767 /* Only lengths provided. */
770 /* lower bounds are first. */
771 lower_bounds
= (intptr_t *) lengths
;
772 lengths
+= klass
->rank
;
774 obj
= (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
775 if (!mono_error_ok (error
)) {
776 frame
->ex
= mono_error_convert_to_exception (error
);
777 FILL_IN_TRACE (frame
->ex
, frame
);
779 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
784 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
786 g_assert (!frame
->ex
);
787 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
791 for (gint32 i
= 0; i
< ac
->rank
; i
++) {
792 guint32 idx
= sp
[i
].data
.i
;
793 guint32 lower
= ao
->bounds
[i
].lower_bound
;
794 guint32 len
= ao
->bounds
[i
].length
;
795 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
796 frame
->ex
= mono_get_exception_index_out_of_range ();
797 FILL_IN_TRACE (frame
->ex
, frame
);
800 pos
= (pos
* len
) + idx
- lower
;
804 if (safe
&& pos
>= ao
->max_length
) {
805 frame
->ex
= mono_get_exception_index_out_of_range ();
806 FILL_IN_TRACE (frame
->ex
, frame
);
814 ves_array_set (InterpFrame
*frame
)
816 stackval
*sp
= frame
->stack_args
+ 1;
818 MonoObject
*o
= frame
->stack_args
->data
.p
;
819 MonoArray
*ao
= (MonoArray
*) o
;
820 MonoClass
*ac
= o
->vtable
->klass
;
822 g_assert (ac
->rank
>= 1);
824 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
828 if (sp
[ac
->rank
].data
.p
&& !mono_object_class (o
)->element_class
->valuetype
) {
830 MonoObject
*isinst
= mono_object_isinst_checked (sp
[ac
->rank
].data
.p
, mono_object_class (o
)->element_class
, error
);
831 mono_error_cleanup (error
);
833 frame
->ex
= mono_get_exception_array_type_mismatch ();
834 FILL_IN_TRACE (frame
->ex
, frame
);
839 gint32 esize
= mono_array_element_size (ac
);
840 gpointer ea
= mono_array_addr_with_size (ao
, esize
, pos
);
842 MonoType
*mt
= mono_method_signature (frame
->imethod
->method
)->params
[ac
->rank
];
843 stackval_to_data (mt
, &sp
[ac
->rank
], ea
, FALSE
);
847 ves_array_get (InterpFrame
*frame
, gboolean safe
)
849 stackval
*sp
= frame
->stack_args
+ 1;
851 MonoObject
*o
= frame
->stack_args
->data
.p
;
852 MonoArray
*ao
= (MonoArray
*) o
;
853 MonoClass
*ac
= o
->vtable
->klass
;
855 g_assert (ac
->rank
>= 1);
857 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, safe
);
861 gint32 esize
= mono_array_element_size (ac
);
862 gpointer ea
= mono_array_addr_with_size (ao
, esize
, pos
);
864 MonoType
*mt
= mono_method_signature (frame
->imethod
->method
)->ret
;
865 stackval_from_data (mt
, frame
->retval
, ea
, FALSE
);
869 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
871 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
873 g_assert (ac
->rank
>= 1);
875 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
879 if (needs_typecheck
&& !mono_class_is_assignable_from (mono_object_class ((MonoObject
*) ao
)->element_class
, required_type
->element_class
)) {
880 frame
->ex
= mono_get_exception_array_type_mismatch ();
881 FILL_IN_TRACE (frame
->ex
, frame
);
884 gint32 esize
= mono_array_element_size (ac
);
885 return mono_array_addr_with_size (ao
, esize
, pos
);
889 interp_walk_stack_with_ctx (MonoInternalStackWalk func
, MonoContext
*ctx
, MonoUnwindOptions options
, void *user_data
)
891 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
896 InterpFrame
*frame
= context
->current_frame
;
899 MonoStackFrameInfo fi
;
900 memset (&fi
, 0, sizeof (MonoStackFrameInfo
));
902 /* TODO: hack to make some asserts happy. */
903 fi
.ji
= (MonoJitInfo
*) frame
->imethod
;
906 fi
.method
= fi
.actual_method
= frame
->imethod
->method
;
908 if (!fi
.method
|| (fi
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (fi
.method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
909 fi
.native_offset
= -1;
910 fi
.type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
912 fi
.type
= FRAME_TYPE_MANAGED
;
913 fi
.native_offset
= frame
->ip
- frame
->imethod
->code
;
914 if (!fi
.method
->wrapper_type
)
918 if (func (&fi
, ctx
, user_data
))
920 frame
= frame
->parent
;
924 static MonoPIFunc mono_interp_to_native_trampoline
= NULL
;
926 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
927 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
929 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
932 g_assert (mono_arm_eabi_supported ());
933 int i8_align
= mono_arm_i8_align ();
943 for (int i
= 0; i
< sig
->param_count
; i
++) {
944 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
946 case MONO_TYPE_BOOLEAN
:
957 case MONO_TYPE_SZARRAY
:
958 case MONO_TYPE_CLASS
:
959 case MONO_TYPE_OBJECT
:
960 case MONO_TYPE_STRING
:
961 case MONO_TYPE_VALUETYPE
:
962 case MONO_TYPE_GENERICINST
:
963 #if SIZEOF_VOID_P == 8
969 #if SIZEOF_VOID_P == 4
973 /* pairs begin at even registers */
974 if (i8_align
== 8 && margs
->ilen
& 1)
981 #if SIZEOF_VOID_P == 8
986 #if SIZEOF_VOID_P == 4
992 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
997 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1000 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1002 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1003 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1005 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1006 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1013 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1017 for (int i
= 0; i
< sig
->param_count
; i
++) {
1018 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1020 case MONO_TYPE_BOOLEAN
:
1021 case MONO_TYPE_CHAR
:
1031 case MONO_TYPE_SZARRAY
:
1032 case MONO_TYPE_CLASS
:
1033 case MONO_TYPE_OBJECT
:
1034 case MONO_TYPE_STRING
:
1035 case MONO_TYPE_VALUETYPE
:
1036 case MONO_TYPE_GENERICINST
:
1037 #if SIZEOF_VOID_P == 8
1041 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1043 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1047 #if SIZEOF_VOID_P == 4
1049 case MONO_TYPE_U8
: {
1050 stackval
*sarg
= &frame
->stack_args
[i
];
1052 /* pairs begin at even registers */
1053 if (i8_align
== 8 && int_i
& 1)
1056 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1058 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1060 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
);
1068 if (ptype
== MONO_TYPE_R4
)
1069 * (float *) &(margs
->fargs
[int_f
]) = (float) frame
->stack_args
[i
].data
.f
;
1071 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1073 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
);
1075 #if SIZEOF_VOID_P == 4
1082 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1086 switch (sig
->ret
->type
) {
1087 case MONO_TYPE_BOOLEAN
:
1088 case MONO_TYPE_CHAR
:
1098 case MONO_TYPE_SZARRAY
:
1099 case MONO_TYPE_CLASS
:
1100 case MONO_TYPE_OBJECT
:
1101 case MONO_TYPE_STRING
:
1104 case MONO_TYPE_VALUETYPE
:
1105 case MONO_TYPE_GENERICINST
:
1106 margs
->retval
= &(frame
->retval
->data
.p
);
1107 margs
->is_float_ret
= 0;
1111 margs
->retval
= &(frame
->retval
->data
.p
);
1112 margs
->is_float_ret
= 1;
1114 case MONO_TYPE_VOID
:
1115 margs
->retval
= NULL
;
1118 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1126 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1128 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1131 stackval_to_data (sig
->ret
, iframe
->retval
, data
, TRUE
);
1133 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, TRUE
);
1137 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1139 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1142 stackval_from_data (sig
->ret
, iframe
->retval
, data
, TRUE
);
1144 stackval_from_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, TRUE
);
1148 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1150 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1153 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1155 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1158 static MONO_NEVER_INLINE
void
1159 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
)
1165 g_assert (!frame
->imethod
);
1166 if (!mono_interp_to_native_trampoline
) {
1167 if (mono_aot_only
) {
1168 mono_interp_to_native_trampoline
= mono_aot_get_trampoline ("interp_to_native_trampoline");
1170 MonoTrampInfo
*info
;
1171 mono_interp_to_native_trampoline
= mono_arch_get_interp_to_native_trampoline (&info
);
1173 // mono_tramp_info_register (info, NULL);
1176 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1177 CallContext ccontext
;
1178 mono_arch_set_native_call_context (&ccontext
, frame
, sig
);
1180 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1184 g_print ("ICALL: mono_interp_to_native_trampoline = %p, addr = %p\n", mono_interp_to_native_trampoline
, addr
);
1187 context
->current_frame
= frame
;
1189 interp_push_lmf (&ext
, frame
);
1190 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1191 mono_interp_to_native_trampoline (addr
, &ccontext
);
1193 mono_interp_to_native_trampoline (addr
, margs
);
1195 interp_pop_lmf (&ext
);
1197 if (*mono_thread_interruption_request_flag ()) {
1198 MonoException
*exc
= mono_thread_interruption_checkpoint ();
1200 interp_throw (context
, exc
, frame
, NULL
, FALSE
);
1203 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1205 mono_arch_get_native_call_context (&ccontext
, frame
, sig
);
1207 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1208 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1210 g_free (margs
->iargs
);
1211 g_free (margs
->fargs
);
1217 interp_init_delegate (MonoDelegate
*del
)
1221 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
1222 del
->method
= ((InterpMethod
*) del
->method_ptr
)->method
;
1227 * runtime specifies that the implementation of the method is automatically
1228 * provided by the runtime and is primarily used for the methods of delegates.
1230 static MONO_NEVER_INLINE
void
1231 ves_imethod (InterpFrame
*frame
, ThreadContext
*context
)
1233 MonoMethod
*method
= frame
->imethod
->method
;
1234 const char *name
= method
->name
;
1235 MonoObject
*obj
= (MonoObject
*) frame
->stack_args
->data
.p
;
1238 mono_class_init (method
->klass
);
1240 if (method
->klass
== mono_defaults
.array_class
) {
1241 if (!strcmp (method
->name
, "UnsafeMov")) {
1242 /* TODO: layout checks */
1243 MonoType
*mt
= mono_method_signature (method
)->ret
;
1244 stackval_from_data (mt
, frame
->retval
, (char *) frame
->stack_args
, FALSE
);
1247 if (!strcmp (method
->name
, "UnsafeLoad")) {
1248 ves_array_get (frame
, FALSE
);
1251 } else if (mini_class_is_system_array (method
->klass
)) {
1253 frame
->ex
= mono_get_exception_null_reference ();
1254 FILL_IN_TRACE (frame
->ex
, frame
);
1257 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1258 ves_array_set (frame
);
1261 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1262 ves_array_get (frame
, TRUE
);
1267 g_error ("Don't know how to exec runtime method %s.%s::%s",
1268 method
->klass
->name_space
, method
->klass
->name
,
1274 dump_stack (stackval
*stack
, stackval
*sp
)
1276 stackval
*s
= stack
;
1277 GString
*str
= g_string_new ("");
1280 return g_string_free (str
, FALSE
);
1283 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1286 return g_string_free (str
, FALSE
);
1291 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1293 switch (type
->type
) {
1300 case MONO_TYPE_CHAR
:
1301 case MONO_TYPE_BOOLEAN
:
1302 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1304 case MONO_TYPE_STRING
:
1305 case MONO_TYPE_SZARRAY
:
1306 case MONO_TYPE_CLASS
:
1307 case MONO_TYPE_OBJECT
:
1308 case MONO_TYPE_ARRAY
:
1312 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1314 case MONO_TYPE_VALUETYPE
:
1315 if (type
->data
.klass
->enumtype
)
1316 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1318 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1322 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1327 GString
*res
= g_string_new ("");
1328 mono_type_get_desc (res
, type
, TRUE
);
1329 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1330 g_string_free (res
, TRUE
);
1338 dump_retval (InterpFrame
*inv
)
1340 GString
*str
= g_string_new ("");
1341 MonoType
*ret
= mono_method_signature (inv
->imethod
->method
)->ret
;
1343 if (ret
->type
!= MONO_TYPE_VOID
)
1344 dump_stackval (str
, inv
->retval
, ret
);
1346 return g_string_free (str
, FALSE
);
1351 dump_args (InterpFrame
*inv
)
1353 GString
*str
= g_string_new ("");
1355 MonoMethodSignature
*signature
= mono_method_signature (inv
->imethod
->method
);
1357 if (signature
->param_count
== 0 && !signature
->hasthis
)
1358 return g_string_free (str
, FALSE
);
1360 if (signature
->hasthis
) {
1361 MonoMethod
*method
= inv
->imethod
->method
;
1362 dump_stackval (str
, inv
->stack_args
, &method
->klass
->byval_arg
);
1365 for (i
= 0; i
< signature
->param_count
; ++i
)
1366 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1368 return g_string_free (str
, FALSE
);
1372 dump_frame (InterpFrame
*inv
)
1374 GString
*str
= g_string_new ("");
1379 for (i
= 0; inv
; inv
= inv
->parent
) {
1380 if (inv
->imethod
!= NULL
) {
1381 MonoMethod
*method
= inv
->imethod
->method
;
1385 const char * opname
= "";
1387 gchar
*source
= NULL
;
1391 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1392 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) == 0) {
1393 MonoMethodHeader
*hd
= mono_method_get_header_checked (method
, error
);
1394 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
1398 opname
= mono_interp_opname
[*inv
->ip
];
1399 codep
= inv
->ip
- inv
->imethod
->code
;
1400 source
= g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method
->name
, codep
);
1405 MonoDebugSourceLocation
*minfo
= mono_debug_lookup_method (method
);
1406 source
= mono_debug_method_lookup_location (minfo
, codep
);
1408 mono_metadata_free_mh (hd
);
1411 args
= dump_args (inv
);
1412 name
= mono_method_full_name (method
, TRUE
);
1414 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i
, codep
, opname
, name
, args
, source
);
1416 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s)\n", i
, codep
, opname
, name
, args
);
1423 return g_string_free (str
, FALSE
);
1427 get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
)
1434 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1435 if (inv
->imethod
!= NULL
)
1438 res
= mono_array_new_checked (domain
, mono_defaults
.int_class
, 3 * i
, error
);
1439 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
1441 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1442 if (inv
->imethod
!= NULL
) {
1443 mono_array_set (res
, gpointer
, i
, inv
->imethod
);
1445 mono_array_set (res
, gpointer
, i
, (gpointer
)inv
->ip
);
1447 mono_array_set (res
, gpointer
, i
, NULL
);
1455 #define MYGUINT64_MAX 18446744073709551615ULL
1456 #define MYGINT64_MAX 9223372036854775807LL
1457 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1459 #define MYGUINT32_MAX 4294967295U
1460 #define MYGINT32_MAX 2147483647
1461 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1463 #define CHECK_ADD_OVERFLOW(a,b) \
1464 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1465 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1467 #define CHECK_SUB_OVERFLOW(a,b) \
1468 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1469 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1471 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1472 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1474 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1475 (guint32)(a) < (guint32)(b) ? -1 : 0
1477 #define CHECK_ADD_OVERFLOW64(a,b) \
1478 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1479 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1481 #define CHECK_SUB_OVERFLOW64(a,b) \
1482 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1483 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1485 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1486 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1488 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1489 (guint64)(a) < (guint64)(b) ? -1 : 0
1491 #if SIZEOF_VOID_P == 4
1492 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1493 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1495 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1496 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1499 /* Resolves to TRUE if the operands would overflow */
1500 #define CHECK_MUL_OVERFLOW(a,b) \
1501 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1502 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1503 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1504 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1505 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1506 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1507 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1509 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1510 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1511 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1513 #define CHECK_MUL_OVERFLOW64(a,b) \
1514 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1515 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1516 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1517 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1518 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1519 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1520 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1522 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1523 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1524 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1526 #if SIZEOF_VOID_P == 4
1527 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1528 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1530 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1531 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1535 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1537 InterpFrame frame
, *old_frame
;
1538 ThreadContext
* volatile context
= mono_native_tls_get_value (thread_context_id
);
1539 MonoMethodSignature
*sig
= mono_method_signature (method
);
1540 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
1543 ThreadContext context_struct
;
1551 if (context
== NULL
) {
1552 context
= &context_struct
;
1553 memset (context
, 0, sizeof (ThreadContext
));
1554 set_context (context
);
1556 old_frame
= context
->current_frame
;
1559 MonoDomain
*domain
= mono_domain_get ();
1561 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (method
, FALSE
, TRUE
);
1563 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1565 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1566 args
= alloca (sizeof (stackval
) * 4);
1569 args
[0].data
.p
= obj
;
1571 args
[0].data
.p
= NULL
;
1572 args
[1].data
.p
= params
;
1573 args
[2].data
.p
= exc
;
1574 args
[3].data
.p
= method
;
1576 INIT_FRAME (&frame
, context
->current_frame
, args
, &result
, domain
, invoke_wrapper
, error
);
1579 frame
.invoke_trap
= 1;
1581 interp_exec_method (&frame
, context
);
1583 if (context
== &context_struct
)
1586 context
->current_frame
= old_frame
;
1590 *exc
= (MonoObject
*) frame
.ex
;
1593 mono_error_set_exception_instance (error
, frame
.ex
);
1596 return result
.data
.p
;
1600 InterpMethod
*rmethod
;
1604 gpointer
*many_args
;
1607 /* Main function for entering the interpreter from compiled code */
1609 interp_entry (InterpEntryData
*data
)
1612 InterpMethod
*rmethod
= data
->rmethod
;
1613 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
1614 ThreadContext context_struct
;
1615 InterpFrame
*old_frame
;
1619 MonoMethodSignature
*sig
;
1623 method
= rmethod
->method
;
1624 sig
= mono_method_signature (method
);
1626 // FIXME: Optimize this
1628 //printf ("%s\n", mono_method_full_name (method, 1));
1631 if (context
== NULL
) {
1632 context
= &context_struct
;
1633 memset (context
, 0, sizeof (ThreadContext
));
1634 set_context (context
);
1636 old_frame
= context
->current_frame
;
1639 args
= alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
1641 args
[0].data
.p
= data
->this_arg
;
1644 if (data
->many_args
)
1645 params
= data
->many_args
;
1647 params
= data
->args
;
1648 for (i
= 0; i
< sig
->param_count
; ++i
) {
1649 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1650 if (sig
->params
[i
]->byref
) {
1651 args
[a_index
].data
.p
= params
[i
];
1654 type
= rmethod
->param_types
[i
];
1655 switch (type
->type
) {
1656 case MONO_TYPE_VALUETYPE
:
1657 args
[a_index
].data
.p
= params
[i
];
1659 case MONO_TYPE_GENERICINST
:
1660 if (MONO_TYPE_IS_REFERENCE (type
))
1661 args
[a_index
].data
.p
= params
[i
];
1663 args
[a_index
].data
.vt
= params
[i
];
1666 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1671 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1673 type
= rmethod
->rtype
;
1674 switch (type
->type
) {
1675 case MONO_TYPE_GENERICINST
:
1676 if (!MONO_TYPE_IS_REFERENCE (type
))
1677 frame
.retval
->data
.vt
= data
->res
;
1679 case MONO_TYPE_VALUETYPE
:
1680 frame
.retval
->data
.vt
= data
->res
;
1686 interp_exec_method (&frame
, context
);
1687 if (context
== &context_struct
)
1690 context
->current_frame
= old_frame
;
1693 g_assert (frame
.ex
== NULL
);
1695 type
= rmethod
->rtype
;
1696 switch (type
->type
) {
1697 case MONO_TYPE_VOID
:
1699 case MONO_TYPE_OBJECT
:
1700 /* No need for a write barrier */
1701 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1703 case MONO_TYPE_GENERICINST
:
1704 if (MONO_TYPE_IS_REFERENCE (type
)) {
1705 *(MonoObject
**)data
->res
= *(MonoObject
**)frame
.retval
->data
.p
;
1707 /* Already set before the call */
1710 case MONO_TYPE_VALUETYPE
:
1711 /* Already set before the call */
1714 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1719 static MONO_NEVER_INLINE stackval
*
1720 do_icall (ThreadContext
*context
, int op
, stackval
*sp
, gpointer ptr
)
1723 interp_push_lmf (&ext
, context
->current_frame
);
1726 case MINT_ICALL_V_V
: {
1727 void (*func
)(void) = ptr
;
1731 case MINT_ICALL_V_P
: {
1732 gpointer (*func
)(void) = ptr
;
1734 sp
[-1].data
.p
= func ();
1737 case MINT_ICALL_P_V
: {
1738 void (*func
)(gpointer
) = ptr
;
1739 func (sp
[-1].data
.p
);
1743 case MINT_ICALL_P_P
: {
1744 gpointer (*func
)(gpointer
) = ptr
;
1745 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1748 case MINT_ICALL_PP_V
: {
1749 void (*func
)(gpointer
,gpointer
) = ptr
;
1751 func (sp
[0].data
.p
, sp
[1].data
.p
);
1754 case MINT_ICALL_PI_V
: {
1755 void (*func
)(gpointer
,int) = ptr
;
1757 func (sp
[0].data
.p
, sp
[1].data
.i
);
1760 case MINT_ICALL_PP_P
: {
1761 gpointer (*func
)(gpointer
,gpointer
) = ptr
;
1763 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1766 case MINT_ICALL_PI_P
: {
1767 gpointer (*func
)(gpointer
,int) = ptr
;
1769 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.i
);
1772 case MINT_ICALL_PPP_V
: {
1773 void (*func
)(gpointer
,gpointer
,gpointer
) = ptr
;
1775 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1778 case MINT_ICALL_PPI_V
: {
1779 void (*func
)(gpointer
,gpointer
,int) = ptr
;
1781 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
1784 case MINT_ICALL_PII_P
: {
1785 gpointer (*func
)(gpointer
,int,int) = ptr
;
1787 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.i
, sp
[1].data
.i
);
1790 case MINT_ICALL_PPII_V
: {
1791 gpointer (*func
)(gpointer
,gpointer
,int,int) = ptr
;
1793 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
, sp
[3].data
.i
);
1797 g_assert_not_reached ();
1800 interp_pop_lmf (&ext
);
1804 static MONO_NEVER_INLINE stackval
*
1805 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
)
1807 MonoMethodSignature
*sig
;
1808 MonoFtnDesc ftndesc
;
1809 guint8 res_buf
[256];
1813 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
1816 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1817 * by ref and return a return value using an explicit return value argument.
1819 if (!rmethod
->jit_wrapper
) {
1820 MonoMethod
*method
= rmethod
->method
;
1823 sig
= mono_method_signature (method
);
1826 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
1827 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1829 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
1830 mono_error_assert_ok (error
);
1832 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
1834 mono_error_assert_ok (error
);
1836 rmethod
->jit_addr
= addr
;
1837 rmethod
->jit_sig
= sig
;
1838 mono_memory_barrier ();
1839 rmethod
->jit_wrapper
= jit_wrapper
;
1842 sig
= rmethod
->jit_sig
;
1845 sp
-= sig
->param_count
;
1849 ftndesc
.addr
= rmethod
->jit_addr
;
1852 // FIXME: Optimize this
1856 int stack_index
= 0;
1857 if (rmethod
->hasthis
) {
1858 args
[pindex
++] = sp
[0].data
.p
;
1861 type
= rmethod
->rtype
;
1862 if (type
->type
!= MONO_TYPE_VOID
) {
1863 if (MONO_TYPE_ISSTRUCT (type
))
1864 args
[pindex
++] = vt_sp
;
1866 args
[pindex
++] = res_buf
;
1868 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
1869 MonoType
*t
= rmethod
->param_types
[i
];
1870 stackval
*sval
= &sp
[stack_index
+ i
];
1871 if (sig
->params
[i
]->byref
) {
1872 args
[pindex
++] = sval
->data
.p
;
1873 } else if (MONO_TYPE_ISSTRUCT (t
)) {
1874 args
[pindex
++] = sval
->data
.p
;
1875 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
1876 args
[pindex
++] = &sval
->data
.p
;
1885 case MONO_TYPE_VALUETYPE
:
1886 args
[pindex
++] = &sval
->data
.i
;
1889 case MONO_TYPE_FNPTR
:
1892 case MONO_TYPE_OBJECT
:
1893 args
[pindex
++] = &sval
->data
.p
;
1897 args
[pindex
++] = &sval
->data
.l
;
1900 printf ("%s\n", mono_type_full_name (t
));
1901 g_assert_not_reached ();
1906 interp_push_lmf (&ext
, frame
);
1910 void (*func
)(gpointer
) = rmethod
->jit_wrapper
;
1916 void (*func
)(gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1918 func (args
[0], &ftndesc
);
1922 void (*func
)(gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1924 func (args
[0], args
[1], &ftndesc
);
1928 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1930 func (args
[0], args
[1], args
[2], &ftndesc
);
1934 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1936 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
1940 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1942 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
1946 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1948 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
1952 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1954 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
1958 g_assert_not_reached ();
1962 interp_pop_lmf (&ext
);
1964 MonoType
*rtype
= rmethod
->rtype
;
1965 switch (rtype
->type
) {
1966 case MONO_TYPE_VOID
:
1967 case MONO_TYPE_OBJECT
:
1968 case MONO_TYPE_STRING
:
1969 case MONO_TYPE_CLASS
:
1970 case MONO_TYPE_ARRAY
:
1971 case MONO_TYPE_SZARRAY
:
1974 sp
->data
.p
= *(gpointer
*)res_buf
;
1977 sp
->data
.i
= *(gint8
*)res_buf
;
1980 sp
->data
.i
= *(guint8
*)res_buf
;
1983 sp
->data
.i
= *(gint16
*)res_buf
;
1986 sp
->data
.i
= *(guint16
*)res_buf
;
1989 sp
->data
.i
= *(gint32
*)res_buf
;
1992 sp
->data
.i
= *(guint32
*)res_buf
;
1994 case MONO_TYPE_VALUETYPE
:
1995 /* The result was written to vt_sp */
1998 case MONO_TYPE_GENERICINST
:
1999 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2000 sp
->data
.p
= *(gpointer
*)res_buf
;
2002 /* The result was written to vt_sp */
2007 g_print ("%s\n", mono_type_full_name (rtype
));
2008 g_assert_not_reached ();
2015 static MONO_NEVER_INLINE
void
2016 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2019 interp_push_lmf (&ext
, frame
);
2021 interp_pop_lmf (&ext
);
2024 static MONO_NEVER_INLINE
void
2025 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2028 /* Don't push lmf if we have no interp data */
2029 gboolean push_lmf
= frame
->parent
!= NULL
;
2031 /* Use the parent frame as the current frame is not complete yet */
2033 interp_push_lmf (&ext
, frame
->parent
);
2035 frame
->ex
= mono_interp_transform_method (frame
->imethod
, context
, frame
);
2038 interp_pop_lmf (&ext
);
2042 * These functions are the entry points into the interpreter from compiled code.
2043 * They are called by the interp_in wrappers. They have the following signature:
2044 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2045 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2046 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2047 * more wrappers then these functions.
2048 * this/static * ret/void * 16 arguments -> 64 functions.
2051 #define MAX_INTERP_ENTRY_ARGS 8
2053 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2054 InterpEntryData data; \
2055 (data).rmethod = (_method); \
2056 (data).res = (_res); \
2057 (data).this_arg = (_this_arg); \
2058 (data).many_args = NULL;
2060 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2061 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2062 interp_entry (&data); \
2064 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2065 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2066 (data).args [0] = arg1; \
2067 interp_entry (&data); \
2069 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2070 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2071 (data).args [0] = arg1; \
2072 (data).args [1] = arg2; \
2073 interp_entry (&data); \
2075 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2076 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2077 (data).args [0] = arg1; \
2078 (data).args [1] = arg2; \
2079 (data).args [2] = arg3; \
2080 interp_entry (&data); \
2082 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2083 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2084 (data).args [0] = arg1; \
2085 (data).args [1] = arg2; \
2086 (data).args [2] = arg3; \
2087 (data).args [3] = arg4; \
2088 interp_entry (&data); \
2090 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2091 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2092 (data).args [0] = arg1; \
2093 (data).args [1] = arg2; \
2094 (data).args [2] = arg3; \
2095 (data).args [3] = arg4; \
2096 (data).args [4] = arg5; \
2097 interp_entry (&data); \
2099 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2100 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2101 (data).args [0] = arg1; \
2102 (data).args [1] = arg2; \
2103 (data).args [2] = arg3; \
2104 (data).args [3] = arg4; \
2105 (data).args [4] = arg5; \
2106 (data).args [5] = arg6; \
2107 interp_entry (&data); \
2109 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2110 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2111 (data).args [0] = arg1; \
2112 (data).args [1] = arg2; \
2113 (data).args [2] = arg3; \
2114 (data).args [3] = arg4; \
2115 (data).args [4] = arg5; \
2116 (data).args [5] = arg6; \
2117 (data).args [6] = arg7; \
2118 interp_entry (&data); \
2120 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2121 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2122 (data).args [0] = arg1; \
2123 (data).args [1] = arg2; \
2124 (data).args [2] = arg3; \
2125 (data).args [3] = arg4; \
2126 (data).args [4] = arg5; \
2127 (data).args [5] = arg6; \
2128 (data).args [6] = arg7; \
2129 (data).args [7] = arg8; \
2130 interp_entry (&data); \
2133 #define ARGLIST0 InterpMethod *rmethod
2134 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2135 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2136 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2137 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2138 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2139 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2140 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2141 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2143 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2144 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2145 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2146 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2147 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2148 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2149 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2150 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2151 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2152 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2153 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2154 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2155 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2156 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2157 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2158 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2159 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2160 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2161 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2162 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2163 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2164 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2165 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2166 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2167 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2168 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2169 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2170 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2171 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2172 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2173 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2174 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2175 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2176 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2177 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2178 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2180 #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
2182 gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2183 gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2184 gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2185 gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2187 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2189 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2191 INTERP_ENTRY_BASE (rmethod
, this_arg
, res
);
2192 data
.many_args
= args
;
2193 interp_entry (&data
);
2197 * interp_create_method_pointer:
2199 * Return a function pointer which can be used to call METHOD using the
2200 * interpreter. Return NULL for methods which are not supported.
2203 interp_create_method_pointer (MonoMethod
*method
, MonoError
*error
)
2206 MonoMethodSignature
*sig
= mono_method_signature (method
);
2207 MonoMethod
*wrapper
;
2208 InterpMethod
*rmethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
2210 /* HACK: method_ptr of delegate should point to a runtime method*/
2211 if (method
->wrapper_type
&& (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
||
2212 (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)))
2215 if (rmethod
->jit_entry
)
2216 return rmethod
->jit_entry
;
2217 wrapper
= mini_get_interp_in_wrapper (sig
);
2219 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2220 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"", mono_method_get_full_name (wrapper
), mono_method_get_full_name (method
));
2222 gpointer entry_func
;
2223 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2224 entry_func
= interp_entry_general
;
2225 } else if (sig
->hasthis
) {
2226 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2227 entry_func
= entry_funcs_instance
[sig
->param_count
];
2229 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2231 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2232 entry_func
= entry_funcs_static
[sig
->param_count
];
2234 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2236 g_assert (entry_func
);
2238 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2239 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2240 ftndesc
->addr
= entry_func
;
2241 ftndesc
->arg
= rmethod
;
2242 mono_error_assert_ok (error
);
2245 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2246 * rgctx register using a trampoline.
2250 addr
= mono_aot_get_static_rgctx_trampoline (ftndesc
, jit_wrapper
);
2252 addr
= mono_arch_get_static_rgctx_trampoline (ftndesc
, jit_wrapper
);
2254 mono_memory_barrier ();
2255 rmethod
->jit_entry
= addr
;
2261 static int opcode_counts
[512];
2263 #define COUNT_OP(op) opcode_counts[op]++
2265 #define COUNT_OP(op)
2269 #define DUMP_INSTR() \
2270 if (tracing > 1) { \
2272 if (sp > frame->stack) { \
2273 ins = dump_stack (frame->stack, sp); \
2275 ins = g_strdup (""); \
2279 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2280 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2281 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2287 #define DUMP_INSTR()
2291 #define USE_COMPUTED_GOTO 1
2293 #if USE_COMPUTED_GOTO
2294 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2295 #define MINT_IN_CASE(x) LAB_ ## x:
2297 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2299 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2301 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2303 #define MINT_IN_SWITCH(op) switch (op)
2304 #define MINT_IN_CASE(x) case x:
2305 #define MINT_IN_BREAK break
2306 #define MINT_IN_DEFAULT default:
2310 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2311 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2314 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, guint16
*start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
, InterpFrame
*base_frame
)
2316 InterpFrame child_frame
;
2317 GSList
*finally_ips
= NULL
;
2318 const unsigned short *endfinally_ip
= NULL
;
2319 const unsigned short *ip
= NULL
;
2320 register stackval
*sp
;
2321 InterpMethod
*rtm
= NULL
;
2323 gint tracing
= global_tracing
;
2324 unsigned char *vtalloc
;
2329 unsigned char *vt_sp
;
2330 unsigned char *locals
;
2332 MonoObject
*o
= NULL
;
2334 #if USE_COMPUTED_GOTO
2335 static void *in_labels
[] = {
2336 #define OPDEF(a,b,c,d) \
2338 #include "mintops.def"
2343 frame
->ex_handler
= NULL
;
2345 frame
->domain
= mono_domain_get ();
2346 context
->current_frame
= frame
;
2348 debug_enter (frame
, &tracing
);
2350 rtm
= frame
->imethod
;
2351 if (!frame
->imethod
->transformed
) {
2353 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
2354 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2358 do_transform_method (frame
, context
);
2360 THROW_EX (frame
->ex
, NULL
);
2361 if (*mono_thread_interruption_request_flag ()) {
2362 MonoException
*exc
= mono_thread_interruption_checkpoint ();
2364 THROW_EX (exc
, NULL
);
2369 if (!start_with_ip
) {
2370 frame
->args
= alloca (rtm
->alloca_size
);
2371 memset (frame
->args
, 0, rtm
->alloca_size
);
2377 frame
->args
= alloca (rtm
->alloca_size
);
2378 memcpy (frame
->args
, base_frame
->args
, rtm
->alloca_size
);
2381 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2382 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2386 locals
= (unsigned char *) vt_sp
+ rtm
->vt_stack_size
;
2387 frame
->locals
= locals
;
2388 child_frame
.parent
= frame
;
2390 if (filter_exception
) {
2391 sp
->data
.p
= filter_exception
;
2396 * using while (ip < end) may result in a 15% performance drop,
2397 * but it may be useful for debug
2401 /* g_assert (sp >= frame->stack); */
2402 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2404 MINT_IN_SWITCH (*ip
) {
2405 MINT_IN_CASE(MINT_INITLOCALS
)
2406 memset (locals
, 0, rtm
->locals_size
);
2409 MINT_IN_CASE(MINT_NOP
)
2412 MINT_IN_CASE(MINT_NIY
)
2413 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2415 MINT_IN_CASE(MINT_BREAK
)
2417 do_debugger_tramp (mono_debugger_agent_user_break
, frame
);
2419 MINT_IN_CASE(MINT_LDNULL
)
2424 MINT_IN_CASE(MINT_VTRESULT
) {
2425 int ret_size
= * (guint16
*)(ip
+ 1);
2426 unsigned char *ret_vt_sp
= vt_sp
;
2427 vt_sp
-= READ32(ip
+ 2);
2429 memmove (vt_sp
, ret_vt_sp
, ret_size
);
2430 sp
[-1].data
.p
= vt_sp
;
2431 vt_sp
+= (ret_size
+ 7) & ~7;
2436 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2437 MINT_IN_CASE(MINT_LDC_I4_M1
)
2440 MINT_IN_CASE(MINT_LDC_I4_0
)
2443 MINT_IN_CASE(MINT_LDC_I4_1
)
2446 MINT_IN_CASE(MINT_LDC_I4_2
)
2449 MINT_IN_CASE(MINT_LDC_I4_3
)
2452 MINT_IN_CASE(MINT_LDC_I4_4
)
2455 MINT_IN_CASE(MINT_LDC_I4_5
)
2458 MINT_IN_CASE(MINT_LDC_I4_6
)
2461 MINT_IN_CASE(MINT_LDC_I4_7
)
2464 MINT_IN_CASE(MINT_LDC_I4_8
)
2467 MINT_IN_CASE(MINT_LDC_I4_S
)
2468 sp
->data
.i
= *(const short *)(ip
+ 1);
2472 MINT_IN_CASE(MINT_LDC_I4
)
2474 sp
->data
.i
= READ32 (ip
);
2478 MINT_IN_CASE(MINT_LDC_I8
)
2480 sp
->data
.l
= READ64 (ip
);
2484 MINT_IN_CASE(MINT_LDC_R4
) {
2488 sp
->data
.f
= * (float *)&val
;
2493 MINT_IN_CASE(MINT_LDC_R8
)
2494 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
2498 MINT_IN_CASE(MINT_DUP
)
2503 MINT_IN_CASE(MINT_DUP_VT
)
2504 i32
= READ32 (ip
+ 1);
2506 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
2507 vt_sp
+= (i32
+ 7) & ~7;
2511 MINT_IN_CASE(MINT_POP
) {
2512 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
2514 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
2519 MINT_IN_CASE(MINT_JMP
) {
2520 InterpMethod
*new_method
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2521 gboolean realloc_frame
= new_method
->alloca_size
> rtm
->alloca_size
;
2523 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
2524 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
2526 if (!new_method
->transformed
) {
2528 frame
->ex
= mono_interp_transform_method (new_method
, context
, NULL
);
2533 rtm
= frame
->imethod
= new_method
;
2535 * We allocate the stack frame from scratch and store the arguments in the
2536 * locals again since it's possible for the caller stack frame to be smaller
2537 * than the callee stack frame (at the interp level)
2539 if (realloc_frame
) {
2540 frame
->args
= alloca (rtm
->alloca_size
);
2541 memset (frame
->args
, 0, rtm
->alloca_size
);
2542 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2544 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2548 locals
= vt_sp
+ rtm
->vt_stack_size
;
2549 frame
->locals
= locals
;
2553 ip
= rtm
->new_body_start
; /* bypass storing input args from callers frame */
2556 MINT_IN_CASE(MINT_CALLI
) {
2557 MonoMethodSignature
*csignature
;
2558 stackval
*endsp
= sp
;
2562 csignature
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2566 child_frame
.imethod
= sp
->data
.p
;
2569 child_frame
.retval
= sp
;
2570 /* decrement by the actual number of args */
2571 sp
-= csignature
->param_count
;
2572 if (csignature
->hasthis
)
2574 child_frame
.stack_args
= sp
;
2576 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
2577 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
2578 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2581 if (csignature
->hasthis
) {
2582 MonoObject
*this_arg
= sp
->data
.p
;
2584 if (this_arg
->vtable
->klass
->valuetype
) {
2585 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2586 sp
[0].data
.p
= unboxed
;
2590 interp_exec_method (&child_frame
, context
);
2592 context
->current_frame
= frame
;
2594 if (context
->has_resume_state
) {
2595 if (frame
== context
->handler_frame
)
2596 SET_RESUME_STATE (context
);
2601 CHECK_CHILD_EX (child_frame
, ip
- 2);
2603 /* need to handle typedbyref ... */
2604 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2610 MINT_IN_CASE(MINT_CALLI_NAT
) {
2611 MonoMethodSignature
*csignature
;
2612 stackval
*endsp
= sp
;
2613 unsigned char *code
= NULL
;
2617 csignature
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2622 child_frame
.imethod
= NULL
;
2625 child_frame
.retval
= sp
;
2626 /* decrement by the actual number of args */
2627 sp
-= csignature
->param_count
;
2628 if (csignature
->hasthis
)
2630 child_frame
.stack_args
= sp
;
2631 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
);
2633 context
->current_frame
= frame
;
2635 if (context
->has_resume_state
) {
2636 if (frame
== context
->handler_frame
)
2637 SET_RESUME_STATE (context
);
2642 CHECK_CHILD_EX (child_frame
, ip
- 2);
2644 /* need to handle typedbyref ... */
2645 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2651 MINT_IN_CASE(MINT_CALL
) {
2652 stackval
*endsp
= sp
;
2656 child_frame
.imethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2659 child_frame
.retval
= sp
;
2660 /* decrement by the actual number of args */
2661 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
;
2663 child_frame
.stack_args
= sp
;
2665 interp_exec_method (&child_frame
, context
);
2667 context
->current_frame
= frame
;
2669 if (context
->has_resume_state
) {
2670 if (frame
== context
->handler_frame
)
2671 SET_RESUME_STATE (context
);
2675 CHECK_CHILD_EX (child_frame
, ip
- 2);
2677 /* need to handle typedbyref ... */
2682 MINT_IN_CASE(MINT_VCALL
) {
2685 child_frame
.imethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2689 child_frame
.retval
= sp
;
2690 /* decrement by the actual number of args */
2691 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
;
2692 child_frame
.stack_args
= sp
;
2694 interp_exec_method (&child_frame
, context
);
2696 context
->current_frame
= frame
;
2698 if (context
->has_resume_state
) {
2699 if (frame
== context
->handler_frame
)
2700 SET_RESUME_STATE (context
);
2705 CHECK_CHILD_EX (child_frame
, ip
- 2);
2709 MINT_IN_CASE(MINT_JIT_CALL
) {
2710 InterpMethod
*rmethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2713 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
);
2715 if (context
->has_resume_state
) {
2717 * If this bit is set, it means the call has thrown the exception, and we
2718 * reached this point because the EH code in mono_handle_exception ()
2719 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2720 * has set the fields in context to indicate where we have to resume execution.
2722 if (frame
== context
->handler_frame
)
2723 SET_RESUME_STATE (context
);
2727 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
2733 MINT_IN_CASE(MINT_CALLVIRT
) {
2734 stackval
*endsp
= sp
;
2735 MonoObject
*this_arg
;
2740 token
= * (unsigned short *)(ip
+ 1);
2742 child_frame
.imethod
= rtm
->data_items
[token
];
2744 child_frame
.retval
= sp
;
2746 /* decrement by the actual number of args */
2747 sp
-= child_frame
.imethod
->param_count
+ 1;
2748 child_frame
.stack_args
= sp
;
2749 this_arg
= sp
->data
.p
;
2750 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
2752 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2753 if (this_class
->valuetype
&& child_frame
.imethod
->method
->klass
->valuetype
) {
2755 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2756 sp
[0].data
.p
= unboxed
;
2759 interp_exec_method (&child_frame
, context
);
2761 context
->current_frame
= frame
;
2763 if (context
->has_resume_state
) {
2764 if (frame
== context
->handler_frame
)
2765 SET_RESUME_STATE (context
);
2770 CHECK_CHILD_EX (child_frame
, ip
- 2);
2772 /* need to handle typedbyref ... */
2777 MINT_IN_CASE(MINT_VCALLVIRT
) {
2778 MonoObject
*this_arg
;
2783 token
= * (unsigned short *)(ip
+ 1);
2785 child_frame
.imethod
= rtm
->data_items
[token
];
2787 child_frame
.retval
= sp
;
2789 /* decrement by the actual number of args */
2790 sp
-= child_frame
.imethod
->param_count
+ 1;
2791 child_frame
.stack_args
= sp
;
2792 this_arg
= sp
->data
.p
;
2793 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
2795 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2796 if (this_class
->valuetype
&& child_frame
.imethod
->method
->klass
->valuetype
) {
2797 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2798 sp
[0].data
.p
= unboxed
;
2801 interp_exec_method (&child_frame
, context
);
2803 context
->current_frame
= frame
;
2805 if (context
->has_resume_state
) {
2806 if (frame
== context
->handler_frame
)
2807 SET_RESUME_STATE (context
);
2812 CHECK_CHILD_EX (child_frame
, ip
- 2);
2815 MINT_IN_CASE(MINT_CALLRUN
)
2816 ves_imethod (frame
, context
);
2818 MonoException
*fex
= frame
->ex
;
2819 //frame = frame->parent;
2820 THROW_EX (fex
, frame
->ip
);
2823 MINT_IN_CASE(MINT_RET
)
2825 *frame
->retval
= *sp
;
2826 if (sp
> frame
->stack
)
2827 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
2829 MINT_IN_CASE(MINT_RET_VOID
)
2830 if (sp
> frame
->stack
)
2831 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
2833 MINT_IN_CASE(MINT_RET_VT
)
2834 i32
= READ32(ip
+ 1);
2836 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
2837 if (sp
> frame
->stack
)
2838 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
2840 MINT_IN_CASE(MINT_BR_S
)
2841 /* Checkpoint to be able to handle aborts */
2842 EXCEPTION_CHECKPOINT
;
2843 ip
+= (short) *(ip
+ 1);
2845 MINT_IN_CASE(MINT_BR
)
2846 /* Checkpoint to be able to handle aborts */
2847 EXCEPTION_CHECKPOINT
;
2848 ip
+= (gint32
) READ32(ip
+ 1);
2850 #define ZEROP_S(datamem, op) \
2852 if (sp->data.datamem op 0) \
2853 ip += * (gint16 *)(ip + 1); \
2857 #define ZEROP(datamem, op) \
2859 if (sp->data.datamem op 0) \
2860 ip += READ32(ip + 1); \
2864 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
2867 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
2870 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
2873 MINT_IN_CASE(MINT_BRFALSE_I4
)
2876 MINT_IN_CASE(MINT_BRFALSE_I8
)
2879 MINT_IN_CASE(MINT_BRFALSE_R8
)
2882 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
2885 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
2888 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
2891 MINT_IN_CASE(MINT_BRTRUE_I4
)
2894 MINT_IN_CASE(MINT_BRTRUE_I8
)
2897 MINT_IN_CASE(MINT_BRTRUE_R8
)
2900 #define CONDBR_S(cond) \
2903 ip += * (gint16 *)(ip + 1); \
2906 #define BRELOP_S(datamem, op) \
2907 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2909 #define CONDBR(cond) \
2912 ip += READ32(ip + 1); \
2916 #define BRELOP(datamem, op) \
2917 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2919 MINT_IN_CASE(MINT_BEQ_I4_S
)
2922 MINT_IN_CASE(MINT_BEQ_I8_S
)
2925 MINT_IN_CASE(MINT_BEQ_R8_S
)
2926 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
2928 MINT_IN_CASE(MINT_BEQ_I4
)
2931 MINT_IN_CASE(MINT_BEQ_I8
)
2934 MINT_IN_CASE(MINT_BEQ_R8
)
2935 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
2937 MINT_IN_CASE(MINT_BGE_I4_S
)
2940 MINT_IN_CASE(MINT_BGE_I8_S
)
2943 MINT_IN_CASE(MINT_BGE_R8_S
)
2944 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
2946 MINT_IN_CASE(MINT_BGE_I4
)
2949 MINT_IN_CASE(MINT_BGE_I8
)
2952 MINT_IN_CASE(MINT_BGE_R8
)
2953 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
2955 MINT_IN_CASE(MINT_BGT_I4_S
)
2958 MINT_IN_CASE(MINT_BGT_I8_S
)
2961 MINT_IN_CASE(MINT_BGT_R8_S
)
2962 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
2964 MINT_IN_CASE(MINT_BGT_I4
)
2967 MINT_IN_CASE(MINT_BGT_I8
)
2970 MINT_IN_CASE(MINT_BGT_R8
)
2971 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
2973 MINT_IN_CASE(MINT_BLT_I4_S
)
2976 MINT_IN_CASE(MINT_BLT_I8_S
)
2979 MINT_IN_CASE(MINT_BLT_R8_S
)
2980 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
2982 MINT_IN_CASE(MINT_BLT_I4
)
2985 MINT_IN_CASE(MINT_BLT_I8
)
2988 MINT_IN_CASE(MINT_BLT_R8
)
2989 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
2991 MINT_IN_CASE(MINT_BLE_I4_S
)
2994 MINT_IN_CASE(MINT_BLE_I8_S
)
2997 MINT_IN_CASE(MINT_BLE_R8_S
)
2998 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3000 MINT_IN_CASE(MINT_BLE_I4
)
3003 MINT_IN_CASE(MINT_BLE_I8
)
3006 MINT_IN_CASE(MINT_BLE_R8
)
3007 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3009 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3012 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3015 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3016 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3018 MINT_IN_CASE(MINT_BNE_UN_I4
)
3021 MINT_IN_CASE(MINT_BNE_UN_I8
)
3024 MINT_IN_CASE(MINT_BNE_UN_R8
)
3025 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3028 #define BRELOP_S_CAST(datamem, op, type) \
3030 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3031 ip += * (gint16 *)(ip + 1); \
3035 #define BRELOP_CAST(datamem, op, type) \
3037 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3038 ip += READ32(ip + 1); \
3042 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3043 BRELOP_S_CAST(i
, >=, guint32
);
3045 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3046 BRELOP_S_CAST(l
, >=, guint64
);
3048 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3049 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3051 MINT_IN_CASE(MINT_BGE_UN_I4
)
3052 BRELOP_CAST(i
, >=, guint32
);
3054 MINT_IN_CASE(MINT_BGE_UN_I8
)
3055 BRELOP_CAST(l
, >=, guint64
);
3057 MINT_IN_CASE(MINT_BGE_UN_R8
)
3058 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3060 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3061 BRELOP_S_CAST(i
, >, guint32
);
3063 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3064 BRELOP_S_CAST(l
, >, guint64
);
3066 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3067 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3069 MINT_IN_CASE(MINT_BGT_UN_I4
)
3070 BRELOP_CAST(i
, >, guint32
);
3072 MINT_IN_CASE(MINT_BGT_UN_I8
)
3073 BRELOP_CAST(l
, >, guint64
);
3075 MINT_IN_CASE(MINT_BGT_UN_R8
)
3076 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3078 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3079 BRELOP_S_CAST(i
, <=, guint32
);
3081 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3082 BRELOP_S_CAST(l
, <=, guint64
);
3084 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3085 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3087 MINT_IN_CASE(MINT_BLE_UN_I4
)
3088 BRELOP_CAST(i
, <=, guint32
);
3090 MINT_IN_CASE(MINT_BLE_UN_I8
)
3091 BRELOP_CAST(l
, <=, guint64
);
3093 MINT_IN_CASE(MINT_BLE_UN_R8
)
3094 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3096 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3097 BRELOP_S_CAST(i
, <, guint32
);
3099 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3100 BRELOP_S_CAST(l
, <, guint64
);
3102 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3103 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3105 MINT_IN_CASE(MINT_BLT_UN_I4
)
3106 BRELOP_CAST(i
, <, guint32
);
3108 MINT_IN_CASE(MINT_BLT_UN_I8
)
3109 BRELOP_CAST(l
, <, guint64
);
3111 MINT_IN_CASE(MINT_BLT_UN_R8
)
3112 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3114 MINT_IN_CASE(MINT_SWITCH
) {
3116 const unsigned short *st
;
3122 if ((guint32
)sp
->data
.i
< n
) {
3124 ip
+= 2 * (guint32
)sp
->data
.i
;
3125 offset
= READ32 (ip
);
3132 MINT_IN_CASE(MINT_LDIND_I1
)
3134 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3136 MINT_IN_CASE(MINT_LDIND_U1
)
3138 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3140 MINT_IN_CASE(MINT_LDIND_I2
)
3142 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3144 MINT_IN_CASE(MINT_LDIND_U2
)
3146 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3148 MINT_IN_CASE(MINT_LDIND_I4
) /* Fall through */
3149 MINT_IN_CASE(MINT_LDIND_U4
)
3151 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3153 MINT_IN_CASE(MINT_LDIND_I8
)
3155 /* memmove handles unaligned case */
3156 memmove (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
3158 MINT_IN_CASE(MINT_LDIND_I
) {
3159 guint16 offset
= * (guint16
*)(ip
+ 1);
3160 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3164 MINT_IN_CASE(MINT_LDIND_R4
)
3166 sp
[-1].data
.f
= *(gfloat
*)sp
[-1].data
.p
;
3168 MINT_IN_CASE(MINT_LDIND_R8
)
3170 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3172 MINT_IN_CASE(MINT_LDIND_REF
)
3174 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3176 MINT_IN_CASE(MINT_STIND_REF
)
3179 mono_gc_wbarrier_generic_store (sp
->data
.p
, sp
[1].data
.p
);
3181 MINT_IN_CASE(MINT_STIND_I1
)
3184 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3186 MINT_IN_CASE(MINT_STIND_I2
)
3189 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3191 MINT_IN_CASE(MINT_STIND_I4
)
3194 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3196 MINT_IN_CASE(MINT_STIND_I
)
3199 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3201 MINT_IN_CASE(MINT_STIND_I8
)
3204 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3206 MINT_IN_CASE(MINT_STIND_R4
)
3209 * (float *) sp
->data
.p
= (gfloat
)sp
[1].data
.f
;
3211 MINT_IN_CASE(MINT_STIND_R8
)
3214 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3216 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3219 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3221 #define BINOP(datamem, op) \
3223 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3225 MINT_IN_CASE(MINT_ADD_I4
)
3228 MINT_IN_CASE(MINT_ADD_I8
)
3231 MINT_IN_CASE(MINT_ADD_R8
)
3234 MINT_IN_CASE(MINT_ADD1_I4
)
3238 MINT_IN_CASE(MINT_SUB_I4
)
3241 MINT_IN_CASE(MINT_SUB_I8
)
3244 MINT_IN_CASE(MINT_SUB_R8
)
3247 MINT_IN_CASE(MINT_SUB1_I4
)
3251 MINT_IN_CASE(MINT_MUL_I4
)
3254 MINT_IN_CASE(MINT_MUL_I8
)
3257 MINT_IN_CASE(MINT_MUL_R8
)
3260 MINT_IN_CASE(MINT_DIV_I4
)
3261 if (sp
[-1].data
.i
== 0)
3262 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3263 if (sp
[-1].data
.i
== (-1))
3264 THROW_EX (mono_get_exception_overflow (), ip
);
3267 MINT_IN_CASE(MINT_DIV_I8
)
3268 if (sp
[-1].data
.l
== 0)
3269 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3270 if (sp
[-1].data
.l
== (-1))
3271 THROW_EX (mono_get_exception_overflow (), ip
);
3274 MINT_IN_CASE(MINT_DIV_R8
)
3278 #define BINOP_CAST(datamem, op, type) \
3280 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3282 MINT_IN_CASE(MINT_DIV_UN_I4
)
3283 if (sp
[-1].data
.i
== 0)
3284 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3285 BINOP_CAST(i
, /, guint32
);
3287 MINT_IN_CASE(MINT_DIV_UN_I8
)
3288 if (sp
[-1].data
.l
== 0)
3289 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3290 BINOP_CAST(l
, /, guint64
);
3292 MINT_IN_CASE(MINT_REM_I4
)
3293 if (sp
[-1].data
.i
== 0)
3294 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3295 if (sp
[-1].data
.i
== (-1))
3296 THROW_EX (mono_get_exception_overflow (), ip
);
3299 MINT_IN_CASE(MINT_REM_I8
)
3300 if (sp
[-1].data
.l
== 0)
3301 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3302 if (sp
[-1].data
.l
== (-1))
3303 THROW_EX (mono_get_exception_overflow (), ip
);
3306 MINT_IN_CASE(MINT_REM_R8
)
3307 /* FIXME: what do we actually do here? */
3309 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
3312 MINT_IN_CASE(MINT_REM_UN_I4
)
3313 if (sp
[-1].data
.i
== 0)
3314 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3315 BINOP_CAST(i
, %, guint32
);
3317 MINT_IN_CASE(MINT_REM_UN_I8
)
3318 if (sp
[-1].data
.l
== 0)
3319 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3320 BINOP_CAST(l
, %, guint64
);
3322 MINT_IN_CASE(MINT_AND_I4
)
3325 MINT_IN_CASE(MINT_AND_I8
)
3328 MINT_IN_CASE(MINT_OR_I4
)
3331 MINT_IN_CASE(MINT_OR_I8
)
3334 MINT_IN_CASE(MINT_XOR_I4
)
3337 MINT_IN_CASE(MINT_XOR_I8
)
3341 #define SHIFTOP(datamem, op) \
3343 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3346 MINT_IN_CASE(MINT_SHL_I4
)
3349 MINT_IN_CASE(MINT_SHL_I8
)
3352 MINT_IN_CASE(MINT_SHR_I4
)
3355 MINT_IN_CASE(MINT_SHR_I8
)
3358 MINT_IN_CASE(MINT_SHR_UN_I4
)
3360 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
3363 MINT_IN_CASE(MINT_SHR_UN_I8
)
3365 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
3368 MINT_IN_CASE(MINT_NEG_I4
)
3369 sp
[-1].data
.i
= - sp
[-1].data
.i
;
3372 MINT_IN_CASE(MINT_NEG_I8
)
3373 sp
[-1].data
.l
= - sp
[-1].data
.l
;
3376 MINT_IN_CASE(MINT_NEG_R8
)
3377 sp
[-1].data
.f
= - sp
[-1].data
.f
;
3380 MINT_IN_CASE(MINT_NOT_I4
)
3381 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
3384 MINT_IN_CASE(MINT_NOT_I8
)
3385 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
3388 MINT_IN_CASE(MINT_CONV_I1_I4
)
3389 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
3392 MINT_IN_CASE(MINT_CONV_I1_I8
)
3393 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
3396 MINT_IN_CASE(MINT_CONV_I1_R8
)
3397 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.f
;
3400 MINT_IN_CASE(MINT_CONV_U1_I4
)
3401 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
3404 MINT_IN_CASE(MINT_CONV_U1_I8
)
3405 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
3408 MINT_IN_CASE(MINT_CONV_U1_R8
)
3409 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.f
;
3412 MINT_IN_CASE(MINT_CONV_I2_I4
)
3413 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
3416 MINT_IN_CASE(MINT_CONV_I2_I8
)
3417 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
3420 MINT_IN_CASE(MINT_CONV_I2_R8
)
3421 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.f
;
3424 MINT_IN_CASE(MINT_CONV_U2_I4
)
3425 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
3428 MINT_IN_CASE(MINT_CONV_U2_I8
)
3429 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
3432 MINT_IN_CASE(MINT_CONV_U2_R8
)
3433 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.f
;
3436 MINT_IN_CASE(MINT_CONV_I4_R8
)
3437 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
3440 MINT_IN_CASE(MINT_CONV_U4_I8
)
3441 MINT_IN_CASE(MINT_CONV_I4_I8
)
3442 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
3445 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
3446 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
3449 MINT_IN_CASE(MINT_CONV_U4_R8
)
3450 /* needed on arm64 */
3451 if (isinf (sp
[-1].data
.f
))
3453 /* needed by wasm */
3454 else if (isnan (sp
[-1].data
.f
))
3457 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3460 MINT_IN_CASE(MINT_CONV_I8_I4
)
3461 sp
[-1].data
.l
= sp
[-1].data
.i
;
3464 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
3465 sp
[-2].data
.l
= sp
[-2].data
.i
;
3468 MINT_IN_CASE(MINT_CONV_I8_U4
)
3469 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
3472 MINT_IN_CASE(MINT_CONV_I8_R8
)
3473 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
3476 MINT_IN_CASE(MINT_CONV_R4_I4
)
3477 sp
[-1].data
.f
= (float)sp
[-1].data
.i
;
3480 MINT_IN_CASE(MINT_CONV_R4_I8
)
3481 sp
[-1].data
.f
= (float)sp
[-1].data
.l
;
3484 MINT_IN_CASE(MINT_CONV_R4_R8
)
3485 sp
[-1].data
.f
= (float)sp
[-1].data
.f
;
3488 MINT_IN_CASE(MINT_CONV_R8_I4
)
3489 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
3492 MINT_IN_CASE(MINT_CONV_R8_I8
)
3493 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
3496 MINT_IN_CASE(MINT_CONV_U8_I4
)
3497 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
3500 MINT_IN_CASE(MINT_CONV_U8_R8
)
3501 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
3504 MINT_IN_CASE(MINT_CPOBJ
) {
3505 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3506 g_assert (c
->valuetype
);
3507 /* if this assertion fails, we need to add a write barrier */
3508 g_assert (!MONO_TYPE_IS_REFERENCE (&c
->byval_arg
));
3509 if (mint_type (&c
->byval_arg
) == MINT_TYPE_VT
)
3510 stackval_from_data (&c
->byval_arg
, &sp
[-2], sp
[-1].data
.p
, FALSE
);
3512 stackval_from_data (&c
->byval_arg
, sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
3517 MINT_IN_CASE(MINT_LDOBJ
) {
3519 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3522 if (mint_type (&c
->byval_arg
) == MINT_TYPE_VT
&& !c
->enumtype
) {
3523 int size
= mono_class_value_size (c
, NULL
);
3524 sp
[-1].data
.p
= vt_sp
;
3525 vt_sp
+= (size
+ 7) & ~7;
3527 stackval_from_data (&c
->byval_arg
, &sp
[-1], p
, FALSE
);
3530 MINT_IN_CASE(MINT_LDSTR
)
3531 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3535 MINT_IN_CASE(MINT_NEWOBJ
) {
3536 MonoClass
*newobj_class
;
3537 MonoMethodSignature
*csig
;
3538 stackval valuetype_this
;
3544 token
= * (guint16
*)(ip
+ 1);
3547 child_frame
.ip
= NULL
;
3548 child_frame
.ex
= NULL
;
3550 child_frame
.imethod
= rtm
->data_items
[token
];
3551 csig
= mono_method_signature (child_frame
.imethod
->method
);
3552 newobj_class
= child_frame
.imethod
->method
->klass
;
3553 /*if (profiling_classes) {
3554 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3556 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3559 if (newobj_class
->parent
== mono_defaults
.array_class
) {
3560 sp
-= csig
->param_count
;
3561 child_frame
.stack_args
= sp
;
3562 o
= ves_array_create (&child_frame
, rtm
->domain
, newobj_class
, csig
, sp
);
3563 CHECK_CHILD_EX (child_frame
, ip
- 2);
3564 goto array_constructed
;
3567 g_assert (csig
->hasthis
);
3568 if (csig
->param_count
) {
3569 sp
-= csig
->param_count
;
3570 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
3572 child_frame
.stack_args
= sp
;
3575 * First arg is the object.
3577 if (newobj_class
->valuetype
) {
3578 MonoType
*t
= &newobj_class
->byval_arg
;
3579 memset (&valuetype_this
, 0, sizeof (stackval
));
3580 if (!newobj_class
->enumtype
&& (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3582 valuetype_this
.data
.p
= vt_sp
;
3584 sp
->data
.p
= &valuetype_this
;
3587 if (newobj_class
!= mono_defaults
.string_class
) {
3588 MonoVTable
*vtable
= mono_class_vtable_checked (rtm
->domain
, newobj_class
, error
);
3589 if (!mono_error_ok (error
) || !mono_runtime_class_init_full (vtable
, error
))
3590 THROW_EX (mono_error_convert_to_exception (error
), ip
);
3591 o
= mono_object_new_checked (rtm
->domain
, newobj_class
, error
);
3592 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3593 EXCEPTION_CHECKPOINT
;
3595 #ifndef DISABLE_REMOTING
3596 if (mono_object_is_transparent_proxy (o
)) {
3597 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
.imethod
->method
, error
);
3598 mono_error_assert_ok (error
);
3599 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, remoting_invoke_method
, error
);
3600 mono_error_assert_ok (error
);
3605 child_frame
.retval
= &retval
;
3609 g_assert (csig
->call_convention
== MONO_CALL_DEFAULT
);
3611 interp_exec_method (&child_frame
, context
);
3613 context
->current_frame
= frame
;
3615 if (context
->has_resume_state
) {
3616 if (frame
== context
->handler_frame
)
3617 SET_RESUME_STATE (context
);
3622 CHECK_CHILD_EX (child_frame
, ip
- 2);
3624 * a constructor returns void, but we need to return the object we created
3627 if (newobj_class
->valuetype
&& !newobj_class
->enumtype
) {
3628 *sp
= valuetype_this
;
3629 } else if (newobj_class
== mono_defaults
.string_class
) {
3637 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
3641 token
= * (guint16
*)(ip
+ 1);
3646 MINT_IN_CASE(MINT_CASTCLASS
)
3647 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3648 if ((o
= sp
[-1].data
.p
)) {
3649 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
3650 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3652 THROW_EX (mono_get_exception_invalid_cast (), ip
);
3656 MINT_IN_CASE(MINT_ISINST
)
3657 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3658 if ((o
= sp
[-1].data
.p
)) {
3659 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
3660 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3662 sp
[-1].data
.p
= NULL
;
3666 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
3667 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
3670 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
3671 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
3674 MINT_IN_CASE(MINT_UNBOX
)
3675 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3679 THROW_EX (mono_get_exception_null_reference (), ip
);
3681 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
3682 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3683 if (!(isinst_obj
|| ((o
->vtable
->klass
->rank
== 0) && (o
->vtable
->klass
->element_class
== c
->element_class
))))
3684 THROW_EX (mono_get_exception_invalid_cast (), ip
);
3686 sp
[-1].data
.p
= mono_object_unbox (o
);
3689 MINT_IN_CASE(MINT_THROW
)
3691 frame
->ex_handler
= NULL
;
3693 sp
->data
.p
= mono_get_exception_null_reference ();
3695 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
3697 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
3699 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
3702 MINT_IN_CASE(MINT_LDFLDA
)
3705 THROW_EX (mono_get_exception_null_reference (), ip
);
3706 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
3709 MINT_IN_CASE(MINT_CKNULL
)
3712 THROW_EX (mono_get_exception_null_reference (), ip
);
3715 MINT_IN_CASE(MINT_CKNULL_N
) {
3716 /* Same as CKNULL, but further down the stack */
3717 int n
= *(guint16
*)(ip
+ 1);
3720 THROW_EX (mono_get_exception_null_reference (), ip
);
3725 #define LDFLD(datamem, fieldtype) \
3726 o = sp [-1].data.p; \
3728 THROW_EX (mono_get_exception_null_reference (), ip); \
3729 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3732 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
3733 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
3734 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
3735 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
3736 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
3737 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
3738 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f
, float); MINT_IN_BREAK
;
3739 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
3740 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
3741 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
3743 MINT_IN_CASE(MINT_LDFLD_VT
)
3746 THROW_EX (mono_get_exception_null_reference (), ip
);
3748 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 2)];
3749 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3750 i32
= mono_class_value_size (klass
, NULL
);
3752 sp
[-1].data
.p
= vt_sp
;
3753 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
3754 vt_sp
+= (i32
+ 7) & ~7;
3758 MINT_IN_CASE(MINT_LDRMFLD
) {
3760 MonoClassField
*field
;
3765 THROW_EX (mono_get_exception_null_reference (), ip
);
3766 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3768 #ifndef DISABLE_REMOTING
3769 if (mono_object_is_transparent_proxy (o
)) {
3770 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3772 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3773 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3776 addr
= (char*)o
+ field
->offset
;
3778 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
3782 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
3783 MonoClassField
*field
;
3789 THROW_EX (mono_get_exception_null_reference (), ip
);
3791 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3792 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3793 i32
= mono_class_value_size (klass
, NULL
);
3796 #ifndef DISABLE_REMOTING
3797 if (mono_object_is_transparent_proxy (o
)) {
3798 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3799 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3800 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3803 addr
= (char*)o
+ field
->offset
;
3805 sp
[-1].data
.p
= vt_sp
;
3806 memcpy(sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
3807 vt_sp
+= (i32
+ 7) & ~7;
3808 memcpy(sp
[-1].data
.p
, addr
, i32
);
3812 #define STFLD(datamem, fieldtype) \
3813 o = sp [-2].data.p; \
3815 THROW_EX (mono_get_exception_null_reference (), ip); \
3817 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3820 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
3821 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
3822 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
3823 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
3824 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
3825 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
3826 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f
, float); MINT_IN_BREAK
;
3827 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
3828 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
3829 MINT_IN_CASE(MINT_STFLD_O
)
3832 THROW_EX (mono_get_exception_null_reference (), ip
);
3834 mono_gc_wbarrier_set_field (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.p
);
3838 MINT_IN_CASE(MINT_STFLD_VT
) {
3841 THROW_EX (mono_get_exception_null_reference (), ip
);
3844 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 2)];
3845 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3846 i32
= mono_class_value_size (klass
, NULL
);
3848 guint16 offset
= * (guint16
*)(ip
+ 1);
3849 mono_value_copy ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
3851 vt_sp
-= (i32
+ 7) & ~7;
3855 MINT_IN_CASE(MINT_STRMFLD
) {
3856 MonoClassField
*field
;
3860 THROW_EX (mono_get_exception_null_reference (), ip
);
3862 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3865 #ifndef DISABLE_REMOTING
3866 if (mono_object_is_transparent_proxy (o
)) {
3867 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3868 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
3869 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3872 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
3877 MINT_IN_CASE(MINT_STRMFLD_VT
) {
3878 MonoClassField
*field
;
3882 THROW_EX (mono_get_exception_null_reference (), ip
);
3883 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3884 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3885 i32
= mono_class_value_size (klass
, NULL
);
3888 #ifndef DISABLE_REMOTING
3889 if (mono_object_is_transparent_proxy (o
)) {
3890 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3891 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
3892 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3895 mono_value_copy ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3898 vt_sp
-= (i32
+ 7) & ~7;
3901 MINT_IN_CASE(MINT_LDSFLDA
) {
3902 MonoClassField
*field
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3903 sp
->data
.p
= mono_class_static_field_address (rtm
->domain
, field
);
3904 EXCEPTION_CHECKPOINT
;
3909 MINT_IN_CASE(MINT_LDSFLD
) {
3910 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3911 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3912 EXCEPTION_CHECKPOINT
;
3913 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
3918 MINT_IN_CASE(MINT_LDSFLD_VT
) {
3919 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3920 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3921 EXCEPTION_CHECKPOINT
;
3922 int size
= READ32 (ip
+ 2);
3926 vt_sp
+= (size
+ 7) & ~7;
3927 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
3931 MINT_IN_CASE(MINT_STSFLD
) {
3932 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3933 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3934 EXCEPTION_CHECKPOINT
;
3937 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
3940 MINT_IN_CASE(MINT_STSFLD_VT
) {
3941 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3942 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3943 EXCEPTION_CHECKPOINT
;
3944 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3945 i32
= mono_class_value_size (klass
, NULL
);
3949 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
3950 vt_sp
-= (i32
+ 7) & ~7;
3953 MINT_IN_CASE(MINT_STOBJ_VT
) {
3955 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3957 size
= mono_class_value_size (c
, NULL
);
3958 memcpy(sp
[-2].data
.p
, sp
[-1].data
.p
, size
);
3959 vt_sp
-= (size
+ 7) & ~7;
3963 MINT_IN_CASE(MINT_STOBJ
) {
3964 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3967 g_assert (!c
->byval_arg
.byref
);
3968 if (MONO_TYPE_IS_REFERENCE (&c
->byval_arg
))
3969 mono_gc_wbarrier_generic_store (sp
[-2].data
.p
, sp
[-1].data
.p
);
3971 stackval_from_data (&c
->byval_arg
, sp
[-2].data
.p
, (char *) &sp
[-1].data
.p
, FALSE
);
3975 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
3976 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGUINT32_MAX
)
3977 THROW_EX (mono_get_exception_overflow (), ip
);
3978 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3981 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
3982 if (sp
[-1].data
.i
< 0)
3983 THROW_EX (mono_get_exception_overflow (), ip
);
3984 sp
[-1].data
.l
= sp
[-1].data
.i
;
3987 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
3988 if (sp
[-1].data
.l
< 0)
3989 THROW_EX (mono_get_exception_overflow (), ip
);
3992 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
3993 if ((guint64
) sp
[-1].data
.l
> MYGINT64_MAX
)
3994 THROW_EX (mono_get_exception_overflow (), ip
);
3997 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
3998 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
3999 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGINT64_MAX
)
4000 THROW_EX (mono_get_exception_overflow (), ip
);
4001 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4004 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
4005 if (sp
[-1].data
.f
< MYGINT64_MIN
|| sp
[-1].data
.f
> MYGINT64_MAX
)
4006 THROW_EX (mono_get_exception_overflow (), ip
);
4007 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4010 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
4011 if ((mono_u
)sp
[-1].data
.l
> MYGUINT32_MAX
)
4012 THROW_EX (mono_get_exception_overflow (), ip
);
4013 sp
[-1].data
.i
= (mono_u
)sp
[-1].data
.l
;
4016 MINT_IN_CASE(MINT_BOX
) {
4017 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4018 guint16 offset
= * (guint16
*)(ip
+ 2);
4019 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
4020 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
4022 if (mint_type (&c
->byval_arg
) == MINT_TYPE_VT
&& !c
->enumtype
&& !(mono_class_is_magic_int (c
) || mono_class_is_magic_float (c
))) {
4023 int size
= mono_class_value_size (c
, NULL
);
4024 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, sp
[-1 - offset
].data
.p
, error
);
4025 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4026 size
= (size
+ 7) & ~7;
4030 stackval_to_data (&c
->byval_arg
, &sp
[-1 - offset
], (char *) &sp
[-1 - offset
], FALSE
);
4031 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, &sp
[-1 - offset
], error
);
4032 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4037 MINT_IN_CASE(MINT_NEWARR
)
4038 sp
[-1].data
.p
= (MonoObject
*) mono_array_new_checked (rtm
->domain
, rtm
->data_items
[*(guint16
*)(ip
+ 1)], sp
[-1].data
.i
, error
);
4039 if (!mono_error_ok (error
)) {
4040 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4042 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4044 /*if (profiling_classes) {
4045 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
4047 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
4051 MINT_IN_CASE(MINT_LDLEN
)
4054 THROW_EX (mono_get_exception_null_reference (), ip
);
4055 sp
[-1].data
.nati
= mono_array_length ((MonoArray
*)o
);
4058 MINT_IN_CASE(MINT_GETCHR
) {
4062 THROW_EX (mono_get_exception_null_reference (), ip
);
4063 i32
= sp
[-1].data
.i
;
4064 if (i32
< 0 || i32
>= mono_string_length (s
))
4065 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4067 sp
[-1].data
.i
= mono_string_chars(s
)[i32
];
4071 MINT_IN_CASE(MINT_STRLEN
)
4075 THROW_EX (mono_get_exception_null_reference (), ip
);
4076 sp
[-1].data
.i
= mono_string_length ((MonoString
*) o
);
4078 MINT_IN_CASE(MINT_ARRAY_RANK
)
4081 THROW_EX (mono_get_exception_null_reference (), ip
);
4082 sp
[-1].data
.i
= mono_object_class (sp
[-1].data
.p
)->rank
;
4085 MINT_IN_CASE(MINT_LDELEMA
)
4086 MINT_IN_CASE(MINT_LDELEMA_TC
) {
4087 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
4089 MonoClass
*klass
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4090 guint16 numargs
= *(guint16
*) (ip
+ 2);
4095 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
4097 THROW_EX (frame
->ex
, ip
);
4102 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
4103 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
4104 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
4105 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
4106 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
4107 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
4108 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
4109 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
4110 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
4111 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
4112 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
4113 MINT_IN_CASE(MINT_LDELEM_VT
) {
4121 THROW_EX (mono_get_exception_null_reference (), ip
);
4123 aindex
= sp
[1].data
.i
;
4124 if (aindex
>= mono_array_length (o
))
4125 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4128 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4131 case MINT_LDELEM_I1
:
4132 sp
[0].data
.i
= mono_array_get (o
, gint8
, aindex
);
4134 case MINT_LDELEM_U1
:
4135 sp
[0].data
.i
= mono_array_get (o
, guint8
, aindex
);
4137 case MINT_LDELEM_I2
:
4138 sp
[0].data
.i
= mono_array_get (o
, gint16
, aindex
);
4140 case MINT_LDELEM_U2
:
4141 sp
[0].data
.i
= mono_array_get (o
, guint16
, aindex
);
4144 sp
[0].data
.nati
= mono_array_get (o
, mono_i
, aindex
);
4146 case MINT_LDELEM_I4
:
4147 sp
[0].data
.i
= mono_array_get (o
, gint32
, aindex
);
4149 case MINT_LDELEM_U4
:
4150 sp
[0].data
.i
= mono_array_get (o
, guint32
, aindex
);
4152 case MINT_LDELEM_I8
:
4153 sp
[0].data
.l
= mono_array_get (o
, guint64
, aindex
);
4155 case MINT_LDELEM_R4
:
4156 sp
[0].data
.f
= mono_array_get (o
, float, aindex
);
4158 case MINT_LDELEM_R8
:
4159 sp
[0].data
.f
= mono_array_get (o
, double, aindex
);
4161 case MINT_LDELEM_REF
:
4162 sp
[0].data
.p
= mono_array_get (o
, gpointer
, aindex
);
4164 case MINT_LDELEM_VT
: {
4165 MonoClass
*klass_vt
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4166 i32
= READ32 (ip
+ 2);
4167 char *src_addr
= mono_array_addr_with_size ((MonoArray
*) o
, i32
, aindex
);
4168 sp
[0].data
.vt
= vt_sp
;
4169 stackval_from_data (&klass_vt
->byval_arg
, sp
, src_addr
, FALSE
);
4170 vt_sp
+= (i32
+ 7) & ~7;
4182 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
4183 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
4184 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
4185 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
4186 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
4187 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
4188 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
4189 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
4190 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
4191 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
4192 MINT_IN_CASE(MINT_STELEM_VT
) {
4199 THROW_EX (mono_get_exception_null_reference (), ip
);
4201 aindex
= sp
[1].data
.i
;
4202 if (aindex
>= mono_array_length ((MonoArray
*)o
))
4203 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4207 mono_array_set ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
4209 case MINT_STELEM_I1
:
4210 mono_array_set ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
4212 case MINT_STELEM_U1
:
4213 mono_array_set ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
4215 case MINT_STELEM_I2
:
4216 mono_array_set ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
4218 case MINT_STELEM_U2
:
4219 mono_array_set ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
4221 case MINT_STELEM_I4
:
4222 mono_array_set ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
4224 case MINT_STELEM_I8
:
4225 mono_array_set ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
4227 case MINT_STELEM_R4
:
4228 mono_array_set ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f
);
4230 case MINT_STELEM_R8
:
4231 mono_array_set ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
4233 case MINT_STELEM_REF
: {
4234 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.p
, mono_object_class (o
)->element_class
, error
);
4235 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4236 if (sp
[2].data
.p
&& !isinst_obj
)
4237 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
4238 mono_array_setref ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
4241 case MINT_STELEM_VT
: {
4242 MonoClass
*klass_vt
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4243 i32
= READ32 (ip
+ 2);
4244 char *dst_addr
= mono_array_addr_with_size ((MonoArray
*) o
, i32
, aindex
);
4246 stackval_to_data (&klass_vt
->byval_arg
, &sp
[2], dst_addr
, FALSE
);
4247 vt_sp
-= (i32
+ 7) & ~7;
4258 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
4259 if (sp
[-1].data
.i
< 0)
4260 THROW_EX (mono_get_exception_overflow (), ip
);
4263 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
4264 if (sp
[-1].data
.l
< MYGINT32_MIN
|| sp
[-1].data
.l
> MYGINT32_MAX
)
4265 THROW_EX (mono_get_exception_overflow (), ip
);
4266 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4269 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
4270 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> MYGINT32_MAX
)
4271 THROW_EX (mono_get_exception_overflow (), ip
);
4272 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4275 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
4276 if (sp
[-1].data
.f
< MYGINT32_MIN
|| sp
[-1].data
.f
> MYGINT32_MAX
)
4277 THROW_EX (mono_get_exception_overflow (), ip
);
4278 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
4281 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
4282 if (sp
[-1].data
.i
< 0)
4283 THROW_EX (mono_get_exception_overflow (), ip
);
4286 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
4287 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> MYGUINT32_MAX
)
4288 THROW_EX (mono_get_exception_overflow (), ip
);
4289 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
4292 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
4293 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGUINT32_MAX
)
4294 THROW_EX (mono_get_exception_overflow (), ip
);
4295 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4298 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
4299 if (sp
[-1].data
.i
< -32768 || sp
[-1].data
.i
> 32767)
4300 THROW_EX (mono_get_exception_overflow (), ip
);
4303 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
4304 if (sp
[-1].data
.l
< -32768 || sp
[-1].data
.l
> 32767)
4305 THROW_EX (mono_get_exception_overflow (), ip
);
4306 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
4309 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
4310 if (sp
[-1].data
.f
< -32768 || sp
[-1].data
.f
> 32767)
4311 THROW_EX (mono_get_exception_overflow (), ip
);
4312 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
4315 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
4316 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> 65535)
4317 THROW_EX (mono_get_exception_overflow (), ip
);
4320 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
4321 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> 65535)
4322 THROW_EX (mono_get_exception_overflow (), ip
);
4323 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
4326 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
4327 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> 65535)
4328 THROW_EX (mono_get_exception_overflow (), ip
);
4329 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
4332 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
4333 if (sp
[-1].data
.i
< -128 || sp
[-1].data
.i
> 127)
4334 THROW_EX (mono_get_exception_overflow (), ip
);
4337 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
4338 if (sp
[-1].data
.l
< -128 || sp
[-1].data
.l
> 127)
4339 THROW_EX (mono_get_exception_overflow (), ip
);
4340 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
4343 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
4344 if (sp
[-1].data
.f
< -128 || sp
[-1].data
.f
> 127)
4345 THROW_EX (mono_get_exception_overflow (), ip
);
4346 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
4349 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
4350 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> 255)
4351 THROW_EX (mono_get_exception_overflow (), ip
);
4354 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
4355 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> 255)
4356 THROW_EX (mono_get_exception_overflow (), ip
);
4357 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
4360 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
4361 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> 255)
4362 THROW_EX (mono_get_exception_overflow (), ip
);
4363 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
4367 MINT_IN_CASE(MINT_LDELEM
)
4368 MINT_IN_CASE(MINT_STELEM
)
4369 MINT_IN_CASE(MINT_UNBOX_ANY
)
4371 MINT_IN_CASE(MINT_CKFINITE
)
4372 if (!isfinite(sp
[-1].data
.f
))
4373 THROW_EX (mono_get_exception_arithmetic (), ip
);
4376 MINT_IN_CASE(MINT_MKREFANY
) {
4377 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4379 /* The value address is on the stack */
4380 gpointer addr
= sp
[-1].data
.p
;
4381 /* Push the typedref value on the stack */
4382 sp
[-1].data
.p
= vt_sp
;
4383 vt_sp
+= sizeof (MonoTypedRef
);
4385 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4387 tref
->type
= &c
->byval_arg
;
4393 MINT_IN_CASE(MINT_REFANYTYPE
) {
4394 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4395 MonoType
*type
= tref
->type
;
4397 vt_sp
-= sizeof (MonoTypedRef
);
4398 sp
[-1].data
.p
= vt_sp
;
4400 *(gpointer
*)sp
[-1].data
.p
= type
;
4404 MINT_IN_CASE(MINT_REFANYVAL
) {
4405 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4406 gpointer addr
= tref
->value
;
4408 vt_sp
-= sizeof (MonoTypedRef
);
4410 sp
[-1].data
.p
= addr
;
4414 MINT_IN_CASE(MINT_LDTOKEN
)
4417 * (gpointer
*)sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4421 MINT_IN_CASE(MINT_ADD_OVF_I4
)
4422 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4423 THROW_EX (mono_get_exception_overflow (), ip
);
4426 MINT_IN_CASE(MINT_ADD_OVF_I8
)
4427 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4428 THROW_EX (mono_get_exception_overflow (), ip
);
4431 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
4432 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4433 THROW_EX (mono_get_exception_overflow (), ip
);
4434 BINOP_CAST(i
, +, guint32
);
4436 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
4437 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4438 THROW_EX (mono_get_exception_overflow (), ip
);
4439 BINOP_CAST(l
, +, guint64
);
4441 MINT_IN_CASE(MINT_MUL_OVF_I4
)
4442 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4443 THROW_EX (mono_get_exception_overflow (), ip
);
4446 MINT_IN_CASE(MINT_MUL_OVF_I8
)
4447 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4448 THROW_EX (mono_get_exception_overflow (), ip
);
4451 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
4452 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4453 THROW_EX (mono_get_exception_overflow (), ip
);
4454 BINOP_CAST(i
, *, guint32
);
4456 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
4457 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4458 THROW_EX (mono_get_exception_overflow (), ip
);
4459 BINOP_CAST(l
, *, guint64
);
4461 MINT_IN_CASE(MINT_SUB_OVF_I4
)
4462 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4463 THROW_EX (mono_get_exception_overflow (), ip
);
4466 MINT_IN_CASE(MINT_SUB_OVF_I8
)
4467 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4468 THROW_EX (mono_get_exception_overflow (), ip
);
4471 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
4472 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4473 THROW_EX (mono_get_exception_overflow (), ip
);
4474 BINOP_CAST(i
, -, guint32
);
4476 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
4477 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4478 THROW_EX (mono_get_exception_overflow (), ip
);
4479 BINOP_CAST(l
, -, guint64
);
4481 MINT_IN_CASE(MINT_START_ABORT_PROT
)
4482 mono_threads_begin_abort_protected_block ();
4485 MINT_IN_CASE(MINT_END_ABORT_PROT
)
4486 /* FIXME We miss it if exception is thrown in finally clause */
4487 mono_threads_end_abort_protected_block ();
4490 MINT_IN_CASE(MINT_ENDFINALLY
)
4492 int clause_index
= *ip
;
4493 if (clause_index
== exit_at_finally
)
4495 while (sp
> frame
->stack
) {
4499 ip
= finally_ips
->data
;
4500 finally_ips
= g_slist_remove (finally_ips
, ip
);
4507 MINT_IN_CASE(MINT_LEAVE
) /* Fall through */
4508 MINT_IN_CASE(MINT_LEAVE_S
)
4509 while (sp
> frame
->stack
) {
4514 if (*ip
== MINT_LEAVE_S
) {
4515 ip
+= (short) *(ip
+ 1);
4517 ip
+= (gint32
) READ32 (ip
+ 1);
4520 goto handle_finally
;
4522 MINT_IN_CASE(MINT_LEAVE_CHECK
)
4523 MINT_IN_CASE(MINT_LEAVE_S_CHECK
)
4524 while (sp
> frame
->stack
) {
4529 if (frame
->ex_handler
!= NULL
&& MONO_OFFSET_IN_HANDLER(frame
->ex_handler
, frame
->ip
- rtm
->code
)) {
4530 frame
->ex_handler
= NULL
;
4534 if (frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
4537 child_frame
.parent
= frame
;
4538 child_frame
.imethod
= NULL
;
4540 * We need for mono_thread_get_undeniable_exception to be able to unwind
4541 * to check the abort threshold. For this to work we use child_frame as a
4542 * dummy frame that is stored in the lmf and serves as the transition frame
4544 context
->current_frame
= &child_frame
;
4545 do_icall (context
, MINT_ICALL_V_P
, &tmp_sp
, mono_thread_get_undeniable_exception
);
4546 context
->current_frame
= frame
;
4548 MonoException
*abort_exc
= (MonoException
*)tmp_sp
.data
.p
;
4550 THROW_EX (abort_exc
, frame
->ip
);
4553 if (*ip
== MINT_LEAVE_S_CHECK
) {
4554 ip
+= (short) *(ip
+ 1);
4556 ip
+= (gint32
) READ32 (ip
+ 1);
4559 goto handle_finally
;
4561 MINT_IN_CASE(MINT_ICALL_V_V
)
4562 MINT_IN_CASE(MINT_ICALL_V_P
)
4563 MINT_IN_CASE(MINT_ICALL_P_V
)
4564 MINT_IN_CASE(MINT_ICALL_P_P
)
4565 MINT_IN_CASE(MINT_ICALL_PP_V
)
4566 MINT_IN_CASE(MINT_ICALL_PI_V
)
4567 MINT_IN_CASE(MINT_ICALL_PP_P
)
4568 MINT_IN_CASE(MINT_ICALL_PI_P
)
4569 MINT_IN_CASE(MINT_ICALL_PPP_V
)
4570 MINT_IN_CASE(MINT_ICALL_PPI_V
)
4571 MINT_IN_CASE(MINT_ICALL_PII_P
)
4572 MINT_IN_CASE(MINT_ICALL_PPII_V
)
4573 sp
= do_icall (context
, *ip
, sp
, rtm
->data_items
[*(guint16
*)(ip
+ 1)]);
4574 EXCEPTION_CHECKPOINT
;
4575 if (context
->has_resume_state
) {
4576 if (frame
== context
->handler_frame
)
4577 SET_RESUME_STATE (context
);
4583 MINT_IN_CASE(MINT_MONO_LDPTR
)
4584 sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4588 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
4589 sp
->data
.p
= mono_object_new_checked (rtm
->domain
, rtm
->data_items
[*(guint16
*)(ip
+ 1)], error
);
4590 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4594 MINT_IN_CASE(MINT_MONO_FREE
)
4597 g_error ("that doesn't seem right");
4598 g_free (sp
->data
.p
);
4600 MINT_IN_CASE(MINT_MONO_RETOBJ
)
4603 stackval_from_data (mono_method_signature (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
4604 mono_method_signature (frame
->imethod
->method
)->pinvoke
);
4605 if (sp
> frame
->stack
)
4606 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
4608 MINT_IN_CASE(MINT_MONO_TLS
) {
4609 MonoTlsKey key
= *(gint32
*)(ip
+ 1);
4610 sp
->data
.p
= ((gpointer (*)(void)) mono_tls_get_tls_getter (key
, FALSE
)) ();
4615 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
4617 mono_memory_barrier ();
4620 MINT_IN_CASE(MINT_MONO_JIT_ATTACH
) {
4623 context
->original_domain
= NULL
;
4624 MonoDomain
*tls_domain
= (MonoDomain
*) ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_DOMAIN
, FALSE
)) ();
4625 gpointer tls_jit
= ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_JIT_TLS
, FALSE
)) ();
4627 if (tls_domain
!= rtm
->domain
|| !tls_jit
)
4628 context
->original_domain
= mono_jit_thread_attach (rtm
->domain
);
4631 MINT_IN_CASE(MINT_MONO_JIT_DETACH
)
4633 mono_jit_set_domain (context
->original_domain
);
4635 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
4636 sp
->data
.p
= mono_domain_get ();
4640 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
4641 if (G_UNLIKELY (ss_enabled
)) {
4642 static void (*ss_tramp
) (void);
4645 void *tramp
= mini_get_single_step_trampoline ();
4646 mono_memory_barrier ();
4651 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
4652 * the address of that instruction is stored as the seq point address.
4657 * Use the same trampoline as the JIT. This ensures that
4658 * the debugger has the context for the last interpreter
4661 do_debugger_tramp (ss_tramp
, frame
);
4663 if (context
->has_resume_state
) {
4664 if (frame
== context
->handler_frame
)
4665 SET_RESUME_STATE (context
);
4672 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
4673 /* Just a placeholder for a breakpoint */
4676 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
4677 static void (*bp_tramp
) (void);
4679 void *tramp
= mini_get_breakpoint_trampoline ();
4680 mono_memory_barrier ();
4686 /* Use the same trampoline as the JIT */
4687 do_debugger_tramp (bp_tramp
, frame
);
4689 if (context
->has_resume_state
) {
4690 if (frame
== context
->handler_frame
)
4691 SET_RESUME_STATE (context
);
4700 #define RELOP(datamem, op) \
4702 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4705 #define RELOP_FP(datamem, op, noorder) \
4707 if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
4708 sp [-1].data.i = noorder; \
4710 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4713 MINT_IN_CASE(MINT_CEQ_I4
)
4716 MINT_IN_CASE(MINT_CEQ0_I4
)
4717 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
4720 MINT_IN_CASE(MINT_CEQ_I8
)
4723 MINT_IN_CASE(MINT_CEQ_R8
)
4726 MINT_IN_CASE(MINT_CNE_I4
)
4729 MINT_IN_CASE(MINT_CNE_I8
)
4732 MINT_IN_CASE(MINT_CNE_R8
)
4735 MINT_IN_CASE(MINT_CGT_I4
)
4738 MINT_IN_CASE(MINT_CGT_I8
)
4741 MINT_IN_CASE(MINT_CGT_R8
)
4744 MINT_IN_CASE(MINT_CGE_I4
)
4747 MINT_IN_CASE(MINT_CGE_I8
)
4750 MINT_IN_CASE(MINT_CGE_R8
)
4754 #define RELOP_CAST(datamem, op, type) \
4756 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4759 MINT_IN_CASE(MINT_CGE_UN_I4
)
4760 RELOP_CAST(l
, >=, guint32
);
4762 MINT_IN_CASE(MINT_CGE_UN_I8
)
4763 RELOP_CAST(l
, >=, guint64
);
4766 MINT_IN_CASE(MINT_CGT_UN_I4
)
4767 RELOP_CAST(i
, >, guint32
);
4769 MINT_IN_CASE(MINT_CGT_UN_I8
)
4770 RELOP_CAST(l
, >, guint64
);
4772 MINT_IN_CASE(MINT_CGT_UN_R8
)
4775 MINT_IN_CASE(MINT_CLT_I4
)
4778 MINT_IN_CASE(MINT_CLT_I8
)
4781 MINT_IN_CASE(MINT_CLT_R8
)
4784 MINT_IN_CASE(MINT_CLT_UN_I4
)
4785 RELOP_CAST(i
, <, guint32
);
4787 MINT_IN_CASE(MINT_CLT_UN_I8
)
4788 RELOP_CAST(l
, <, guint64
);
4790 MINT_IN_CASE(MINT_CLT_UN_R8
)
4793 MINT_IN_CASE(MINT_CLE_I4
)
4796 MINT_IN_CASE(MINT_CLE_I8
)
4799 MINT_IN_CASE(MINT_CLE_UN_I4
)
4800 RELOP_CAST(l
, <=, guint32
);
4802 MINT_IN_CASE(MINT_CLE_UN_I8
)
4803 RELOP_CAST(l
, <=, guint64
);
4805 MINT_IN_CASE(MINT_CLE_R8
)
4813 MINT_IN_CASE(MINT_LDFTN
) {
4814 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4819 MINT_IN_CASE(MINT_LDVIRTFTN
) {
4820 InterpMethod
*m
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4824 THROW_EX (mono_get_exception_null_reference (), ip
- 2);
4826 sp
->data
.p
= get_virtual_method (m
, sp
->data
.p
);
4831 #define LDARG(datamem, argtype) \
4832 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4836 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
4837 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
4838 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
4839 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
4840 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
4841 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
4842 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f
, float); MINT_IN_BREAK
;
4843 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
4844 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
4845 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
4847 MINT_IN_CASE(MINT_LDARG_VT
)
4849 i32
= READ32(ip
+ 2);
4850 memcpy(sp
->data
.p
, frame
->args
+ * (guint16
*)(ip
+ 1), i32
);
4851 vt_sp
+= (i32
+ 7) & ~7;
4856 #define STARG(datamem, argtype) \
4858 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4861 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
4862 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
4863 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
4864 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
4865 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
4866 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
4867 MINT_IN_CASE(MINT_STARG_R4
) STARG(f
, float); MINT_IN_BREAK
;
4868 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
4869 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
4870 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
4872 MINT_IN_CASE(MINT_STARG_VT
)
4873 i32
= READ32(ip
+ 2);
4875 memcpy(frame
->args
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
4876 vt_sp
-= (i32
+ 7) & ~7;
4880 #define STINARG(datamem, argtype) \
4882 int n = * (guint16 *)(ip + 1); \
4883 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4887 MINT_IN_CASE(MINT_STINARG_I1
) STINARG(i
, gint8
); MINT_IN_BREAK
;
4888 MINT_IN_CASE(MINT_STINARG_U1
) STINARG(i
, guint8
); MINT_IN_BREAK
;
4889 MINT_IN_CASE(MINT_STINARG_I2
) STINARG(i
, gint16
); MINT_IN_BREAK
;
4890 MINT_IN_CASE(MINT_STINARG_U2
) STINARG(i
, guint16
); MINT_IN_BREAK
;
4891 MINT_IN_CASE(MINT_STINARG_I4
) STINARG(i
, gint32
); MINT_IN_BREAK
;
4892 MINT_IN_CASE(MINT_STINARG_I8
) STINARG(l
, gint64
); MINT_IN_BREAK
;
4893 MINT_IN_CASE(MINT_STINARG_R4
) STINARG(f
, float); MINT_IN_BREAK
;
4894 MINT_IN_CASE(MINT_STINARG_R8
) STINARG(f
, double); MINT_IN_BREAK
;
4895 MINT_IN_CASE(MINT_STINARG_O
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
4896 MINT_IN_CASE(MINT_STINARG_P
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
4898 MINT_IN_CASE(MINT_STINARG_VT
) {
4899 int n
= * (guint16
*)(ip
+ 1);
4900 i32
= READ32(ip
+ 2);
4901 memcpy (frame
->args
+ rtm
->arg_offsets
[n
], frame
->stack_args
[n
].data
.p
, i32
);
4906 MINT_IN_CASE(MINT_PROF_ENTER
) {
4909 if (MONO_PROFILER_ENABLED (method_enter
)) {
4910 MonoProfilerCallContext
*prof_ctx
= NULL
;
4912 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
4913 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
4914 prof_ctx
->interp_frame
= frame
;
4915 prof_ctx
->method
= frame
->imethod
->method
;
4918 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
4926 MINT_IN_CASE(MINT_LDARGA
)
4927 sp
->data
.p
= frame
->args
+ * (guint16
*)(ip
+ 1);
4932 #define LDLOC(datamem, argtype) \
4933 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4937 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
4938 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
4939 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
4940 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
4941 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
4942 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
4943 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f
, float); MINT_IN_BREAK
;
4944 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
4945 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
4946 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
4948 MINT_IN_CASE(MINT_LDLOC_VT
)
4950 i32
= READ32(ip
+ 2);
4951 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
4952 vt_sp
+= (i32
+ 7) & ~7;
4957 MINT_IN_CASE(MINT_LDLOCA_S
)
4958 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
4963 #define STLOC(datamem, argtype) \
4965 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4968 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
4969 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
4970 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
4971 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
4972 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
4973 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
4974 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f
, float); MINT_IN_BREAK
;
4975 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
4976 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
4977 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
4979 #define STLOC_NP(datamem, argtype) \
4980 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4983 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
4984 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
4986 MINT_IN_CASE(MINT_STLOC_VT
)
4987 i32
= READ32(ip
+ 2);
4989 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
4990 vt_sp
-= (i32
+ 7) & ~7;
4994 MINT_IN_CASE(MINT_LOCALLOC
) {
4995 if (sp
!= frame
->stack
+ 1) /*FIX?*/
4996 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
4998 int len
= sp
[-1].data
.i
;
4999 sp
[-1].data
.p
= alloca (len
);
5001 if (frame
->imethod
->init_locals
)
5002 memset (sp
[-1].data
.p
, 0, len
);
5006 MINT_IN_CASE(MINT_ENDFILTER
)
5007 /* top of stack is result of filter */
5008 frame
->retval
= &sp
[-1];
5010 MINT_IN_CASE(MINT_INITOBJ
)
5012 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
5015 MINT_IN_CASE(MINT_CPBLK
)
5017 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
5018 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
5020 /* FIXME: value and size may be int64... */
5021 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
5024 MINT_IN_CASE(MINT_CONSTRAINED_
) {
5026 /* FIXME: implement */
5028 token
= READ32 (ip
);
5033 MINT_IN_CASE(MINT_INITBLK
)
5036 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
5038 /* FIXME: value and size may be int64... */
5039 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
5042 MINT_IN_CASE(MINT_NO_
)
5043 /* FIXME: implement */
5047 MINT_IN_CASE(MINT_RETHROW
) {
5049 * need to clarify what this should actually do:
5050 * start the search from the last found handler in
5051 * this method or continue in the caller or what.
5052 * Also, do we need to run finally/fault handlers after a retrow?
5053 * Well, this implementation will follow the usual search
5054 * for an handler, considering the current ip as throw spot.
5055 * We need to NULL frame->ex_handler for the later code to
5056 * actually run the new found handler.
5058 int exvar_offset
= *(guint16
*)(ip
+ 1);
5059 frame
->ex_handler
= NULL
;
5060 THROW_EX_GENERAL (*(MonoException
**)(frame
->locals
+ exvar_offset
), ip
- 1, TRUE
);
5064 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-rtm
->code
);
5065 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip
);
5069 g_assert_not_reached ();
5074 MonoExceptionClause
*clause
;
5075 GSList
*old_list
= finally_ips
;
5076 MonoMethod
*method
= frame
->imethod
->method
;
5080 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- rtm
->code
);
5082 if (rtm
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5083 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5086 ip_offset
= frame
->ip
- rtm
->code
;
5088 if (endfinally_ip
!= NULL
)
5089 finally_ips
= g_slist_prepend(finally_ips
, (void *)endfinally_ip
);
5090 for (i
= 0; i
< rtm
->num_clauses
; ++i
)
5091 if (frame
->ex_handler
== &rtm
->clauses
[i
])
5096 clause
= &rtm
->clauses
[i
];
5097 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- rtm
->code
)))) {
5098 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5099 ip
= rtm
->code
+ clause
->handler_offset
;
5100 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5103 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
5109 endfinally_ip
= NULL
;
5111 if (old_list
!= finally_ips
&& finally_ips
) {
5112 ip
= finally_ips
->data
;
5113 finally_ips
= g_slist_remove (finally_ips
, ip
);
5114 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5115 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
5120 * If an exception is set, we need to execute the fault handler, too,
5121 * otherwise, we continue normally.
5131 MonoExceptionClause
*clause
;
5132 GSList
*old_list
= finally_ips
;
5136 g_print ("* Handle fault\n");
5138 ip_offset
= frame
->ip
- rtm
->code
;
5140 for (i
= 0; i
< rtm
->num_clauses
; ++i
) {
5141 clause
= &rtm
->clauses
[i
];
5142 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
&& MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
)) {
5143 ip
= rtm
->code
+ clause
->handler_offset
;
5144 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5147 g_print ("* Executing handler at IL_%04x\n", clause
->handler_offset
);
5152 if (old_list
!= finally_ips
&& finally_ips
) {
5153 ip
= finally_ips
->data
;
5154 finally_ips
= g_slist_remove (finally_ips
, ip
);
5155 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5156 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
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
;
5186 /* make sure we don't miss to pop a LMF */
5187 MonoLMF
*lmf
= mono_get_lmf ();
5188 if (lmf
&& (gsize
) lmf
->previous_lmf
& 2) {
5189 MonoLMFExt
*ext
= (MonoLMFExt
*) lmf
;
5190 if (ext
->interp_exit
&& ext
->interp_exit_data
== frame
->parent
)
5191 interp_pop_lmf (ext
);
5198 memcpy (base_frame
->args
, frame
->args
, rtm
->alloca_size
);
5200 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
5201 frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
5202 MonoProfilerCallContext
*prof_ctx
= NULL
;
5204 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
5205 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
5206 prof_ctx
->interp_frame
= frame
;
5207 prof_ctx
->method
= frame
->imethod
->method
;
5209 MonoType
*rtype
= mono_method_signature (frame
->imethod
->method
)->ret
;
5211 switch (rtype
->type
) {
5212 case MONO_TYPE_VOID
:
5214 case MONO_TYPE_VALUETYPE
:
5215 prof_ctx
->return_value
= frame
->retval
->data
.p
;
5218 prof_ctx
->return_value
= frame
->retval
;
5223 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
5226 } else if (frame
->ex
&& frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
5227 MONO_PROFILER_RAISE (method_exception_leave
, (frame
->imethod
->method
, &frame
->ex
->object
));
5233 interp_exec_method (InterpFrame
*frame
, ThreadContext
*context
)
5235 interp_exec_method_full (frame
, context
, NULL
, NULL
, -1, NULL
);
5239 interp_parse_options (const char *options
)
5246 args
= g_strsplit (options
, ",", -1);
5247 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
5250 if (strncmp (arg
, "jit=", 4) == 0)
5251 jit_classes
= g_slist_prepend (jit_classes
, arg
+ 4);
5255 typedef int (*TestMethod
) (void);
5258 * interp_set_resume_state:
5260 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5263 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
5265 ThreadContext
*context
;
5268 context
= jit_tls
->interp_context
;
5271 context
->has_resume_state
= TRUE
;
5272 context
->handler_frame
= interp_frame
;
5273 /* This is on the stack, so it doesn't need a wbarrier */
5274 context
->handler_frame
->ex
= ex
;
5277 *(MonoException
**)(context
->handler_frame
->locals
+ ei
->exvar_offset
) = ex
;
5278 context
->handler_ip
= handler_ip
;
5282 * interp_run_finally:
5284 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5285 * frame->interp_frame.
5286 * Return TRUE if the finally clause threw an exception.
5289 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
)
5291 InterpFrame
*iframe
= frame
->interp_frame
;
5292 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
5294 interp_exec_method_full (iframe
, context
, handler_ip
, NULL
, clause_index
, NULL
);
5295 if (context
->has_resume_state
)
5302 * interp_run_filter:
5304 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
5305 * frame->interp_frame.
5308 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
)
5310 InterpFrame
*iframe
= frame
->interp_frame
;
5311 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
5312 InterpFrame child_frame
;
5316 * Have to run the clause in a new frame which is a copy of IFRAME, since
5317 * during debugging, there are two copies of the frame on the stack.
5319 memset (&child_frame
, 0, sizeof (InterpFrame
));
5320 child_frame
.imethod
= iframe
->imethod
;
5321 child_frame
.retval
= &retval
;
5322 child_frame
.parent
= iframe
;
5324 interp_exec_method_full (&child_frame
, context
, handler_ip
, ex
, clause_index
, iframe
);
5325 /* ENDFILTER stores the result into child_frame->retval */
5326 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
5330 InterpFrame
*current
;
5334 * interp_frame_iter_init:
5336 * Initialize an iterator for iterating through interpreted frames.
5339 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
5341 StackIter
*stack_iter
= (StackIter
*)iter
;
5343 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
5347 * interp_frame_iter_next:
5349 * Fill out FRAME with date for the next interpreter frame.
5352 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
5354 StackIter
*stack_iter
= (StackIter
*)iter
;
5355 InterpFrame
*iframe
= stack_iter
->current
;
5357 memset (frame
, 0, sizeof (StackFrameInfo
));
5358 /* pinvoke frames doesn't have imethod set */
5359 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
5360 iframe
= iframe
->parent
;
5364 frame
->type
= FRAME_TYPE_INTERP
;
5365 frame
->domain
= iframe
->domain
;
5366 frame
->interp_frame
= iframe
;
5367 frame
->method
= iframe
->imethod
->method
;
5368 frame
->actual_method
= frame
->method
;
5369 /* This is the offset in the interpreter IR */
5370 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
5371 frame
->ji
= iframe
->imethod
->jinfo
;
5372 frame
->managed
= TRUE
;
5373 frame
->frame_addr
= iframe
;
5375 stack_iter
->current
= iframe
->parent
;
5381 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
5385 rtm
= lookup_imethod (domain
, method
);
5393 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
5395 guint16
*code
= (guint16
*)ip
;
5396 g_assert (*code
== MINT_SDB_SEQ_POINT
);
5397 *code
= MINT_SDB_BREAKPOINT
;
5401 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
5403 guint16
*code
= (guint16
*)ip
;
5404 g_assert (*code
== MINT_SDB_BREAKPOINT
);
5405 *code
= MINT_SDB_SEQ_POINT
;
5409 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
5411 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5413 g_assert (iframe
->imethod
);
5414 return iframe
->imethod
->jinfo
;
5418 interp_frame_get_ip (MonoInterpFrameHandle frame
)
5420 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5422 g_assert (iframe
->imethod
);
5423 return (gpointer
)iframe
->ip
;
5427 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
5429 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5431 g_assert (iframe
->imethod
);
5433 int arg_offset
= iframe
->imethod
->arg_offsets
[pos
+ (iframe
->imethod
->hasthis
? 1 : 0)];
5435 return iframe
->args
+ arg_offset
;
5439 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
5441 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5443 g_assert (iframe
->imethod
);
5445 return iframe
->locals
+ iframe
->imethod
->local_offsets
[pos
];
5449 interp_frame_get_this (MonoInterpFrameHandle frame
)
5451 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5453 g_assert (iframe
->imethod
);
5454 g_assert (iframe
->imethod
->hasthis
);
5456 int arg_offset
= iframe
->imethod
->arg_offsets
[0];
5458 return iframe
->args
+ arg_offset
;
5461 static MonoInterpFrameHandle
5462 interp_frame_get_parent (MonoInterpFrameHandle frame
)
5464 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5466 return iframe
->parent
;
5470 interp_start_single_stepping (void)
5476 interp_stop_single_stepping (void)
5482 mono_ee_interp_init (const char *opts
)
5484 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
5485 g_assert (!interp_init_done
);
5486 interp_init_done
= TRUE
;
5488 mono_native_tls_alloc (&thread_context_id
, NULL
);
5491 interp_parse_options (opts
);
5492 mono_interp_transform_init ();
5495 c
.create_method_pointer
= interp_create_method_pointer
;
5496 c
.runtime_invoke
= interp_runtime_invoke
;
5497 c
.init_delegate
= interp_init_delegate
;
5498 c
.get_remoting_invoke
= interp_get_remoting_invoke
;
5499 c
.create_trampoline
= interp_create_trampoline
;
5500 c
.walk_stack_with_ctx
= interp_walk_stack_with_ctx
;
5501 c
.set_resume_state
= interp_set_resume_state
;
5502 c
.run_finally
= interp_run_finally
;
5503 c
.run_filter
= interp_run_filter
;
5504 c
.frame_iter_init
= interp_frame_iter_init
;
5505 c
.frame_iter_next
= interp_frame_iter_next
;
5506 c
.find_jit_info
= interp_find_jit_info
;
5507 c
.set_breakpoint
= interp_set_breakpoint
;
5508 c
.clear_breakpoint
= interp_clear_breakpoint
;
5509 c
.frame_get_jit_info
= interp_frame_get_jit_info
;
5510 c
.frame_get_ip
= interp_frame_get_ip
;
5511 c
.frame_get_arg
= interp_frame_get_arg
;
5512 c
.frame_get_local
= interp_frame_get_local
;
5513 c
.frame_get_this
= interp_frame_get_this
;
5514 c
.frame_get_parent
= interp_frame_get_parent
;
5515 c
.frame_arg_to_data
= interp_frame_arg_to_data
;
5516 c
.data_to_frame_arg
= interp_data_to_frame_arg
;
5517 c
.frame_arg_to_storage
= interp_frame_arg_to_storage
;
5518 c
.start_single_stepping
= interp_start_single_stepping
;
5519 c
.stop_single_stepping
= interp_stop_single_stepping
;
5520 mini_install_interp_callbacks (&c
);