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.
27 #include <mono/utils/gc_wrapper.h>
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
62 #include "interp-internals.h"
66 #include <mono/mini/mini.h>
67 #include <mono/mini/mini-runtime.h>
68 #include <mono/mini/aot-runtime.h>
69 #include <mono/mini/jit-icalls.h>
70 #include <mono/mini/debugger-agent.h>
71 #include <mono/mini/ee.h>
74 #include <mono/mini/mini-arm.h>
77 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
80 #define finite _finite
84 #define finite isfinite
89 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
91 frame
->parent
= parent_frame
;
92 frame
->stack_args
= method_args
;
93 frame
->retval
= method_retval
;
94 frame
->imethod
= rmethod
;
97 frame
->invoke_trap
= 0;
100 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
101 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
102 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
105 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL, NULL, -1, NULL)
108 * List of classes whose methods will be executed by transitioning to JITted code.
111 GSList
*mono_interp_jit_classes
;
112 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
113 static gboolean ss_enabled
;
115 static gboolean interp_init_done
= FALSE
;
117 static char* dump_frame (InterpFrame
*inv
);
118 static MonoArray
*get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
);
119 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, guint16
*start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
, InterpFrame
*base_frame
);
120 static InterpMethod
* lookup_method_pointer (gpointer addr
);
122 typedef void (*ICallMethod
) (InterpFrame
*frame
);
124 static MonoNativeTlsKey thread_context_id
;
126 static char* dump_args (InterpFrame
*inv
);
128 #define DEBUG_INTERP 0
131 int mono_interp_traceopt
= 2;
132 /* If true, then we output the opcodes as we interpret them */
133 static int global_tracing
= 2;
135 static int debug_indent_level
= 0;
137 static int break_on_method
= 0;
138 static int nested_trace
= 0;
139 static GList
*db_methods
= NULL
;
146 for (h
= 0; h
< debug_indent_level
; h
++)
151 db_match_method (gpointer data
, gpointer user_data
)
153 MonoMethod
*m
= (MonoMethod
*)user_data
;
154 MonoMethodDesc
*desc
= data
;
156 if (mono_method_desc_full_match (desc
, m
))
161 debug_enter (InterpFrame
*frame
, int *tracing
)
164 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
166 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
170 MonoMethod
*method
= frame
->imethod
->method
;
171 char *mn
, *args
= dump_args (frame
);
172 debug_indent_level
++;
174 mn
= mono_method_full_name (method
, FALSE
);
175 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
177 g_print ("%s)\n", args
);
183 #define DEBUG_LEAVE() \
186 args = dump_retval (frame); \
188 mn = mono_method_full_name (frame->imethod->method, FALSE); \
189 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
191 g_print (" => %s\n", args); \
193 debug_indent_level--; \
194 if (tracing == 3) global_tracing = 0; \
199 int mono_interp_traceopt
= 0;
200 static void debug_enter (InterpFrame
*frame
, int *tracing
)
203 #define DEBUG_LEAVE()
208 set_resume_state (ThreadContext
*context
, InterpFrame
*frame
)
211 context
->has_resume_state
= 0;
212 context
->handler_frame
= NULL
;
213 context
->handler_ei
= NULL
;
216 /* Set the current execution state to the resume state in context */
217 #define SET_RESUME_STATE(context) do { \
218 ip = (const guint16*)(context)->handler_ip; \
219 /* spec says stack should be empty at endfinally so it should be at the start too */ \
221 vt_sp = (unsigned char *) sp + rtm->stack_size; \
223 sp->data.p = frame->ex; \
226 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
227 while (finally_ips && \
228 finally_ips->data >= (context)->handler_ei->try_start && \
229 finally_ips->data < (context)->handler_ei->try_end) \
230 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
231 set_resume_state ((context), (frame)); \
236 set_context (ThreadContext
*context
)
238 MonoJitTlsData
*jit_tls
;
240 mono_native_tls_set_value (thread_context_id
, context
);
241 jit_tls
= mono_tls_get_jit_tls ();
243 /* jit_tls assumes ownership of 'context' */
244 jit_tls
->interp_context
= context
;
248 ves_real_abort (int line
, MonoMethod
*mh
,
249 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
252 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
253 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
254 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
255 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
256 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
257 mono_metadata_free_mh (header
);
260 #define ves_abort() \
262 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
263 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
267 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
270 MonoJitDomainInfo
*info
;
272 info
= domain_jit_info (domain
);
273 mono_domain_jit_code_hash_lock (domain
);
274 rtm
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
275 mono_domain_jit_code_hash_unlock (domain
);
280 interp_get_remoting_invoke (gpointer addr
, MonoError
*error
)
282 #ifndef DISABLE_REMOTING
283 InterpMethod
*imethod
= lookup_method_pointer (addr
);
286 g_assert (mono_use_interpreter
);
288 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
289 return_val_if_nok (error
, NULL
);
290 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
292 g_assert_not_reached ();
298 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
301 MonoJitDomainInfo
*info
;
302 MonoMethodSignature
*sig
;
307 info
= domain_jit_info (domain
);
308 mono_domain_jit_code_hash_lock (domain
);
309 rtm
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
310 mono_domain_jit_code_hash_unlock (domain
);
314 sig
= mono_method_signature (method
);
316 rtm
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
317 rtm
->method
= method
;
318 rtm
->domain
= domain
;
319 rtm
->param_count
= sig
->param_count
;
320 rtm
->hasthis
= sig
->hasthis
;
321 rtm
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
322 rtm
->rtype
= mini_get_underlying_type (sig
->ret
);
323 rtm
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
324 for (i
= 0; i
< sig
->param_count
; ++i
)
325 rtm
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
327 mono_domain_jit_code_hash_lock (domain
);
328 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
329 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, rtm
);
330 mono_domain_jit_code_hash_unlock (domain
);
332 rtm
->prof_flags
= mono_profiler_get_call_instrumentation_flags (rtm
->method
);
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
= m_class_get_vtable (mono_object_class (obj
)) [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
, void *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 (m_class_is_enumtype (type
->data
.klass
)) {
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 (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
510 g_error ("got type 0x%02x", type
->type
);
515 stackval_to_data (MonoType
*type_
, stackval
*val
, void *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 memmove (data
, &val
->data
.l
, sizeof (gint64
));
570 float tmp
= (float)val
->data
.f
;
571 /* memmove handles unaligned case */
572 memmove (data
, &tmp
, sizeof (float));
576 memmove (data
, &val
->data
.f
, sizeof (double));
579 case MONO_TYPE_STRING
:
580 case MONO_TYPE_SZARRAY
:
581 case MONO_TYPE_CLASS
:
582 case MONO_TYPE_OBJECT
:
583 case MONO_TYPE_ARRAY
: {
584 gpointer
*p
= (gpointer
*) data
;
585 mono_gc_wbarrier_generic_store (p
, val
->data
.o
);
588 case MONO_TYPE_PTR
: {
589 gpointer
*p
= (gpointer
*) data
;
593 case MONO_TYPE_VALUETYPE
:
594 if (m_class_is_enumtype (type
->data
.klass
)) {
595 stackval_to_data (mono_class_enum_basetype (type
->data
.klass
), val
, data
, pinvoke
);
597 } else if (pinvoke
) {
598 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
600 mono_value_copy (data
, val
->data
.vt
, type
->data
.klass
);
603 case MONO_TYPE_GENERICINST
: {
604 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
606 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
607 mono_value_copy (data
, val
->data
.vt
, mono_class_from_mono_type (type
));
610 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
614 g_error ("got type %x", type
->type
);
619 * Same as stackval_to_data but return address of storage instead
620 * of copying the value.
623 stackval_to_data_addr (MonoType
*type_
, stackval
*val
)
625 MonoType
*type
= mini_native_type_replace_type (type_
);
629 switch (type
->type
) {
632 case MONO_TYPE_BOOLEAN
:
641 return &val
->data
.nati
;
648 case MONO_TYPE_STRING
:
649 case MONO_TYPE_SZARRAY
:
650 case MONO_TYPE_CLASS
:
651 case MONO_TYPE_OBJECT
:
652 case MONO_TYPE_ARRAY
:
655 case MONO_TYPE_VALUETYPE
:
656 if (m_class_is_enumtype (type
->data
.klass
))
657 return stackval_to_data_addr (mono_class_enum_basetype (type
->data
.klass
), val
);
660 case MONO_TYPE_TYPEDBYREF
:
662 case MONO_TYPE_GENERICINST
: {
663 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
665 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
667 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
670 g_error ("got type %x", type
->type
);
676 * Throw an exception from the interpreter.
678 static MONO_NEVER_INLINE
void
679 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, gconstpointer ip
, gboolean rethrow
)
684 interp_push_lmf (&ext
, frame
);
685 frame
->ip
= (const guint16
*)ip
;
688 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
689 MonoException
*mono_ex
= (MonoException
*) ex
;
691 mono_ex
->stack_trace
= NULL
;
692 mono_ex
->trace_ips
= NULL
;
695 mono_error_assert_ok (error
);
698 memset (&ctx
, 0, sizeof (MonoContext
));
699 MONO_CONTEXT_SET_SP (&ctx
, frame
);
702 * Call the JIT EH code. The EH code will call back to us using:
703 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
704 * Since ctx.ip is 0, this will start unwinding from the LMF frame
705 * pushed above, which points to our frames.
707 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
708 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
709 /* We need to unwind into non-interpreter code */
710 mono_restore_context (&ctx
);
711 g_assert_not_reached ();
714 interp_pop_lmf (&ext
);
716 g_assert (context
->has_resume_state
);
720 fill_in_trace (MonoException
*exception
, InterpFrame
*frame
)
723 char *stack_trace
= dump_frame (frame
);
724 MonoDomain
*domain
= frame
->imethod
->domain
;
725 (exception
)->stack_trace
= mono_string_new_checked (domain
, stack_trace
, error
);
726 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
727 (exception
)->trace_ips
= get_trace_ips (domain
, frame
);
728 g_free (stack_trace
);
731 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
733 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
735 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
736 if (frame == context->handler_frame) \
737 SET_RESUME_STATE (context); \
742 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
745 * Its possible for child_frame.ex to contain an unthrown exception, if the transform phase
748 #define CHECK_CHILD_EX(child_frame, ip) do { \
749 if ((child_frame).ex) \
750 THROW_EX ((child_frame).ex, (ip)); \
753 #define EXCEPTION_CHECKPOINT \
755 if (*mono_thread_interruption_request_flag ()) { \
756 MonoException *exc = mono_thread_interruption_checkpoint (); \
758 THROW_EX (exc, ip); \
764 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
767 intptr_t *lower_bounds
;
771 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
772 for (i
= 0; i
< param_count
; ++i
) {
773 lengths
[i
] = values
->data
.i
;
776 if (m_class_get_rank (klass
) == param_count
) {
777 /* Only lengths provided. */
780 /* lower bounds are first. */
781 lower_bounds
= (intptr_t *) lengths
;
782 lengths
+= m_class_get_rank (klass
);
784 obj
= (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
789 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
791 g_assert (!frame
->ex
);
792 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
796 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
797 guint32 idx
= sp
[i
].data
.i
;
798 guint32 lower
= ao
->bounds
[i
].lower_bound
;
799 guint32 len
= ao
->bounds
[i
].length
;
800 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
801 frame
->ex
= mono_get_exception_index_out_of_range ();
802 FILL_IN_TRACE (frame
->ex
, frame
);
805 pos
= (pos
* len
) + idx
- lower
;
809 if (safe
&& pos
>= ao
->max_length
) {
810 frame
->ex
= mono_get_exception_index_out_of_range ();
811 FILL_IN_TRACE (frame
->ex
, frame
);
819 ves_array_set (InterpFrame
*frame
, stackval
*sp
, MonoMethodSignature
*sig
)
821 MonoObject
*o
= sp
->data
.o
;
822 MonoArray
*ao
= (MonoArray
*) o
;
823 MonoClass
*ac
= o
->vtable
->klass
;
825 g_assert (m_class_get_rank (ac
) >= 1);
827 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, TRUE
);
831 int val_index
= 1 + m_class_get_rank (ac
);
832 if (sp
[val_index
].data
.p
&& !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o
)))) {
834 MonoObject
*isinst
= mono_object_isinst_checked (sp
[val_index
].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
835 mono_error_cleanup (error
);
837 frame
->ex
= mono_get_exception_array_type_mismatch ();
838 FILL_IN_TRACE (frame
->ex
, frame
);
843 gint32 esize
= mono_array_element_size (ac
);
844 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
846 MonoType
*mt
= sig
->params
[m_class_get_rank (ac
)];
847 stackval_to_data (mt
, &sp
[val_index
], ea
, FALSE
);
851 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
853 MonoObject
*o
= sp
->data
.o
;
854 MonoArray
*ao
= (MonoArray
*) o
;
855 MonoClass
*ac
= o
->vtable
->klass
;
857 g_assert (m_class_get_rank (ac
) >= 1);
859 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, safe
);
863 gint32 esize
= mono_array_element_size (ac
);
864 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
866 MonoType
*mt
= sig
->ret
;
867 stackval_from_data (mt
, retval
, ea
, FALSE
);
871 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
873 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
875 g_assert (m_class_get_rank (ac
) >= 1);
877 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
881 if (needs_typecheck
&& !mono_class_is_assignable_from (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), m_class_get_element_class (required_type
))) {
882 frame
->ex
= mono_get_exception_array_type_mismatch ();
883 FILL_IN_TRACE (frame
->ex
, frame
);
886 gint32 esize
= mono_array_element_size (ac
);
887 return mono_array_addr_with_size_fast (ao
, esize
, pos
);
890 static MonoPIFunc mono_interp_to_native_trampoline
= NULL
;
892 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
893 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
896 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
897 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
899 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
902 g_assert (mono_arm_eabi_supported ());
903 int i8_align
= mono_arm_i8_align ();
913 for (int i
= 0; i
< sig
->param_count
; i
++) {
914 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
916 case MONO_TYPE_BOOLEAN
:
927 case MONO_TYPE_SZARRAY
:
928 case MONO_TYPE_CLASS
:
929 case MONO_TYPE_OBJECT
:
930 case MONO_TYPE_STRING
:
931 case MONO_TYPE_VALUETYPE
:
932 case MONO_TYPE_GENERICINST
:
933 #if SIZEOF_VOID_P == 8
939 #if SIZEOF_VOID_P == 4
943 /* pairs begin at even registers */
944 if (i8_align
== 8 && margs
->ilen
& 1)
951 #if SIZEOF_VOID_P == 8
956 #if SIZEOF_VOID_P == 4
962 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
967 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
970 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
972 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
973 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
975 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
976 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
983 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
987 for (int i
= 0; i
< sig
->param_count
; i
++) {
988 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
990 case MONO_TYPE_BOOLEAN
:
1001 case MONO_TYPE_SZARRAY
:
1002 case MONO_TYPE_CLASS
:
1003 case MONO_TYPE_OBJECT
:
1004 case MONO_TYPE_STRING
:
1005 case MONO_TYPE_VALUETYPE
:
1006 case MONO_TYPE_GENERICINST
:
1007 #if SIZEOF_VOID_P == 8
1011 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1013 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1017 #if SIZEOF_VOID_P == 4
1019 case MONO_TYPE_U8
: {
1020 stackval
*sarg
= &frame
->stack_args
[i
];
1022 /* pairs begin at even registers */
1023 if (i8_align
== 8 && int_i
& 1)
1026 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1028 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1030 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
);
1038 if (ptype
== MONO_TYPE_R4
)
1039 * (float *) &(margs
->fargs
[int_f
]) = (float) frame
->stack_args
[i
].data
.f
;
1041 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1043 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
);
1045 #if SIZEOF_VOID_P == 4
1052 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1056 switch (sig
->ret
->type
) {
1057 case MONO_TYPE_BOOLEAN
:
1058 case MONO_TYPE_CHAR
:
1068 case MONO_TYPE_SZARRAY
:
1069 case MONO_TYPE_CLASS
:
1070 case MONO_TYPE_OBJECT
:
1071 case MONO_TYPE_STRING
:
1074 case MONO_TYPE_VALUETYPE
:
1075 case MONO_TYPE_GENERICINST
:
1076 margs
->retval
= &(frame
->retval
->data
.p
);
1077 margs
->is_float_ret
= 0;
1081 margs
->retval
= &(frame
->retval
->data
.p
);
1082 margs
->is_float_ret
= 1;
1084 case MONO_TYPE_VOID
:
1085 margs
->retval
= NULL
;
1088 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1096 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1098 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1101 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1103 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1107 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1109 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1112 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1113 else if (sig
->hasthis
&& index
== 0)
1114 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1116 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1120 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1122 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1125 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1127 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1131 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1133 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1134 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1135 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1137 switch (type
->type
) {
1138 case MONO_TYPE_GENERICINST
:
1139 if (!MONO_TYPE_IS_REFERENCE (type
))
1140 val
->data
.vt
= storage
;
1142 case MONO_TYPE_VALUETYPE
:
1143 val
->data
.vt
= storage
;
1146 g_assert_not_reached ();
1150 static MONO_NEVER_INLINE
void
1151 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
)
1157 g_assert (!frame
->imethod
);
1158 if (!mono_interp_to_native_trampoline
) {
1159 if (mono_ee_features
.use_aot_trampolines
) {
1160 mono_interp_to_native_trampoline
= (MonoPIFunc
)mono_aot_get_trampoline ("interp_to_native_trampoline");
1162 MonoTrampInfo
*info
;
1163 mono_interp_to_native_trampoline
= (MonoPIFunc
)mono_arch_get_interp_to_native_trampoline (&info
);
1165 // mono_tramp_info_register (info, NULL);
1168 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1169 CallContext ccontext
;
1170 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1172 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1176 g_print ("ICALL: mono_interp_to_native_trampoline = %p, addr = %p\n", mono_interp_to_native_trampoline
, addr
);
1179 context
->current_frame
= frame
;
1181 interp_push_lmf (&ext
, frame
);
1182 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1183 mono_interp_to_native_trampoline (addr
, &ccontext
);
1185 mono_interp_to_native_trampoline (addr
, margs
);
1187 interp_pop_lmf (&ext
);
1189 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1191 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1193 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1194 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1196 g_free (margs
->iargs
);
1197 g_free (margs
->fargs
);
1203 * interp_init_delegate:
1205 * Initialize del->interp_method.
1208 interp_init_delegate (MonoDelegate
*del
)
1213 if (del
->interp_method
) {
1214 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1215 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1216 } else if (del
->method
) {
1217 /* Delegate created dynamically */
1218 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1220 /* Created from JITted code */
1221 g_assert (del
->method_ptr
);
1222 del
->interp_method
= lookup_method_pointer (del
->method_ptr
);
1223 g_assert (del
->interp_method
);
1226 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1229 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1230 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1231 mono_class_is_abstract (method
->klass
))
1232 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
);
1234 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1235 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1236 const char *name
= method
->name
;
1237 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1239 * When invoking the delegate interp_method is executed directly. If it's an
1240 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1242 * FIXME We should do this later, when we also know the delegate on which the
1243 * target method is called.
1245 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1246 mono_error_assert_ok (error
);
1252 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1255 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1257 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1259 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1260 MonoMethod
*invoke
= mono_get_delegate_invoke (mono_handle_class (this_obj
));
1261 /* virtual invoke delegates must not have null check */
1262 if (mono_method_signature (imethod
->method
)->param_count
== mono_method_signature (invoke
)->param_count
1263 && MONO_HANDLE_IS_NULL (target
)) {
1264 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1269 g_assert (imethod
->method
);
1270 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1271 return_if_nok (error
);
1273 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1275 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1280 * runtime specifies that the implementation of the method is automatically
1281 * provided by the runtime and is primarily used for the methods of delegates.
1283 static MONO_NEVER_INLINE
void
1284 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1286 const char *name
= method
->name
;
1287 mono_class_init (method
->klass
);
1289 if (method
->klass
== mono_defaults
.array_class
) {
1290 if (!strcmp (name
, "UnsafeMov")) {
1291 /* TODO: layout checks */
1292 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1295 if (!strcmp (name
, "UnsafeLoad")) {
1296 ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1299 } else if (mini_class_is_system_array (method
->klass
)) {
1300 MonoObject
*obj
= (MonoObject
*) sp
->data
.p
;
1302 frame
->ex
= mono_get_exception_null_reference ();
1303 FILL_IN_TRACE (frame
->ex
, frame
);
1306 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1307 ves_array_set (frame
, sp
, sig
);
1310 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1311 ves_array_get (frame
, sp
, retval
, sig
, TRUE
);
1316 g_error ("Don't know how to exec runtime method %s.%s::%s",
1317 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1323 dump_stack (stackval
*stack
, stackval
*sp
)
1325 stackval
*s
= stack
;
1326 GString
*str
= g_string_new ("");
1329 return g_string_free (str
, FALSE
);
1332 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1335 return g_string_free (str
, FALSE
);
1340 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1342 switch (type
->type
) {
1349 case MONO_TYPE_CHAR
:
1350 case MONO_TYPE_BOOLEAN
:
1351 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1353 case MONO_TYPE_STRING
:
1354 case MONO_TYPE_SZARRAY
:
1355 case MONO_TYPE_CLASS
:
1356 case MONO_TYPE_OBJECT
:
1357 case MONO_TYPE_ARRAY
:
1361 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1363 case MONO_TYPE_VALUETYPE
:
1364 if (m_class_is_enumtype (type
->data
.klass
))
1365 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1367 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1371 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1376 GString
*res
= g_string_new ("");
1377 mono_type_get_desc (res
, type
, TRUE
);
1378 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1379 g_string_free (res
, TRUE
);
1387 dump_retval (InterpFrame
*inv
)
1389 GString
*str
= g_string_new ("");
1390 MonoType
*ret
= mono_method_signature (inv
->imethod
->method
)->ret
;
1392 if (ret
->type
!= MONO_TYPE_VOID
)
1393 dump_stackval (str
, inv
->retval
, ret
);
1395 return g_string_free (str
, FALSE
);
1400 dump_args (InterpFrame
*inv
)
1402 GString
*str
= g_string_new ("");
1404 MonoMethodSignature
*signature
= mono_method_signature (inv
->imethod
->method
);
1406 if (signature
->param_count
== 0 && !signature
->hasthis
)
1407 return g_string_free (str
, FALSE
);
1409 if (signature
->hasthis
) {
1410 MonoMethod
*method
= inv
->imethod
->method
;
1411 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1414 for (i
= 0; i
< signature
->param_count
; ++i
)
1415 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1417 return g_string_free (str
, FALSE
);
1421 dump_frame (InterpFrame
*inv
)
1423 GString
*str
= g_string_new ("");
1428 for (i
= 0; inv
; inv
= inv
->parent
) {
1429 if (inv
->imethod
!= NULL
) {
1430 MonoMethod
*method
= inv
->imethod
->method
;
1434 const char * opname
= "";
1436 gchar
*source
= NULL
;
1440 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1441 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) == 0) {
1442 MonoMethodHeader
*hd
= mono_method_get_header_checked (method
, error
);
1443 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
1447 opname
= mono_interp_opname
[*inv
->ip
];
1448 codep
= inv
->ip
- inv
->imethod
->code
;
1449 source
= g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method
->name
, codep
);
1454 MonoDebugSourceLocation
*minfo
= mono_debug_lookup_method (method
);
1455 source
= mono_debug_method_lookup_location (minfo
, codep
);
1457 mono_metadata_free_mh (hd
);
1460 args
= dump_args (inv
);
1461 name
= mono_method_full_name (method
, TRUE
);
1463 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i
, codep
, opname
, name
, args
, source
);
1465 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s)\n", i
, codep
, opname
, name
, args
);
1472 return g_string_free (str
, FALSE
);
1476 get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
)
1483 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1484 if (inv
->imethod
!= NULL
)
1487 res
= mono_array_new_checked (domain
, mono_defaults
.int_class
, 3 * i
, error
);
1488 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
1490 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1491 if (inv
->imethod
!= NULL
) {
1492 mono_array_set_fast (res
, gpointer
, i
, inv
->imethod
);
1494 mono_array_set_fast (res
, gpointer
, i
, (gpointer
)inv
->ip
);
1496 mono_array_set_fast (res
, gpointer
, i
, NULL
);
1503 #define CHECK_ADD_OVERFLOW(a,b) \
1504 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1505 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1507 #define CHECK_SUB_OVERFLOW(a,b) \
1508 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1509 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1511 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1512 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1514 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1515 (guint32)(a) < (guint32)(b) ? -1 : 0
1517 #define CHECK_ADD_OVERFLOW64(a,b) \
1518 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1519 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1521 #define CHECK_SUB_OVERFLOW64(a,b) \
1522 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1523 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1525 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1526 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1528 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1529 (guint64)(a) < (guint64)(b) ? -1 : 0
1531 #if SIZEOF_VOID_P == 4
1532 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1533 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1535 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1536 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1539 /* Resolves to TRUE if the operands would overflow */
1540 #define CHECK_MUL_OVERFLOW(a,b) \
1541 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1542 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1543 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1544 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1545 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1546 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1547 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1549 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1550 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1551 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1553 #define CHECK_MUL_OVERFLOW64(a,b) \
1554 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1555 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1556 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1557 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1558 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1559 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1560 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1562 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1563 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1564 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1566 #if SIZEOF_VOID_P == 4
1567 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1568 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1570 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1571 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1575 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1577 InterpFrame frame
, *old_frame
;
1578 ThreadContext
*context
= (ThreadContext
*)mono_native_tls_get_value (thread_context_id
);
1579 MonoMethodSignature
*sig
= mono_method_signature (method
);
1580 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
1582 MonoMethod
*target_method
= method
;
1590 if (context
== NULL
) {
1591 context
= g_new0 (ThreadContext
, 1);
1592 set_context (context
);
1594 old_frame
= context
->current_frame
;
1596 MonoDomain
*domain
= mono_domain_get ();
1598 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1599 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1600 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1602 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1604 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1608 args
[0].data
.p
= obj
;
1610 args
[0].data
.p
= NULL
;
1611 args
[1].data
.p
= params
;
1612 args
[2].data
.p
= exc
;
1613 args
[3].data
.p
= target_method
;
1615 INIT_FRAME (&frame
, NULL
, args
, &result
, domain
, invoke_wrapper
, error
);
1618 frame
.invoke_trap
= 1;
1620 interp_exec_method (&frame
, context
);
1622 context
->current_frame
= old_frame
;
1626 *exc
= (MonoObject
*) frame
.ex
;
1629 mono_error_set_exception_instance (error
, frame
.ex
);
1632 return (MonoObject
*)result
.data
.p
;
1636 InterpMethod
*rmethod
;
1640 gpointer
*many_args
;
1643 /* Main function for entering the interpreter from compiled code */
1645 interp_entry (InterpEntryData
*data
)
1648 InterpMethod
*rmethod
= data
->rmethod
;
1649 ThreadContext
*context
= (ThreadContext
*)mono_native_tls_get_value (thread_context_id
);
1650 InterpFrame
*old_frame
;
1654 MonoMethodSignature
*sig
;
1658 method
= rmethod
->method
;
1659 sig
= mono_method_signature (method
);
1661 // FIXME: Optimize this
1663 //printf ("%s\n", mono_method_full_name (method, 1));
1666 if (context
== NULL
) {
1667 context
= g_new0 (ThreadContext
, 1);
1668 set_context (context
);
1670 old_frame
= context
->current_frame
;
1672 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1674 args
[0].data
.p
= data
->this_arg
;
1677 if (data
->many_args
)
1678 params
= data
->many_args
;
1680 params
= data
->args
;
1681 for (i
= 0; i
< sig
->param_count
; ++i
) {
1682 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1683 if (sig
->params
[i
]->byref
) {
1684 args
[a_index
].data
.p
= params
[i
];
1687 type
= rmethod
->param_types
[i
];
1688 switch (type
->type
) {
1689 case MONO_TYPE_VALUETYPE
:
1690 args
[a_index
].data
.p
= params
[i
];
1692 case MONO_TYPE_GENERICINST
:
1693 if (MONO_TYPE_IS_REFERENCE (type
))
1694 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1696 args
[a_index
].data
.vt
= params
[i
];
1699 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1704 memset (&result
, 0, sizeof (result
));
1705 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1707 type
= rmethod
->rtype
;
1708 switch (type
->type
) {
1709 case MONO_TYPE_GENERICINST
:
1710 if (!MONO_TYPE_IS_REFERENCE (type
))
1711 frame
.retval
->data
.vt
= data
->res
;
1713 case MONO_TYPE_VALUETYPE
:
1714 frame
.retval
->data
.vt
= data
->res
;
1720 interp_exec_method (&frame
, context
);
1721 context
->current_frame
= old_frame
;
1724 g_assert (frame
.ex
== NULL
);
1726 type
= rmethod
->rtype
;
1727 switch (type
->type
) {
1728 case MONO_TYPE_VOID
:
1730 case MONO_TYPE_OBJECT
:
1731 /* No need for a write barrier */
1732 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1734 case MONO_TYPE_GENERICINST
:
1735 if (MONO_TYPE_IS_REFERENCE (type
)) {
1736 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1738 /* Already set before the call */
1741 case MONO_TYPE_VALUETYPE
:
1742 /* Already set before the call */
1745 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1750 static MONO_NEVER_INLINE stackval
*
1751 do_icall (ThreadContext
*context
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
)
1754 interp_push_lmf (&ext
, context
->current_frame
);
1757 case MINT_ICALL_V_V
: {
1758 typedef void (*T
)(void);
1763 case MINT_ICALL_V_P
: {
1764 typedef gpointer (*T
)(void);
1767 sp
[-1].data
.p
= func ();
1770 case MINT_ICALL_P_V
: {
1771 typedef void (*T
)(gpointer
);
1773 func (sp
[-1].data
.p
);
1777 case MINT_ICALL_P_P
: {
1778 typedef gpointer (*T
)(gpointer
);
1780 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1783 case MINT_ICALL_PP_V
: {
1784 typedef void (*T
)(gpointer
,gpointer
);
1787 func (sp
[0].data
.p
, sp
[1].data
.p
);
1790 case MINT_ICALL_PP_P
: {
1791 typedef gpointer (*T
)(gpointer
,gpointer
);
1794 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1797 case MINT_ICALL_PPP_V
: {
1798 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
1801 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1804 case MINT_ICALL_PPP_P
: {
1805 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
1808 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
1811 case MINT_ICALL_PPPP_V
: {
1812 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1815 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1818 case MINT_ICALL_PPPP_P
: {
1819 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1822 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1825 case MINT_ICALL_PPPPP_V
: {
1826 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1829 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
1832 case MINT_ICALL_PPPPP_P
: {
1833 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1836 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1839 case MINT_ICALL_PPPPPP_V
: {
1840 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1843 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
, sp
[5].data
.p
);
1846 case MINT_ICALL_PPPPPP_P
: {
1847 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1850 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
1854 g_assert_not_reached ();
1857 /* convert the native representation to the stackval representation */
1859 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
1861 interp_pop_lmf (&ext
);
1865 static MONO_NEVER_INLINE stackval
*
1866 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
1868 MonoMethodSignature
*sig
;
1869 MonoFtnDesc ftndesc
;
1870 guint8 res_buf
[256];
1874 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
1877 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1878 * by ref and return a return value using an explicit return value argument.
1880 if (!rmethod
->jit_wrapper
) {
1881 MonoMethod
*method
= rmethod
->method
;
1883 sig
= mono_method_signature (method
);
1886 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
1887 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1889 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
1890 mono_error_assert_ok (error
);
1892 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
1893 return_val_if_nok (error
, NULL
);
1896 rmethod
->jit_addr
= addr
;
1897 rmethod
->jit_sig
= sig
;
1898 mono_memory_barrier ();
1899 rmethod
->jit_wrapper
= jit_wrapper
;
1902 sig
= rmethod
->jit_sig
;
1905 sp
-= sig
->param_count
;
1909 ftndesc
.addr
= rmethod
->jit_addr
;
1912 // FIXME: Optimize this
1916 int stack_index
= 0;
1917 if (rmethod
->hasthis
) {
1918 args
[pindex
++] = sp
[0].data
.p
;
1921 type
= rmethod
->rtype
;
1922 if (type
->type
!= MONO_TYPE_VOID
) {
1923 if (MONO_TYPE_ISSTRUCT (type
))
1924 args
[pindex
++] = vt_sp
;
1926 args
[pindex
++] = res_buf
;
1928 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
1929 MonoType
*t
= rmethod
->param_types
[i
];
1930 stackval
*sval
= &sp
[stack_index
+ i
];
1931 if (sig
->params
[i
]->byref
) {
1932 args
[pindex
++] = sval
->data
.p
;
1933 } else if (MONO_TYPE_ISSTRUCT (t
)) {
1934 args
[pindex
++] = sval
->data
.p
;
1935 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
1936 args
[pindex
++] = &sval
->data
.p
;
1945 case MONO_TYPE_VALUETYPE
:
1946 args
[pindex
++] = &sval
->data
.i
;
1949 case MONO_TYPE_FNPTR
:
1952 case MONO_TYPE_OBJECT
:
1953 args
[pindex
++] = &sval
->data
.p
;
1957 args
[pindex
++] = &sval
->data
.l
;
1959 case MONO_TYPE_R4
: {
1960 float tmp
= (float)sval
->data
.f
;
1961 sval
->data
.i
= *(int*)&tmp
;
1962 args
[pindex
++] = &sval
->data
.i
;
1966 args
[pindex
++] = &sval
->data
.f
;
1969 printf ("%s\n", mono_type_full_name (t
));
1970 g_assert_not_reached ();
1975 interp_push_lmf (&ext
, frame
);
1979 typedef void (*T
)(gpointer
);
1980 T func
= (T
)rmethod
->jit_wrapper
;
1986 typedef void (*T
)(gpointer
, gpointer
);
1987 T func
= (T
)rmethod
->jit_wrapper
;
1989 func (args
[0], &ftndesc
);
1993 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
1994 T func
= (T
)rmethod
->jit_wrapper
;
1996 func (args
[0], args
[1], &ftndesc
);
2000 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2001 T func
= (T
)rmethod
->jit_wrapper
;
2003 func (args
[0], args
[1], args
[2], &ftndesc
);
2007 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2008 T func
= (T
)rmethod
->jit_wrapper
;
2010 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2014 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2015 T func
= (T
)rmethod
->jit_wrapper
;
2017 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2021 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2022 T func
= (T
)rmethod
->jit_wrapper
;
2024 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2028 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2029 T func
= (T
)rmethod
->jit_wrapper
;
2031 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2035 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2036 T func
= (T
)rmethod
->jit_wrapper
;
2038 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2042 g_assert_not_reached ();
2046 interp_pop_lmf (&ext
);
2048 MonoType
*rtype
= rmethod
->rtype
;
2049 switch (rtype
->type
) {
2050 case MONO_TYPE_VOID
:
2051 case MONO_TYPE_OBJECT
:
2052 case MONO_TYPE_STRING
:
2053 case MONO_TYPE_CLASS
:
2054 case MONO_TYPE_ARRAY
:
2055 case MONO_TYPE_SZARRAY
:
2059 sp
->data
.p
= *(gpointer
*)res_buf
;
2062 sp
->data
.i
= *(gint8
*)res_buf
;
2065 sp
->data
.i
= *(guint8
*)res_buf
;
2068 sp
->data
.i
= *(gint16
*)res_buf
;
2071 sp
->data
.i
= *(guint16
*)res_buf
;
2074 sp
->data
.i
= *(gint32
*)res_buf
;
2077 sp
->data
.i
= *(guint32
*)res_buf
;
2080 sp
->data
.l
= *(gint64
*)res_buf
;
2083 sp
->data
.l
= *(guint64
*)res_buf
;
2086 sp
->data
.f
= *(float*)res_buf
;
2089 sp
->data
.f
= *(double*)res_buf
;
2091 case MONO_TYPE_VALUETYPE
:
2092 /* The result was written to vt_sp */
2095 case MONO_TYPE_GENERICINST
:
2096 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2097 sp
->data
.p
= *(gpointer
*)res_buf
;
2099 /* The result was written to vt_sp */
2104 g_print ("%s\n", mono_type_full_name (rtype
));
2105 g_assert_not_reached ();
2112 static MONO_NEVER_INLINE
void
2113 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2116 interp_push_lmf (&ext
, frame
);
2118 interp_pop_lmf (&ext
);
2121 static MONO_NEVER_INLINE
void
2122 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2125 /* Don't push lmf if we have no interp data */
2126 gboolean push_lmf
= frame
->parent
!= NULL
;
2129 /* Use the parent frame as the current frame is not complete yet */
2131 interp_push_lmf (&ext
, frame
->parent
);
2133 mono_interp_transform_method (frame
->imethod
, context
, error
);
2134 frame
->ex
= mono_error_convert_to_exception (error
);
2137 interp_pop_lmf (&ext
);
2141 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, unsigned char **vt_sp
)
2143 char *vt
= *(char**)vt_sp
;
2144 stackval
*first_arg
= sp
- csig
->param_count
;
2147 * We need to have the varargs linearly on the stack so the ArgIterator
2148 * can iterate over them. We pass the signature first and then copy them
2149 * one by one on the vtstack.
2151 *(gpointer
*)vt
= csig
;
2152 vt
+= sizeof (gpointer
);
2154 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2155 int align
, arg_size
;
2156 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2157 vt
= (char*)ALIGN_PTR_TO (vt
, align
);
2159 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt
, FALSE
);
2163 vt
= (char*)ALIGN_PTR_TO (vt
, MINT_VT_ALIGNMENT
);
2165 *(char**)vt_sp
= vt
;
2169 * These functions are the entry points into the interpreter from compiled code.
2170 * They are called by the interp_in wrappers. They have the following signature:
2171 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2172 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2173 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2174 * more wrappers then these functions.
2175 * this/static * ret/void * 16 arguments -> 64 functions.
2178 #define MAX_INTERP_ENTRY_ARGS 8
2180 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2181 InterpEntryData data; \
2182 (data).rmethod = (_method); \
2183 (data).res = (_res); \
2184 (data).this_arg = (_this_arg); \
2185 (data).many_args = NULL;
2187 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2188 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2189 interp_entry (&data); \
2191 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2192 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2193 (data).args [0] = arg1; \
2194 interp_entry (&data); \
2196 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2197 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2198 (data).args [0] = arg1; \
2199 (data).args [1] = arg2; \
2200 interp_entry (&data); \
2202 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2203 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2204 (data).args [0] = arg1; \
2205 (data).args [1] = arg2; \
2206 (data).args [2] = arg3; \
2207 interp_entry (&data); \
2209 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2210 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2211 (data).args [0] = arg1; \
2212 (data).args [1] = arg2; \
2213 (data).args [2] = arg3; \
2214 (data).args [3] = arg4; \
2215 interp_entry (&data); \
2217 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2218 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2219 (data).args [0] = arg1; \
2220 (data).args [1] = arg2; \
2221 (data).args [2] = arg3; \
2222 (data).args [3] = arg4; \
2223 (data).args [4] = arg5; \
2224 interp_entry (&data); \
2226 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2227 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2228 (data).args [0] = arg1; \
2229 (data).args [1] = arg2; \
2230 (data).args [2] = arg3; \
2231 (data).args [3] = arg4; \
2232 (data).args [4] = arg5; \
2233 (data).args [5] = arg6; \
2234 interp_entry (&data); \
2236 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2237 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2238 (data).args [0] = arg1; \
2239 (data).args [1] = arg2; \
2240 (data).args [2] = arg3; \
2241 (data).args [3] = arg4; \
2242 (data).args [4] = arg5; \
2243 (data).args [5] = arg6; \
2244 (data).args [6] = arg7; \
2245 interp_entry (&data); \
2247 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2248 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2249 (data).args [0] = arg1; \
2250 (data).args [1] = arg2; \
2251 (data).args [2] = arg3; \
2252 (data).args [3] = arg4; \
2253 (data).args [4] = arg5; \
2254 (data).args [5] = arg6; \
2255 (data).args [6] = arg7; \
2256 (data).args [7] = arg8; \
2257 interp_entry (&data); \
2260 #define ARGLIST0 InterpMethod *rmethod
2261 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2262 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2263 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2264 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2265 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2266 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2267 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2268 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2270 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2271 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2272 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2273 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2274 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2275 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2276 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2277 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2278 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2279 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2280 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2281 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2282 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2283 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2284 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2285 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2286 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2287 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2288 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2289 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2290 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2291 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2292 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2293 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2294 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2295 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2296 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2297 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2298 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2299 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2300 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2301 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2302 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2303 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2304 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2305 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2307 #define INTERP_ENTRY_FUNCLIST(type) (gpointer)interp_entry_ ## type ## _0, (gpointer)interp_entry_ ## type ## _1, (gpointer)interp_entry_ ## type ## _2, (gpointer)interp_entry_ ## type ## _3, (gpointer)interp_entry_ ## type ## _4, (gpointer)interp_entry_ ## type ## _5, (gpointer)interp_entry_ ## type ## _6, (gpointer)interp_entry_ ## type ## _7, (gpointer)interp_entry_ ## type ## _8
2309 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2310 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2311 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2312 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2314 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2316 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2318 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2319 data
.many_args
= args
;
2320 interp_entry (&data
);
2323 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2325 // inline so we can alloc on stack
2326 #define alloc_storage_for_stackval(s, t, p) do { \
2327 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2328 (s)->data.vt = alloca (mono_class_value_size ((t)->data.generic_class->container_class, NULL)); \
2329 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2331 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2333 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2338 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2341 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
2342 InterpFrame
*old_frame
;
2346 MonoMethodSignature
*sig
;
2347 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2348 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2351 method
= rmethod
->method
;
2352 sig
= mono_method_signature (method
);
2355 if (context
== NULL
) {
2356 context
= g_new0 (ThreadContext
, 1);
2357 set_context (context
);
2359 old_frame
= context
->current_frame
;
2361 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2363 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2365 /* Allocate storage for value types */
2366 for (i
= 0; i
< sig
->param_count
; i
++) {
2367 MonoType
*type
= sig
->params
[i
];
2368 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2371 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2372 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2374 /* Copy the args saved in the trampoline to the frame stack */
2375 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2377 interp_exec_method (&frame
, context
);
2378 context
->current_frame
= old_frame
;
2381 g_assert (frame
.ex
== NULL
);
2383 /* Write back the return value */
2384 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2388 static InterpMethod
*
2389 lookup_method_pointer (gpointer addr
)
2391 MonoDomain
*domain
= mono_domain_get ();
2392 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2393 InterpMethod
*res
= NULL
;
2395 mono_domain_lock (domain
);
2396 if (info
->interp_method_pointer_hash
)
2397 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2398 mono_domain_unlock (domain
);
2403 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2405 interp_no_native_to_managed (void)
2407 g_error ("interpreter: native-to-managed transition not available on this platform");
2412 * interp_create_method_pointer:
2414 * Return a function pointer which can be used to call METHOD using the
2415 * interpreter. Return NULL for methods which are not supported.
2418 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2420 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2421 return interp_no_native_to_managed
;
2423 gpointer addr
, entry_func
, entry_wrapper
;
2424 MonoDomain
*domain
= mono_domain_get ();
2425 MonoJitDomainInfo
*info
;
2426 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2429 /* Return any errors from method compilation */
2430 mono_interp_transform_method (imethod
, (ThreadContext
*)mono_native_tls_get_value (thread_context_id
), error
);
2431 return_val_if_nok (error
, NULL
);
2434 /* HACK: method_ptr of delegate should point to a runtime method*/
2435 if (method
->wrapper_type
&& (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
||
2436 (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)))
2439 if (imethod
->jit_entry
)
2440 return imethod
->jit_entry
;
2442 MonoMethodSignature
*sig
= mono_method_signature (method
);
2443 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2444 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2446 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2447 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2448 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2449 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2451 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2452 entry_func
= (gpointer
)interp_entry_general
;
2453 } else if (sig
->hasthis
) {
2454 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2455 entry_func
= entry_funcs_instance
[sig
->param_count
];
2457 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2459 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2460 entry_func
= entry_funcs_static
[sig
->param_count
];
2462 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2464 g_assert (entry_func
);
2466 if (!mono_native_to_interp_trampoline
) {
2467 if (mono_aot_only
) {
2468 mono_native_to_interp_trampoline
= mono_aot_get_trampoline ("native_to_interp_trampoline");
2470 MonoTrampInfo
*info
;
2471 mono_native_to_interp_trampoline
= mono_arch_get_native_to_interp_trampoline (&info
);
2472 mono_tramp_info_register (info
, NULL
);
2475 entry_wrapper
= mono_native_to_interp_trampoline
;
2476 /* We need the lmf wrapper only when being called from mixed mode */
2478 entry_func
= interp_entry_from_trampoline
;
2480 entry_func
= mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper (), error
);
2482 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2483 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2484 ftndesc
->addr
= entry_func
;
2485 ftndesc
->arg
= imethod
;
2486 mono_error_assert_ok (error
);
2489 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2490 * rgctx register using a trampoline.
2493 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2495 info
= domain_jit_info (domain
);
2496 mono_domain_lock (domain
);
2497 if (!info
->interp_method_pointer_hash
)
2498 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2499 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2500 mono_domain_unlock (domain
);
2502 mono_memory_barrier ();
2503 imethod
->jit_entry
= addr
;
2510 static int opcode_counts
[512];
2512 #define COUNT_OP(op) opcode_counts[op]++
2514 #define COUNT_OP(op)
2518 #define DUMP_INSTR() \
2519 if (tracing > 1) { \
2521 if (sp > frame->stack) { \
2522 ins = dump_stack (frame->stack, sp); \
2524 ins = g_strdup (""); \
2528 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2529 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2530 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2536 #define DUMP_INSTR()
2540 #define USE_COMPUTED_GOTO 1
2542 #if USE_COMPUTED_GOTO
2543 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2544 #define MINT_IN_CASE(x) LAB_ ## x:
2546 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2548 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2550 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2552 #define MINT_IN_SWITCH(op) switch (op)
2553 #define MINT_IN_CASE(x) case x:
2554 #define MINT_IN_BREAK break
2555 #define MINT_IN_DEFAULT default:
2559 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2560 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2563 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, guint16
*start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
, InterpFrame
*base_frame
)
2565 InterpFrame child_frame
;
2566 GSList
*finally_ips
= NULL
;
2567 const unsigned short *endfinally_ip
= NULL
;
2568 const unsigned short *ip
= NULL
;
2569 register stackval
*sp
;
2570 InterpMethod
*rtm
= NULL
;
2572 gint tracing
= global_tracing
;
2573 unsigned char *vtalloc
;
2578 unsigned char *vt_sp
;
2579 unsigned char *locals
;
2581 MonoObject
*o
= NULL
;
2583 #if USE_COMPUTED_GOTO
2584 static void *in_labels
[] = {
2585 #define OPDEF(a,b,c,d) \
2587 #include "mintops.def"
2593 frame
->ex_handler
= NULL
;
2595 frame
->domain
= mono_domain_get ();
2596 context
->current_frame
= frame
;
2598 debug_enter (frame
, &tracing
);
2600 rtm
= frame
->imethod
;
2601 if (!frame
->imethod
->transformed
) {
2603 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
2604 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2608 do_transform_method (frame
, context
);
2610 THROW_EX (frame
->ex
, NULL
);
2611 if (*mono_thread_interruption_request_flag ()) {
2612 MonoException
*exc
= mono_thread_interruption_checkpoint ();
2614 THROW_EX (exc
, NULL
);
2619 if (!start_with_ip
) {
2620 frame
->args
= g_newa (char, rtm
->alloca_size
);
2621 memset (frame
->args
, 0, rtm
->alloca_size
);
2627 frame
->args
= g_newa (char, rtm
->alloca_size
);
2628 memcpy (frame
->args
, base_frame
->args
, rtm
->alloca_size
);
2631 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2632 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2636 locals
= (unsigned char *) vt_sp
+ rtm
->vt_stack_size
;
2637 frame
->locals
= locals
;
2638 child_frame
.parent
= frame
;
2640 if (filter_exception
) {
2641 sp
->data
.p
= filter_exception
;
2646 * using while (ip < end) may result in a 15% performance drop,
2647 * but it may be useful for debug
2651 /* g_assert (sp >= frame->stack); */
2652 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2654 MINT_IN_SWITCH (*ip
) {
2655 MINT_IN_CASE(MINT_INITLOCALS
)
2656 memset (locals
, 0, rtm
->locals_size
);
2659 MINT_IN_CASE(MINT_NOP
)
2662 MINT_IN_CASE(MINT_NIY
)
2663 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2665 MINT_IN_CASE(MINT_BREAK
)
2667 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
2669 MINT_IN_CASE(MINT_LDNULL
)
2674 MINT_IN_CASE(MINT_ARGLIST
)
2675 g_assert (frame
->varargs
);
2677 *(gpointer
*)sp
->data
.p
= frame
->varargs
;
2678 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
2682 MINT_IN_CASE(MINT_VTRESULT
) {
2683 int ret_size
= * (guint16
*)(ip
+ 1);
2684 unsigned char *ret_vt_sp
= vt_sp
;
2685 vt_sp
-= READ32(ip
+ 2);
2687 memmove (vt_sp
, ret_vt_sp
, ret_size
);
2688 sp
[-1].data
.p
= vt_sp
;
2689 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
2694 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2695 MINT_IN_CASE(MINT_LDC_I4_M1
)
2698 MINT_IN_CASE(MINT_LDC_I4_0
)
2701 MINT_IN_CASE(MINT_LDC_I4_1
)
2704 MINT_IN_CASE(MINT_LDC_I4_2
)
2707 MINT_IN_CASE(MINT_LDC_I4_3
)
2710 MINT_IN_CASE(MINT_LDC_I4_4
)
2713 MINT_IN_CASE(MINT_LDC_I4_5
)
2716 MINT_IN_CASE(MINT_LDC_I4_6
)
2719 MINT_IN_CASE(MINT_LDC_I4_7
)
2722 MINT_IN_CASE(MINT_LDC_I4_8
)
2725 MINT_IN_CASE(MINT_LDC_I4_S
)
2726 sp
->data
.i
= *(const short *)(ip
+ 1);
2730 MINT_IN_CASE(MINT_LDC_I4
)
2732 sp
->data
.i
= READ32 (ip
);
2736 MINT_IN_CASE(MINT_LDC_I8
)
2738 sp
->data
.l
= READ64 (ip
);
2742 MINT_IN_CASE(MINT_LDC_R4
) {
2746 sp
->data
.f
= * (float *)&val
;
2751 MINT_IN_CASE(MINT_LDC_R8
)
2752 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
2756 MINT_IN_CASE(MINT_DUP
)
2761 MINT_IN_CASE(MINT_DUP_VT
)
2762 i32
= READ32 (ip
+ 1);
2764 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
2765 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
2769 MINT_IN_CASE(MINT_POP
) {
2770 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
2772 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
2777 MINT_IN_CASE(MINT_JMP
) {
2778 InterpMethod
*new_method
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2779 gboolean realloc_frame
= new_method
->alloca_size
> rtm
->alloca_size
;
2781 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
2782 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
2784 if (!new_method
->transformed
) {
2788 mono_interp_transform_method (new_method
, context
, error
);
2789 frame
->ex
= mono_error_convert_to_exception (error
);
2794 rtm
= frame
->imethod
= new_method
;
2796 * We allocate the stack frame from scratch and store the arguments in the
2797 * locals again since it's possible for the caller stack frame to be smaller
2798 * than the callee stack frame (at the interp level)
2800 if (realloc_frame
) {
2801 frame
->args
= g_newa (char, rtm
->alloca_size
);
2802 memset (frame
->args
, 0, rtm
->alloca_size
);
2803 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2805 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2809 locals
= vt_sp
+ rtm
->vt_stack_size
;
2810 frame
->locals
= locals
;
2814 ip
= rtm
->new_body_start
; /* bypass storing input args from callers frame */
2817 MINT_IN_CASE(MINT_CALLI
) {
2818 MonoMethodSignature
*csignature
;
2819 stackval
*endsp
= sp
;
2823 csignature
= (MonoMethodSignature
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2827 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
2830 child_frame
.retval
= sp
;
2831 /* decrement by the actual number of args */
2832 sp
-= csignature
->param_count
;
2833 if (csignature
->hasthis
)
2835 child_frame
.stack_args
= sp
;
2837 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
2838 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
2839 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2842 if (csignature
->hasthis
) {
2843 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
2845 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
2846 gpointer unboxed
= mono_object_unbox (this_arg
);
2847 sp
[0].data
.p
= unboxed
;
2851 interp_exec_method (&child_frame
, context
);
2853 context
->current_frame
= frame
;
2855 if (context
->has_resume_state
) {
2856 if (frame
== context
->handler_frame
)
2857 SET_RESUME_STATE (context
);
2862 CHECK_CHILD_EX (child_frame
, ip
- 2);
2864 /* need to handle typedbyref ... */
2865 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2871 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
2872 gpointer target_ip
= sp
[-1].data
.p
;
2873 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2874 int opcode
= *(guint16
*)(ip
+ 2);
2879 sp
= do_icall (context
, csignature
, opcode
, sp
, target_ip
);
2880 EXCEPTION_CHECKPOINT
;
2881 if (context
->has_resume_state
) {
2882 if (frame
== context
->handler_frame
)
2883 SET_RESUME_STATE (context
);
2890 MINT_IN_CASE(MINT_CALLI_NAT
) {
2891 MonoMethodSignature
*csignature
;
2892 stackval
*endsp
= sp
;
2893 unsigned char *code
= NULL
;
2897 csignature
= (MonoMethodSignature
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2901 code
= (guchar
*)sp
->data
.p
;
2902 child_frame
.imethod
= NULL
;
2905 child_frame
.retval
= sp
;
2906 /* decrement by the actual number of args */
2907 sp
-= csignature
->param_count
;
2908 if (csignature
->hasthis
)
2910 child_frame
.stack_args
= sp
;
2911 if (frame
->imethod
->method
->dynamic
&& csignature
->pinvoke
) {
2912 MonoMarshalSpec
**mspecs
;
2913 MonoMethodPInvoke piinfo
;
2916 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
2917 mspecs
= g_newa (MonoMarshalSpec
*, csignature
->param_count
+ 1);
2918 memset (&piinfo
, 0, sizeof (piinfo
));
2920 m
= mono_marshal_get_native_func_wrapper (m_class_get_image (frame
->imethod
->method
->klass
), csignature
, &piinfo
, mspecs
, code
);
2921 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, m
, error
);
2922 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2924 interp_exec_method (&child_frame
, context
);
2926 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
);
2928 context
->current_frame
= frame
;
2930 if (context
->has_resume_state
) {
2931 if (frame
== context
->handler_frame
)
2932 SET_RESUME_STATE (context
);
2937 CHECK_CHILD_EX (child_frame
, ip
- 2);
2939 /* need to handle typedbyref ... */
2940 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2946 MINT_IN_CASE(MINT_CALL
)
2947 MINT_IN_CASE(MINT_VCALL
)
2948 MINT_IN_CASE(MINT_CALLVIRT
)
2949 MINT_IN_CASE(MINT_VCALLVIRT
) {
2950 gboolean is_void
= *ip
== MINT_VCALL
|| *ip
== MINT_VCALLVIRT
;
2951 gboolean is_virtual
= *ip
== MINT_CALLVIRT
|| *ip
== MINT_VCALLVIRT
;
2952 stackval
*endsp
= sp
;
2953 int num_varargs
= 0;;
2957 child_frame
.imethod
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2958 if (child_frame
.imethod
->vararg
) {
2959 /* The real signature for vararg calls */
2960 MonoMethodSignature
*csig
= (MonoMethodSignature
*) rtm
->data_items
[* (guint16
*) (ip
+ 2)];
2961 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
2962 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
2963 child_frame
.varargs
= (char*) vt_sp
;
2964 copy_varargs_vtstack (csig
, sp
, &vt_sp
);
2966 ip
+= 2 + child_frame
.imethod
->vararg
;
2968 child_frame
.retval
= sp
;
2970 /* decrement by the actual number of args */
2971 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
2972 child_frame
.stack_args
= sp
;
2975 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
2976 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2978 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
2979 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
2981 gpointer unboxed
= mono_object_unbox (this_arg
);
2982 sp
[0].data
.p
= unboxed
;
2986 interp_exec_method (&child_frame
, context
);
2988 context
->current_frame
= frame
;
2990 if (context
->has_resume_state
) {
2991 if (frame
== context
->handler_frame
)
2992 SET_RESUME_STATE (context
);
2996 CHECK_CHILD_EX (child_frame
, ip
- 2);
2999 /* need to handle typedbyref ... */
3005 MINT_IN_CASE(MINT_JIT_CALL
) {
3006 InterpMethod
*rmethod
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3010 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3011 if (!is_ok (error
)) {
3012 MonoException
*ex
= mono_error_convert_to_exception (error
);
3016 if (context
->has_resume_state
) {
3018 * If this bit is set, it means the call has thrown the exception, and we
3019 * reached this point because the EH code in mono_handle_exception ()
3020 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
3021 * has set the fields in context to indicate where we have to resume execution.
3023 if (frame
== context
->handler_frame
)
3024 SET_RESUME_STATE (context
);
3028 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3033 MINT_IN_CASE(MINT_CALLRUN
) {
3034 MonoMethod
*target_method
= (MonoMethod
*) rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3035 MonoMethodSignature
*sig
= (MonoMethodSignature
*) rtm
->data_items
[* (guint16
*)(ip
+ 2)];
3041 sp
-= sig
->param_count
;
3045 ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3047 THROW_EX (frame
->ex
, ip
);
3049 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3056 MINT_IN_CASE(MINT_RET
)
3058 *frame
->retval
= *sp
;
3059 if (sp
> frame
->stack
)
3060 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3062 MINT_IN_CASE(MINT_RET_VOID
)
3063 if (sp
> frame
->stack
)
3064 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
3066 MINT_IN_CASE(MINT_RET_VT
)
3067 i32
= READ32(ip
+ 1);
3069 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3070 if (sp
> frame
->stack
)
3071 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3073 MINT_IN_CASE(MINT_BR_S
)
3074 ip
+= (short) *(ip
+ 1);
3076 MINT_IN_CASE(MINT_BR
)
3077 ip
+= (gint32
) READ32(ip
+ 1);
3079 #define ZEROP_S(datamem, op) \
3081 if (sp->data.datamem op 0) \
3082 ip += * (gint16 *)(ip + 1); \
3086 #define ZEROP(datamem, op) \
3088 if (sp->data.datamem op 0) \
3089 ip += READ32(ip + 1); \
3093 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3096 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3099 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3102 MINT_IN_CASE(MINT_BRFALSE_I4
)
3105 MINT_IN_CASE(MINT_BRFALSE_I8
)
3108 MINT_IN_CASE(MINT_BRFALSE_R8
)
3111 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3114 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3117 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3120 MINT_IN_CASE(MINT_BRTRUE_I4
)
3123 MINT_IN_CASE(MINT_BRTRUE_I8
)
3126 MINT_IN_CASE(MINT_BRTRUE_R8
)
3129 #define CONDBR_S(cond) \
3132 ip += * (gint16 *)(ip + 1); \
3135 #define BRELOP_S(datamem, op) \
3136 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3138 #define CONDBR(cond) \
3141 ip += READ32(ip + 1); \
3145 #define BRELOP(datamem, op) \
3146 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3148 MINT_IN_CASE(MINT_BEQ_I4_S
)
3151 MINT_IN_CASE(MINT_BEQ_I8_S
)
3154 MINT_IN_CASE(MINT_BEQ_R8_S
)
3155 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3157 MINT_IN_CASE(MINT_BEQ_I4
)
3160 MINT_IN_CASE(MINT_BEQ_I8
)
3163 MINT_IN_CASE(MINT_BEQ_R8
)
3164 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3166 MINT_IN_CASE(MINT_BGE_I4_S
)
3169 MINT_IN_CASE(MINT_BGE_I8_S
)
3172 MINT_IN_CASE(MINT_BGE_R8_S
)
3173 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3175 MINT_IN_CASE(MINT_BGE_I4
)
3178 MINT_IN_CASE(MINT_BGE_I8
)
3181 MINT_IN_CASE(MINT_BGE_R8
)
3182 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3184 MINT_IN_CASE(MINT_BGT_I4_S
)
3187 MINT_IN_CASE(MINT_BGT_I8_S
)
3190 MINT_IN_CASE(MINT_BGT_R8_S
)
3191 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3193 MINT_IN_CASE(MINT_BGT_I4
)
3196 MINT_IN_CASE(MINT_BGT_I8
)
3199 MINT_IN_CASE(MINT_BGT_R8
)
3200 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3202 MINT_IN_CASE(MINT_BLT_I4_S
)
3205 MINT_IN_CASE(MINT_BLT_I8_S
)
3208 MINT_IN_CASE(MINT_BLT_R8_S
)
3209 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3211 MINT_IN_CASE(MINT_BLT_I4
)
3214 MINT_IN_CASE(MINT_BLT_I8
)
3217 MINT_IN_CASE(MINT_BLT_R8
)
3218 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3220 MINT_IN_CASE(MINT_BLE_I4_S
)
3223 MINT_IN_CASE(MINT_BLE_I8_S
)
3226 MINT_IN_CASE(MINT_BLE_R8_S
)
3227 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3229 MINT_IN_CASE(MINT_BLE_I4
)
3232 MINT_IN_CASE(MINT_BLE_I8
)
3235 MINT_IN_CASE(MINT_BLE_R8
)
3236 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3238 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3241 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3244 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3245 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3247 MINT_IN_CASE(MINT_BNE_UN_I4
)
3250 MINT_IN_CASE(MINT_BNE_UN_I8
)
3253 MINT_IN_CASE(MINT_BNE_UN_R8
)
3254 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3257 #define BRELOP_S_CAST(datamem, op, type) \
3259 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3260 ip += * (gint16 *)(ip + 1); \
3264 #define BRELOP_CAST(datamem, op, type) \
3266 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3267 ip += READ32(ip + 1); \
3271 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3272 BRELOP_S_CAST(i
, >=, guint32
);
3274 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3275 BRELOP_S_CAST(l
, >=, guint64
);
3277 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3278 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3280 MINT_IN_CASE(MINT_BGE_UN_I4
)
3281 BRELOP_CAST(i
, >=, guint32
);
3283 MINT_IN_CASE(MINT_BGE_UN_I8
)
3284 BRELOP_CAST(l
, >=, guint64
);
3286 MINT_IN_CASE(MINT_BGE_UN_R8
)
3287 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3289 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3290 BRELOP_S_CAST(i
, >, guint32
);
3292 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3293 BRELOP_S_CAST(l
, >, guint64
);
3295 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3296 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3298 MINT_IN_CASE(MINT_BGT_UN_I4
)
3299 BRELOP_CAST(i
, >, guint32
);
3301 MINT_IN_CASE(MINT_BGT_UN_I8
)
3302 BRELOP_CAST(l
, >, guint64
);
3304 MINT_IN_CASE(MINT_BGT_UN_R8
)
3305 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3307 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3308 BRELOP_S_CAST(i
, <=, guint32
);
3310 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3311 BRELOP_S_CAST(l
, <=, guint64
);
3313 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3314 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3316 MINT_IN_CASE(MINT_BLE_UN_I4
)
3317 BRELOP_CAST(i
, <=, guint32
);
3319 MINT_IN_CASE(MINT_BLE_UN_I8
)
3320 BRELOP_CAST(l
, <=, guint64
);
3322 MINT_IN_CASE(MINT_BLE_UN_R8
)
3323 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3325 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3326 BRELOP_S_CAST(i
, <, guint32
);
3328 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3329 BRELOP_S_CAST(l
, <, guint64
);
3331 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3332 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3334 MINT_IN_CASE(MINT_BLT_UN_I4
)
3335 BRELOP_CAST(i
, <, guint32
);
3337 MINT_IN_CASE(MINT_BLT_UN_I8
)
3338 BRELOP_CAST(l
, <, guint64
);
3340 MINT_IN_CASE(MINT_BLT_UN_R8
)
3341 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3343 MINT_IN_CASE(MINT_SWITCH
) {
3345 const unsigned short *st
;
3351 if ((guint32
)sp
->data
.i
< n
) {
3353 ip
+= 2 * (guint32
)sp
->data
.i
;
3354 offset
= READ32 (ip
);
3361 MINT_IN_CASE(MINT_LDIND_I1
)
3363 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3365 MINT_IN_CASE(MINT_LDIND_U1
)
3367 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3369 MINT_IN_CASE(MINT_LDIND_I2
)
3371 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3373 MINT_IN_CASE(MINT_LDIND_U2
)
3375 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3377 MINT_IN_CASE(MINT_LDIND_I4
) /* Fall through */
3378 MINT_IN_CASE(MINT_LDIND_U4
)
3380 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3382 MINT_IN_CASE(MINT_LDIND_I8
)
3384 /* memmove handles unaligned case */
3385 memmove (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
3387 MINT_IN_CASE(MINT_LDIND_I
) {
3388 guint16 offset
= * (guint16
*)(ip
+ 1);
3389 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3393 MINT_IN_CASE(MINT_LDIND_R4
)
3395 sp
[-1].data
.f
= *(gfloat
*)sp
[-1].data
.p
;
3397 MINT_IN_CASE(MINT_LDIND_R8
)
3399 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3401 MINT_IN_CASE(MINT_LDIND_REF
)
3403 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3405 MINT_IN_CASE(MINT_STIND_REF
)
3408 mono_gc_wbarrier_generic_store (sp
->data
.p
, sp
[1].data
.o
);
3410 MINT_IN_CASE(MINT_STIND_I1
)
3413 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3415 MINT_IN_CASE(MINT_STIND_I2
)
3418 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3420 MINT_IN_CASE(MINT_STIND_I4
)
3423 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3425 MINT_IN_CASE(MINT_STIND_I
)
3428 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3430 MINT_IN_CASE(MINT_STIND_I8
)
3433 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3435 MINT_IN_CASE(MINT_STIND_R4
)
3438 * (float *) sp
->data
.p
= (gfloat
)sp
[1].data
.f
;
3440 MINT_IN_CASE(MINT_STIND_R8
)
3443 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3445 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3448 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3450 #define BINOP(datamem, op) \
3452 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3454 MINT_IN_CASE(MINT_ADD_I4
)
3457 MINT_IN_CASE(MINT_ADD_I8
)
3460 MINT_IN_CASE(MINT_ADD_R8
)
3463 MINT_IN_CASE(MINT_ADD1_I4
)
3467 MINT_IN_CASE(MINT_ADD1_I8
)
3471 MINT_IN_CASE(MINT_SUB_I4
)
3474 MINT_IN_CASE(MINT_SUB_I8
)
3477 MINT_IN_CASE(MINT_SUB_R8
)
3480 MINT_IN_CASE(MINT_SUB1_I4
)
3484 MINT_IN_CASE(MINT_SUB1_I8
)
3488 MINT_IN_CASE(MINT_MUL_I4
)
3491 MINT_IN_CASE(MINT_MUL_I8
)
3494 MINT_IN_CASE(MINT_MUL_R8
)
3497 MINT_IN_CASE(MINT_DIV_I4
)
3498 if (sp
[-1].data
.i
== 0)
3499 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3500 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
3501 THROW_EX (mono_get_exception_overflow (), ip
);
3504 MINT_IN_CASE(MINT_DIV_I8
)
3505 if (sp
[-1].data
.l
== 0)
3506 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3507 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
3508 THROW_EX (mono_get_exception_overflow (), ip
);
3511 MINT_IN_CASE(MINT_DIV_R8
)
3515 #define BINOP_CAST(datamem, op, type) \
3517 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3519 MINT_IN_CASE(MINT_DIV_UN_I4
)
3520 if (sp
[-1].data
.i
== 0)
3521 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3522 BINOP_CAST(i
, /, guint32
);
3524 MINT_IN_CASE(MINT_DIV_UN_I8
)
3525 if (sp
[-1].data
.l
== 0)
3526 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3527 BINOP_CAST(l
, /, guint64
);
3529 MINT_IN_CASE(MINT_REM_I4
)
3530 if (sp
[-1].data
.i
== 0)
3531 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3532 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
3533 THROW_EX (mono_get_exception_overflow (), ip
);
3536 MINT_IN_CASE(MINT_REM_I8
)
3537 if (sp
[-1].data
.l
== 0)
3538 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3539 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
3540 THROW_EX (mono_get_exception_overflow (), ip
);
3543 MINT_IN_CASE(MINT_REM_R8
)
3544 /* FIXME: what do we actually do here? */
3546 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
3549 MINT_IN_CASE(MINT_REM_UN_I4
)
3550 if (sp
[-1].data
.i
== 0)
3551 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3552 BINOP_CAST(i
, %, guint32
);
3554 MINT_IN_CASE(MINT_REM_UN_I8
)
3555 if (sp
[-1].data
.l
== 0)
3556 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3557 BINOP_CAST(l
, %, guint64
);
3559 MINT_IN_CASE(MINT_AND_I4
)
3562 MINT_IN_CASE(MINT_AND_I8
)
3565 MINT_IN_CASE(MINT_OR_I4
)
3568 MINT_IN_CASE(MINT_OR_I8
)
3571 MINT_IN_CASE(MINT_XOR_I4
)
3574 MINT_IN_CASE(MINT_XOR_I8
)
3578 #define SHIFTOP(datamem, op) \
3580 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3583 MINT_IN_CASE(MINT_SHL_I4
)
3586 MINT_IN_CASE(MINT_SHL_I8
)
3589 MINT_IN_CASE(MINT_SHR_I4
)
3592 MINT_IN_CASE(MINT_SHR_I8
)
3595 MINT_IN_CASE(MINT_SHR_UN_I4
)
3597 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
3600 MINT_IN_CASE(MINT_SHR_UN_I8
)
3602 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
3605 MINT_IN_CASE(MINT_NEG_I4
)
3606 sp
[-1].data
.i
= - sp
[-1].data
.i
;
3609 MINT_IN_CASE(MINT_NEG_I8
)
3610 sp
[-1].data
.l
= - sp
[-1].data
.l
;
3613 MINT_IN_CASE(MINT_NEG_R8
)
3614 sp
[-1].data
.f
= - sp
[-1].data
.f
;
3617 MINT_IN_CASE(MINT_NOT_I4
)
3618 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
3621 MINT_IN_CASE(MINT_NOT_I8
)
3622 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
3625 MINT_IN_CASE(MINT_CONV_I1_I4
)
3626 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
3629 MINT_IN_CASE(MINT_CONV_I1_I8
)
3630 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
3633 MINT_IN_CASE(MINT_CONV_I1_R8
)
3634 /* without gint32 cast, C compiler is allowed to use undefined
3635 * behaviour if data.f is bigger than >255. See conv.fpint section
3637 * > The conversion truncates; that is, the fractional part
3638 * > is discarded. The behavior is undefined if the truncated
3639 * > value cannot be represented in the destination type.
3641 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
3644 MINT_IN_CASE(MINT_CONV_U1_I4
)
3645 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
3648 MINT_IN_CASE(MINT_CONV_U1_I8
)
3649 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
3652 MINT_IN_CASE(MINT_CONV_U1_R8
)
3653 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
3656 MINT_IN_CASE(MINT_CONV_I2_I4
)
3657 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
3660 MINT_IN_CASE(MINT_CONV_I2_I8
)
3661 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
3664 MINT_IN_CASE(MINT_CONV_I2_R8
)
3665 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
3668 MINT_IN_CASE(MINT_CONV_U2_I4
)
3669 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
3672 MINT_IN_CASE(MINT_CONV_U2_I8
)
3673 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
3676 MINT_IN_CASE(MINT_CONV_U2_R8
)
3677 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
3680 MINT_IN_CASE(MINT_CONV_I4_R8
)
3681 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
3684 MINT_IN_CASE(MINT_CONV_U4_I8
)
3685 MINT_IN_CASE(MINT_CONV_I4_I8
)
3686 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
3689 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
3690 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
3693 MINT_IN_CASE(MINT_CONV_U4_R8
)
3694 /* needed on arm64 */
3695 if (isinf (sp
[-1].data
.f
))
3697 /* needed by wasm */
3698 else if (isnan (sp
[-1].data
.f
))
3701 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3704 MINT_IN_CASE(MINT_CONV_I8_I4
)
3705 sp
[-1].data
.l
= sp
[-1].data
.i
;
3708 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
3709 sp
[-2].data
.l
= sp
[-2].data
.i
;
3712 MINT_IN_CASE(MINT_CONV_I8_U4
)
3713 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
3716 MINT_IN_CASE(MINT_CONV_I8_R8
)
3717 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
3720 MINT_IN_CASE(MINT_CONV_R4_I4
)
3721 sp
[-1].data
.f
= (float)sp
[-1].data
.i
;
3724 MINT_IN_CASE(MINT_CONV_R4_I8
)
3725 sp
[-1].data
.f
= (float)sp
[-1].data
.l
;
3728 MINT_IN_CASE(MINT_CONV_R4_R8
)
3729 sp
[-1].data
.f
= (float)sp
[-1].data
.f
;
3732 MINT_IN_CASE(MINT_CONV_R8_I4
)
3733 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
3736 MINT_IN_CASE(MINT_CONV_R8_I8
)
3737 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
3740 MINT_IN_CASE(MINT_CONV_U8_I4
)
3741 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
3744 MINT_IN_CASE(MINT_CONV_U8_R8
)
3745 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
3748 MINT_IN_CASE(MINT_CPOBJ
) {
3749 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3750 g_assert (m_class_is_valuetype (c
));
3751 /* if this assertion fails, we need to add a write barrier */
3752 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
3753 if (mint_type (m_class_get_byval_arg (c
)) == MINT_TYPE_VT
)
3754 stackval_from_data (m_class_get_byval_arg (c
), &sp
[-2], sp
[-1].data
.p
, FALSE
);
3756 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
3761 MINT_IN_CASE(MINT_LDOBJ
) {
3763 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3766 if (mint_type (m_class_get_byval_arg (c
)) == MINT_TYPE_VT
&& !m_class_is_enumtype (c
)) {
3767 int size
= mono_class_value_size (c
, NULL
);
3768 sp
[-1].data
.p
= vt_sp
;
3769 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3771 stackval_from_data (m_class_get_byval_arg (c
), &sp
[-1], p
, FALSE
);
3774 MINT_IN_CASE(MINT_LDSTR
)
3775 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3779 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
3780 MonoString
*s
= NULL
;
3781 guint32 strtoken
= (guint32
)(gsize
)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3783 MonoMethod
*method
= frame
->imethod
->method
;
3784 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
3785 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
3786 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
3787 s
= mono_string_new_wrapper ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
3789 g_assert_not_reached ();
3796 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
3797 MonoClass
*newobj_class
;
3798 InterpMethod
*imethod
;
3799 guint32 token
= * (guint16
*)(ip
+ 1);
3800 guint16 param_count
= * (guint16
*)(ip
+ 2);
3802 imethod
= (InterpMethod
*) rtm
->data_items
[token
];
3803 newobj_class
= imethod
->method
->klass
;
3806 sp
->data
.p
= ves_array_create (rtm
->domain
, newobj_class
, param_count
, sp
, error
);
3807 if (!mono_error_ok (error
))
3808 THROW_EX (mono_error_convert_to_exception (error
), ip
);
3814 MINT_IN_CASE(MINT_NEWOBJ_FAST
)
3815 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
3816 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
3817 guint16 param_count
;
3818 gboolean vt
= *ip
!= MINT_NEWOBJ_FAST
;
3819 stackval valuetype_this
;
3823 child_frame
.imethod
= (InterpMethod
*) rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3824 param_count
= *(guint16
*)(ip
+ 2);
3828 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
3830 child_frame
.stack_args
= sp
;
3833 gboolean vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
3834 memset (&valuetype_this
, 0, sizeof (stackval
));
3837 valuetype_this
.data
.p
= vt_sp
;
3839 sp
->data
.p
= &valuetype_this
;
3842 MonoVTable
*vtable
= (MonoVTable
*) rtm
->data_items
[*(guint16
*)(ip
+ 3)];
3843 if (G_UNLIKELY (!vtable
->initialized
)) {
3844 mono_runtime_class_init_full (vtable
, error
);
3845 if (!mono_error_ok (error
))
3846 THROW_EX (mono_error_convert_to_exception (error
), ip
);
3848 o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3849 if (G_UNLIKELY (!o
)) {
3850 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
3851 THROW_EX (mono_error_convert_to_exception (error
), ip
);
3856 interp_exec_method (&child_frame
, context
);
3858 context
->current_frame
= frame
;
3860 if (context
->has_resume_state
) {
3861 if (frame
== context
->handler_frame
)
3862 SET_RESUME_STATE (context
);
3866 CHECK_CHILD_EX (child_frame
, ip
);
3868 *sp
= valuetype_this
;
3875 MINT_IN_CASE(MINT_NEWOBJ
) {
3876 MonoClass
*newobj_class
;
3877 MonoMethodSignature
*csig
;
3878 stackval valuetype_this
;
3884 token
= * (guint16
*)(ip
+ 1);
3887 child_frame
.ip
= NULL
;
3888 child_frame
.ex
= NULL
;
3890 child_frame
.imethod
= (InterpMethod
*)rtm
->data_items
[token
];
3891 csig
= mono_method_signature (child_frame
.imethod
->method
);
3892 newobj_class
= child_frame
.imethod
->method
->klass
;
3893 /*if (profiling_classes) {
3894 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3896 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3899 g_assert (csig
->hasthis
);
3900 if (csig
->param_count
) {
3901 sp
-= csig
->param_count
;
3902 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
3904 child_frame
.stack_args
= sp
;
3907 * First arg is the object.
3909 if (m_class_is_valuetype (newobj_class
)) {
3910 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
3911 memset (&valuetype_this
, 0, sizeof (stackval
));
3912 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3914 valuetype_this
.data
.p
= vt_sp
;
3916 sp
->data
.p
= &valuetype_this
;
3919 if (newobj_class
!= mono_defaults
.string_class
) {
3920 MonoVTable
*vtable
= mono_class_vtable_checked (rtm
->domain
, newobj_class
, error
);
3921 if (!mono_error_ok (error
) || !mono_runtime_class_init_full (vtable
, error
))
3922 THROW_EX (mono_error_convert_to_exception (error
), ip
);
3923 o
= mono_object_new_checked (rtm
->domain
, newobj_class
, error
);
3924 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3925 EXCEPTION_CHECKPOINT
;
3927 #ifndef DISABLE_REMOTING
3928 if (mono_object_is_transparent_proxy (o
)) {
3929 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
.imethod
->method
, error
);
3930 mono_error_assert_ok (error
);
3931 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, remoting_invoke_method
, error
);
3932 mono_error_assert_ok (error
);
3937 child_frame
.retval
= &retval
;
3941 interp_exec_method (&child_frame
, context
);
3943 context
->current_frame
= frame
;
3945 if (context
->has_resume_state
) {
3946 if (frame
== context
->handler_frame
)
3947 SET_RESUME_STATE (context
);
3952 CHECK_CHILD_EX (child_frame
, ip
- 2);
3954 * a constructor returns void, but we need to return the object we created
3956 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
3957 *sp
= valuetype_this
;
3958 } else if (newobj_class
== mono_defaults
.string_class
) {
3966 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
3970 token
= * (guint16
*)(ip
+ 1);
3975 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
3976 MonoClass
*newobj_class
;
3977 MonoMethodSignature
*csig
;
3981 token
= * (guint16
*)(ip
+ 1);
3984 InterpMethod
*cmethod
= (InterpMethod
*)rtm
->data_items
[token
];
3985 csig
= mono_method_signature (cmethod
->method
);
3986 newobj_class
= cmethod
->method
->klass
;
3988 g_assert (csig
->hasthis
);
3989 sp
-= csig
->param_count
;
3991 gpointer arg0
= sp
[0].data
.p
;
3993 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
3994 *byreference_this
= arg0
;
3996 /* Followed by a VTRESULT opcode which will push the result on the stack */
4001 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4002 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4003 sp
[-1].data
.p
= *byreference_this
;
4008 MINT_IN_CASE(MINT_CASTCLASS
)
4009 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4010 if ((o
= sp
[-1].data
.o
)) {
4011 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4012 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4014 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4018 MINT_IN_CASE(MINT_ISINST
)
4019 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4020 if ((o
= sp
[-1].data
.o
)) {
4021 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4022 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4024 sp
[-1].data
.p
= NULL
;
4028 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4029 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4032 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4033 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4036 MINT_IN_CASE(MINT_UNBOX
)
4037 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4041 THROW_EX (mono_get_exception_null_reference (), ip
);
4043 MonoObject
*isinst_obj
;
4044 isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4045 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4046 if (!(isinst_obj
|| ((m_class_get_rank (o
->vtable
->klass
) == 0) && (m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))))
4047 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4049 sp
[-1].data
.p
= mono_object_unbox (o
);
4052 MINT_IN_CASE(MINT_THROW
)
4054 frame
->ex_handler
= NULL
;
4056 sp
->data
.p
= mono_get_exception_null_reference ();
4058 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4060 MINT_IN_CASE(MINT_CHECKPOINT
)
4061 /* Do synchronous checking of abort requests */
4062 EXCEPTION_CHECKPOINT
;
4065 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
4067 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4070 MINT_IN_CASE(MINT_LDFLDA
)
4073 THROW_EX (mono_get_exception_null_reference (), ip
);
4074 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4077 MINT_IN_CASE(MINT_CKNULL
)
4080 THROW_EX (mono_get_exception_null_reference (), ip
);
4083 MINT_IN_CASE(MINT_CKNULL_N
) {
4084 /* Same as CKNULL, but further down the stack */
4085 int n
= *(guint16
*)(ip
+ 1);
4088 THROW_EX (mono_get_exception_null_reference (), ip
);
4093 #define LDFLD(datamem, fieldtype) \
4094 o = sp [-1].data.o; \
4096 THROW_EX (mono_get_exception_null_reference (), ip); \
4097 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4100 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4101 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4102 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4103 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4104 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4105 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4106 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f
, float); MINT_IN_BREAK
;
4107 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4108 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4109 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4111 MINT_IN_CASE(MINT_LDFLD_VT
) {
4114 THROW_EX (mono_get_exception_null_reference (), ip
);
4116 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 2)];
4117 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
4118 i32
= mono_class_value_size (klass
, NULL
);
4120 sp
[-1].data
.p
= vt_sp
;
4121 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
4122 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4127 MINT_IN_CASE(MINT_LDRMFLD
) {
4128 MonoClassField
*field
;
4133 THROW_EX (mono_get_exception_null_reference (), ip
);
4134 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4136 #ifndef DISABLE_REMOTING
4137 if (mono_object_is_transparent_proxy (o
)) {
4139 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4141 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4142 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4145 addr
= (char*)o
+ field
->offset
;
4147 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
4151 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
4152 MonoClassField
*field
;
4157 THROW_EX (mono_get_exception_null_reference (), ip
);
4159 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4160 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
4161 i32
= mono_class_value_size (klass
, NULL
);
4164 #ifndef DISABLE_REMOTING
4165 if (mono_object_is_transparent_proxy (o
)) {
4167 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4168 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4169 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4172 addr
= (char*)o
+ field
->offset
;
4174 sp
[-1].data
.p
= vt_sp
;
4175 memcpy(sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
4176 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4177 memcpy(sp
[-1].data
.p
, addr
, i32
);
4181 #define STFLD(datamem, fieldtype) \
4182 o = sp [-2].data.o; \
4184 THROW_EX (mono_get_exception_null_reference (), ip); \
4186 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4189 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
4190 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
4191 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
4192 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
4193 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
4194 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
4195 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f
, float); MINT_IN_BREAK
;
4196 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
4197 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
4198 MINT_IN_CASE(MINT_STFLD_O
)
4201 THROW_EX (mono_get_exception_null_reference (), ip
);
4203 mono_gc_wbarrier_set_field (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.o
);
4207 MINT_IN_CASE(MINT_STFLD_VT
) {
4210 THROW_EX (mono_get_exception_null_reference (), ip
);
4213 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 2)];
4214 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
4215 i32
= mono_class_value_size (klass
, NULL
);
4217 guint16 offset
= * (guint16
*)(ip
+ 1);
4218 mono_value_copy ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
4220 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4224 MINT_IN_CASE(MINT_STRMFLD
) {
4225 MonoClassField
*field
;
4229 THROW_EX (mono_get_exception_null_reference (), ip
);
4231 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4234 #ifndef DISABLE_REMOTING
4235 if (mono_object_is_transparent_proxy (o
)) {
4236 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4237 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4238 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4241 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
4246 MINT_IN_CASE(MINT_STRMFLD_VT
) {
4247 MonoClassField
*field
;
4251 THROW_EX (mono_get_exception_null_reference (), ip
);
4252 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4253 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
4254 i32
= mono_class_value_size (klass
, NULL
);
4257 #ifndef DISABLE_REMOTING
4258 if (mono_object_is_transparent_proxy (o
)) {
4259 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4260 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4261 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4264 mono_value_copy ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
4267 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4270 MINT_IN_CASE(MINT_LDSFLDA
) {
4271 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4272 sp
->data
.p
= mono_class_static_field_address (rtm
->domain
, field
);
4273 EXCEPTION_CHECKPOINT
;
4278 MINT_IN_CASE(MINT_LDSFLD
) {
4279 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4280 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4281 EXCEPTION_CHECKPOINT
;
4282 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
4287 MINT_IN_CASE(MINT_LDSFLD_VT
) {
4288 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4289 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4290 EXCEPTION_CHECKPOINT
;
4291 int size
= READ32 (ip
+ 2);
4295 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4296 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
4300 MINT_IN_CASE(MINT_STSFLD
) {
4301 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4302 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4303 EXCEPTION_CHECKPOINT
;
4306 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
4309 MINT_IN_CASE(MINT_STSFLD_VT
) {
4310 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4311 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4312 EXCEPTION_CHECKPOINT
;
4313 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
4314 i32
= mono_class_value_size (klass
, NULL
);
4318 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
4319 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4322 MINT_IN_CASE(MINT_STOBJ_VT
) {
4324 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4326 size
= mono_class_value_size (c
, NULL
);
4327 memcpy(sp
[-2].data
.p
, sp
[-1].data
.p
, size
);
4328 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4332 MINT_IN_CASE(MINT_STOBJ
) {
4333 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4336 g_assert (!m_class_get_byval_arg (c
)->byref
);
4337 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)))
4338 mono_gc_wbarrier_generic_store (sp
[-2].data
.o
, sp
[-1].data
.o
);
4340 stackval_to_data (m_class_get_byval_arg (c
), &sp
[-1], sp
[-2].data
.p
, FALSE
);
4344 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
4345 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
4346 THROW_EX (mono_get_exception_overflow (), ip
);
4347 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4350 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
4351 if (sp
[-1].data
.i
< 0)
4352 THROW_EX (mono_get_exception_overflow (), ip
);
4353 sp
[-1].data
.l
= sp
[-1].data
.i
;
4356 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
4357 if (sp
[-1].data
.l
< 0)
4358 THROW_EX (mono_get_exception_overflow (), ip
);
4361 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
4362 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
4363 THROW_EX (mono_get_exception_overflow (), ip
);
4366 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
4367 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
)
4368 THROW_EX (mono_get_exception_overflow (), ip
);
4369 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4372 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
4373 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
4374 THROW_EX (mono_get_exception_overflow (), ip
);
4375 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4378 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
4379 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
)
4380 THROW_EX (mono_get_exception_overflow (), ip
);
4381 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4384 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
4385 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
4386 THROW_EX (mono_get_exception_overflow (), ip
);
4387 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4390 MINT_IN_CASE(MINT_BOX
) {
4391 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4392 guint16 offset
= * (guint16
*)(ip
+ 2);
4393 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
4394 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
4396 if (mint_type (m_class_get_byval_arg (c
)) == MINT_TYPE_VT
&& !m_class_is_enumtype (c
) && !(mono_class_is_magic_int (c
) || mono_class_is_magic_float (c
))) {
4397 int size
= mono_class_value_size (c
, NULL
);
4398 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, sp
[-1 - offset
].data
.p
, error
);
4399 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4400 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4404 stackval_to_data (m_class_get_byval_arg (c
), &sp
[-1 - offset
], (char *) &sp
[-1 - offset
], FALSE
);
4405 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, &sp
[-1 - offset
], error
);
4406 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4411 MINT_IN_CASE(MINT_NEWARR
)
4412 sp
[-1].data
.p
= (MonoObject
*) mono_array_new_checked (rtm
->domain
, (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)], sp
[-1].data
.i
, error
);
4413 if (!mono_error_ok (error
)) {
4414 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4416 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4418 /*if (profiling_classes) {
4419 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
4421 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
4425 MINT_IN_CASE(MINT_LDLEN
)
4428 THROW_EX (mono_get_exception_null_reference (), ip
);
4429 sp
[-1].data
.nati
= mono_array_length_fast ((MonoArray
*)o
);
4432 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
4434 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 1);
4436 THROW_EX (mono_get_exception_null_reference (), ip
);
4437 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
4441 MINT_IN_CASE(MINT_GETCHR
) {
4443 s
= (MonoString
*)sp
[-2].data
.p
;
4445 THROW_EX (mono_get_exception_null_reference (), ip
);
4446 i32
= sp
[-1].data
.i
;
4447 if (i32
< 0 || i32
>= mono_string_length (s
))
4448 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4450 sp
[-1].data
.i
= mono_string_chars(s
)[i32
];
4454 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
4455 guint8
*span
= (guint8
*) sp
[-2].data
.p
;
4456 int index
= sp
[-1].data
.i
;
4457 gsize element_size
= (gsize
) *(gint16
*) (ip
+ 1);
4458 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 2);
4459 gsize offset_pointer
= (gsize
) *(gint16
*) (ip
+ 3);
4463 THROW_EX (mono_get_exception_null_reference (), ip
);
4465 gint32 length
= *(gint32
*) (span
+ offset_length
);
4466 if (index
< 0 || index
>= length
)
4467 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4469 gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
4470 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
4475 MINT_IN_CASE(MINT_STRLEN
)
4479 THROW_EX (mono_get_exception_null_reference (), ip
);
4480 sp
[-1].data
.i
= mono_string_length ((MonoString
*) o
);
4482 MINT_IN_CASE(MINT_ARRAY_RANK
)
4485 THROW_EX (mono_get_exception_null_reference (), ip
);
4486 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
4489 MINT_IN_CASE(MINT_LDELEMA
)
4490 MINT_IN_CASE(MINT_LDELEMA_TC
) {
4491 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
4493 MonoClass
*klass
= (MonoClass
*)rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4494 guint16 numargs
= *(guint16
*) (ip
+ 2);
4499 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
4501 THROW_EX (frame
->ex
, ip
);
4506 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
4507 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
4508 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
4509 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
4510 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
4511 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
4512 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
4513 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
4514 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
4515 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
4516 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
4517 MINT_IN_CASE(MINT_LDELEM_VT
) {
4523 o
= (MonoArray
*)sp
[0].data
.p
;
4525 THROW_EX (mono_get_exception_null_reference (), ip
);
4527 aindex
= sp
[1].data
.i
;
4528 if (aindex
>= mono_array_length_fast (o
))
4529 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4532 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4535 case MINT_LDELEM_I1
:
4536 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
4538 case MINT_LDELEM_U1
:
4539 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
4541 case MINT_LDELEM_I2
:
4542 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
4544 case MINT_LDELEM_U2
:
4545 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
4548 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
4550 case MINT_LDELEM_I4
:
4551 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
4553 case MINT_LDELEM_U4
:
4554 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
4556 case MINT_LDELEM_I8
:
4557 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
4559 case MINT_LDELEM_R4
:
4560 sp
[0].data
.f
= mono_array_get_fast (o
, float, aindex
);
4562 case MINT_LDELEM_R8
:
4563 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
4565 case MINT_LDELEM_REF
:
4566 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
4568 case MINT_LDELEM_VT
: {
4569 MonoClass
*klass_vt
= (MonoClass
*)rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4570 i32
= READ32 (ip
+ 2);
4571 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
4572 sp
[0].data
.vt
= vt_sp
;
4573 stackval_from_data (m_class_get_byval_arg (klass_vt
), sp
, src_addr
, FALSE
);
4574 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4586 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
4587 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
4588 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
4589 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
4590 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
4591 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
4592 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
4593 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
4594 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
4595 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
4596 MINT_IN_CASE(MINT_STELEM_VT
) {
4603 THROW_EX (mono_get_exception_null_reference (), ip
);
4605 aindex
= sp
[1].data
.i
;
4606 if (aindex
>= mono_array_length_fast ((MonoArray
*)o
))
4607 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4611 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
4613 case MINT_STELEM_I1
:
4614 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
4616 case MINT_STELEM_U1
:
4617 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
4619 case MINT_STELEM_I2
:
4620 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
4622 case MINT_STELEM_U2
:
4623 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
4625 case MINT_STELEM_I4
:
4626 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
4628 case MINT_STELEM_I8
:
4629 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
4631 case MINT_STELEM_R4
:
4632 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f
);
4634 case MINT_STELEM_R8
:
4635 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
4637 case MINT_STELEM_REF
: {
4638 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
4639 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4640 if (sp
[2].data
.p
&& !isinst_obj
)
4641 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
4642 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
4645 case MINT_STELEM_VT
: {
4646 MonoClass
*klass_vt
= (MonoClass
*)rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4647 i32
= READ32 (ip
+ 2);
4648 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
4650 stackval_to_data (m_class_get_byval_arg (klass_vt
), &sp
[2], dst_addr
, FALSE
);
4651 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4662 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
4663 if (sp
[-1].data
.i
< 0)
4664 THROW_EX (mono_get_exception_overflow (), ip
);
4667 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
4668 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
4669 THROW_EX (mono_get_exception_overflow (), ip
);
4670 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4673 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
4674 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
4675 THROW_EX (mono_get_exception_overflow (), ip
);
4676 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4679 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
4680 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
4681 THROW_EX (mono_get_exception_overflow (), ip
);
4682 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
4685 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
4686 if (sp
[-1].data
.i
< 0)
4687 THROW_EX (mono_get_exception_overflow (), ip
);
4690 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
4691 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
4692 THROW_EX (mono_get_exception_overflow (), ip
);
4693 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
4696 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
4697 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
4698 THROW_EX (mono_get_exception_overflow (), ip
);
4699 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4702 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
4703 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
4704 THROW_EX (mono_get_exception_overflow (), ip
);
4707 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
4708 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
4709 THROW_EX (mono_get_exception_overflow (), ip
);
4712 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
4713 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
4714 THROW_EX (mono_get_exception_overflow (), ip
);
4715 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
4718 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
4719 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
4720 THROW_EX (mono_get_exception_overflow (), ip
);
4721 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
4724 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
4725 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
4726 THROW_EX (mono_get_exception_overflow (), ip
);
4727 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
4730 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
4731 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
4732 THROW_EX (mono_get_exception_overflow (), ip
);
4733 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
4736 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
4737 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
4738 THROW_EX (mono_get_exception_overflow (), ip
);
4741 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
4742 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
4743 THROW_EX (mono_get_exception_overflow (), ip
);
4744 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
4747 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
4748 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
4749 THROW_EX (mono_get_exception_overflow (), ip
);
4750 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
4753 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
4754 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
4755 THROW_EX (mono_get_exception_overflow (), ip
);
4758 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
4759 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
4760 THROW_EX (mono_get_exception_overflow (), ip
);
4763 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
4764 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
4765 THROW_EX (mono_get_exception_overflow (), ip
);
4766 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
4769 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
4770 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
4771 THROW_EX (mono_get_exception_overflow (), ip
);
4772 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
4775 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
4776 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
4777 THROW_EX (mono_get_exception_overflow (), ip
);
4778 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
4781 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
4782 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
4783 THROW_EX (mono_get_exception_overflow (), ip
);
4784 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
4787 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
4788 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
4789 THROW_EX (mono_get_exception_overflow (), ip
);
4792 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
4793 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
4794 THROW_EX (mono_get_exception_overflow (), ip
);
4795 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
4798 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
4799 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
4800 THROW_EX (mono_get_exception_overflow (), ip
);
4801 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
4805 MINT_IN_CASE(MINT_LDELEM
)
4806 MINT_IN_CASE(MINT_STELEM
)
4807 MINT_IN_CASE(MINT_UNBOX_ANY
)
4809 MINT_IN_CASE(MINT_CKFINITE
)
4810 if (!isfinite(sp
[-1].data
.f
))
4811 THROW_EX (mono_get_exception_arithmetic (), ip
);
4814 MINT_IN_CASE(MINT_MKREFANY
) {
4815 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4817 /* The value address is on the stack */
4818 gpointer addr
= sp
[-1].data
.p
;
4819 /* Push the typedref value on the stack */
4820 sp
[-1].data
.p
= vt_sp
;
4821 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
4823 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
4825 tref
->type
= m_class_get_byval_arg (c
);
4831 MINT_IN_CASE(MINT_REFANYTYPE
) {
4832 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
4833 MonoType
*type
= tref
->type
;
4835 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
4836 sp
[-1].data
.p
= vt_sp
;
4838 *(gpointer
*)sp
[-1].data
.p
= type
;
4842 MINT_IN_CASE(MINT_REFANYVAL
) {
4843 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
4844 gpointer addr
= tref
->value
;
4846 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4847 if (c
!= tref
->klass
)
4848 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4850 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
4852 sp
[-1].data
.p
= addr
;
4856 MINT_IN_CASE(MINT_LDTOKEN
)
4859 * (gpointer
*)sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4863 MINT_IN_CASE(MINT_ADD_OVF_I4
)
4864 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4865 THROW_EX (mono_get_exception_overflow (), ip
);
4868 MINT_IN_CASE(MINT_ADD_OVF_I8
)
4869 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4870 THROW_EX (mono_get_exception_overflow (), ip
);
4873 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
4874 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4875 THROW_EX (mono_get_exception_overflow (), ip
);
4876 BINOP_CAST(i
, +, guint32
);
4878 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
4879 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4880 THROW_EX (mono_get_exception_overflow (), ip
);
4881 BINOP_CAST(l
, +, guint64
);
4883 MINT_IN_CASE(MINT_MUL_OVF_I4
)
4884 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4885 THROW_EX (mono_get_exception_overflow (), ip
);
4888 MINT_IN_CASE(MINT_MUL_OVF_I8
)
4889 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4890 THROW_EX (mono_get_exception_overflow (), ip
);
4893 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
4894 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4895 THROW_EX (mono_get_exception_overflow (), ip
);
4896 BINOP_CAST(i
, *, guint32
);
4898 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
4899 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4900 THROW_EX (mono_get_exception_overflow (), ip
);
4901 BINOP_CAST(l
, *, guint64
);
4903 MINT_IN_CASE(MINT_SUB_OVF_I4
)
4904 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4905 THROW_EX (mono_get_exception_overflow (), ip
);
4908 MINT_IN_CASE(MINT_SUB_OVF_I8
)
4909 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4910 THROW_EX (mono_get_exception_overflow (), ip
);
4913 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
4914 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4915 THROW_EX (mono_get_exception_overflow (), ip
);
4916 BINOP_CAST(i
, -, guint32
);
4918 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
4919 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4920 THROW_EX (mono_get_exception_overflow (), ip
);
4921 BINOP_CAST(l
, -, guint64
);
4923 MINT_IN_CASE(MINT_START_ABORT_PROT
)
4924 mono_threads_begin_abort_protected_block ();
4927 MINT_IN_CASE(MINT_ENDFINALLY
) {
4929 int clause_index
= *ip
;
4930 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
4932 if (clause_index
== exit_at_finally
)
4934 while (sp
> frame
->stack
) {
4938 ip
= (const guint16
*)finally_ips
->data
;
4939 finally_ips
= g_slist_remove (finally_ips
, ip
);
4940 /* Throw abort after the last finally block to avoid confusing EH */
4941 if (pending_abort
&& !finally_ips
)
4942 EXCEPTION_CHECKPOINT
;
4949 MINT_IN_CASE(MINT_LEAVE
) /* Fall through */
4950 MINT_IN_CASE(MINT_LEAVE_S
)
4951 while (sp
> frame
->stack
) {
4956 if (*ip
== MINT_LEAVE_S
) {
4957 ip
+= (short) *(ip
+ 1);
4959 ip
+= (gint32
) READ32 (ip
+ 1);
4962 goto handle_finally
;
4964 MINT_IN_CASE(MINT_LEAVE_CHECK
)
4965 MINT_IN_CASE(MINT_LEAVE_S_CHECK
)
4966 while (sp
> frame
->stack
) {
4971 if (frame
->ex_handler
!= NULL
&& MONO_OFFSET_IN_HANDLER(frame
->ex_handler
, frame
->ip
- rtm
->code
)) {
4972 frame
->ex_handler
= NULL
;
4976 if (frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
4979 child_frame
.parent
= frame
;
4980 child_frame
.imethod
= NULL
;
4982 * We need for mono_thread_get_undeniable_exception to be able to unwind
4983 * to check the abort threshold. For this to work we use child_frame as a
4984 * dummy frame that is stored in the lmf and serves as the transition frame
4986 context
->current_frame
= &child_frame
;
4987 do_icall (context
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
);
4988 context
->current_frame
= frame
;
4990 MonoException
*abort_exc
= (MonoException
*)tmp_sp
.data
.p
;
4992 THROW_EX (abort_exc
, frame
->ip
);
4995 if (*ip
== MINT_LEAVE_S_CHECK
) {
4996 ip
+= (short) *(ip
+ 1);
4998 ip
+= (gint32
) READ32 (ip
+ 1);
5001 goto handle_finally
;
5003 MINT_IN_CASE(MINT_ICALL_V_V
)
5004 MINT_IN_CASE(MINT_ICALL_V_P
)
5005 MINT_IN_CASE(MINT_ICALL_P_V
)
5006 MINT_IN_CASE(MINT_ICALL_P_P
)
5007 MINT_IN_CASE(MINT_ICALL_PP_V
)
5008 MINT_IN_CASE(MINT_ICALL_PP_P
)
5009 MINT_IN_CASE(MINT_ICALL_PPP_V
)
5010 MINT_IN_CASE(MINT_ICALL_PPP_P
)
5011 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
5012 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
5013 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
5014 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
5015 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
5016 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
5018 sp
= do_icall (context
, NULL
, *ip
, sp
, rtm
->data_items
[*(guint16
*)(ip
+ 1)]);
5019 EXCEPTION_CHECKPOINT
;
5020 if (context
->has_resume_state
) {
5021 if (frame
== context
->handler_frame
)
5022 SET_RESUME_STATE (context
);
5028 MINT_IN_CASE(MINT_MONO_LDPTR
)
5029 sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
5033 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
5034 sp
->data
.p
= mono_object_new_checked (rtm
->domain
, (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)], error
);
5035 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5039 MINT_IN_CASE(MINT_MONO_FREE
)
5042 g_error ("that doesn't seem right");
5043 g_free (sp
->data
.p
);
5045 MINT_IN_CASE(MINT_MONO_RETOBJ
)
5048 stackval_from_data (mono_method_signature (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
5049 mono_method_signature (frame
->imethod
->method
)->pinvoke
);
5050 if (sp
> frame
->stack
)
5051 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
5053 MINT_IN_CASE(MINT_MONO_TLS
) {
5054 MonoTlsKey key
= (MonoTlsKey
)*(gint32
*)(ip
+ 1);
5055 sp
->data
.p
= ((gpointer (*)(void)) mono_tls_get_tls_getter (key
, FALSE
)) ();
5060 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
5062 mono_memory_barrier ();
5065 MINT_IN_CASE(MINT_MONO_JIT_ATTACH
) {
5068 context
->original_domain
= NULL
;
5069 MonoDomain
*tls_domain
= (MonoDomain
*) mono_tls_get_domain ();
5070 gpointer tls_jit
= mono_tls_get_jit_tls ();
5072 if (tls_domain
!= rtm
->domain
|| !tls_jit
) {
5073 context
->original_domain
= mono_jit_thread_attach (rtm
->domain
);
5075 * Make sure the JitTlsData contains the interp context, in case
5076 * we weren't yet attached at interp_entry time.
5078 g_assert (context
== mono_native_tls_get_value (thread_context_id
));
5079 set_context (context
);
5083 MINT_IN_CASE(MINT_MONO_JIT_DETACH
)
5085 mono_jit_set_domain (context
->original_domain
);
5087 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
5088 sp
->data
.p
= mono_domain_get ();
5092 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
5093 if (G_UNLIKELY (ss_enabled
)) {
5094 typedef void (*T
) (void);
5098 void *tramp
= mini_get_single_step_trampoline ();
5099 mono_memory_barrier ();
5100 ss_tramp
= (T
)tramp
;
5104 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5105 * the address of that instruction is stored as the seq point address.
5110 * Use the same trampoline as the JIT. This ensures that
5111 * the debugger has the context for the last interpreter
5114 do_debugger_tramp (ss_tramp
, frame
);
5116 if (context
->has_resume_state
) {
5117 if (frame
== context
->handler_frame
)
5118 SET_RESUME_STATE (context
);
5125 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
5126 /* Just a placeholder for a breakpoint */
5129 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
5130 typedef void (*T
) (void);
5133 void *tramp
= mini_get_breakpoint_trampoline ();
5134 mono_memory_barrier ();
5135 bp_tramp
= (T
)tramp
;
5140 /* Use the same trampoline as the JIT */
5141 do_debugger_tramp (bp_tramp
, frame
);
5143 if (context
->has_resume_state
) {
5144 if (frame
== context
->handler_frame
)
5145 SET_RESUME_STATE (context
);
5154 #define RELOP(datamem, op) \
5156 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5159 #define RELOP_FP(datamem, op, noorder) \
5161 if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5162 sp [-1].data.i = noorder; \
5164 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5167 MINT_IN_CASE(MINT_CEQ_I4
)
5170 MINT_IN_CASE(MINT_CEQ0_I4
)
5171 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
5174 MINT_IN_CASE(MINT_CEQ_I8
)
5177 MINT_IN_CASE(MINT_CEQ_R8
)
5180 MINT_IN_CASE(MINT_CNE_I4
)
5183 MINT_IN_CASE(MINT_CNE_I8
)
5186 MINT_IN_CASE(MINT_CNE_R8
)
5189 MINT_IN_CASE(MINT_CGT_I4
)
5192 MINT_IN_CASE(MINT_CGT_I8
)
5195 MINT_IN_CASE(MINT_CGT_R8
)
5198 MINT_IN_CASE(MINT_CGE_I4
)
5201 MINT_IN_CASE(MINT_CGE_I8
)
5204 MINT_IN_CASE(MINT_CGE_R8
)
5208 #define RELOP_CAST(datamem, op, type) \
5210 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5213 MINT_IN_CASE(MINT_CGE_UN_I4
)
5214 RELOP_CAST(l
, >=, guint32
);
5216 MINT_IN_CASE(MINT_CGE_UN_I8
)
5217 RELOP_CAST(l
, >=, guint64
);
5220 MINT_IN_CASE(MINT_CGT_UN_I4
)
5221 RELOP_CAST(i
, >, guint32
);
5223 MINT_IN_CASE(MINT_CGT_UN_I8
)
5224 RELOP_CAST(l
, >, guint64
);
5226 MINT_IN_CASE(MINT_CGT_UN_R8
)
5229 MINT_IN_CASE(MINT_CLT_I4
)
5232 MINT_IN_CASE(MINT_CLT_I8
)
5235 MINT_IN_CASE(MINT_CLT_R8
)
5238 MINT_IN_CASE(MINT_CLT_UN_I4
)
5239 RELOP_CAST(i
, <, guint32
);
5241 MINT_IN_CASE(MINT_CLT_UN_I8
)
5242 RELOP_CAST(l
, <, guint64
);
5244 MINT_IN_CASE(MINT_CLT_UN_R8
)
5247 MINT_IN_CASE(MINT_CLE_I4
)
5250 MINT_IN_CASE(MINT_CLE_I8
)
5253 MINT_IN_CASE(MINT_CLE_UN_I4
)
5254 RELOP_CAST(l
, <=, guint32
);
5256 MINT_IN_CASE(MINT_CLE_UN_I8
)
5257 RELOP_CAST(l
, <=, guint64
);
5259 MINT_IN_CASE(MINT_CLE_R8
)
5267 MINT_IN_CASE(MINT_LDFTN
) {
5268 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
5273 MINT_IN_CASE(MINT_LDVIRTFTN
) {
5274 InterpMethod
*m
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
5278 THROW_EX (mono_get_exception_null_reference (), ip
- 2);
5280 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
);
5285 #define LDARG(datamem, argtype) \
5286 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
5290 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
5291 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
5292 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
5293 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
5294 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
5295 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
5296 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f
, float); MINT_IN_BREAK
;
5297 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
5298 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
5299 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
5301 MINT_IN_CASE(MINT_LDARG_VT
)
5303 i32
= READ32(ip
+ 2);
5304 memcpy(sp
->data
.p
, frame
->args
+ * (guint16
*)(ip
+ 1), i32
);
5305 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5310 #define STARG(datamem, argtype) \
5312 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5315 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
5316 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
5317 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
5318 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
5319 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
5320 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
5321 MINT_IN_CASE(MINT_STARG_R4
) STARG(f
, float); MINT_IN_BREAK
;
5322 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
5323 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
5324 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
5326 MINT_IN_CASE(MINT_STARG_VT
)
5327 i32
= READ32(ip
+ 2);
5329 memcpy(frame
->args
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
5330 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5334 #define STINARG(datamem, argtype) \
5336 int n = * (guint16 *)(ip + 1); \
5337 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
5341 MINT_IN_CASE(MINT_STINARG_I1
) STINARG(i
, gint8
); MINT_IN_BREAK
;
5342 MINT_IN_CASE(MINT_STINARG_U1
) STINARG(i
, guint8
); MINT_IN_BREAK
;
5343 MINT_IN_CASE(MINT_STINARG_I2
) STINARG(i
, gint16
); MINT_IN_BREAK
;
5344 MINT_IN_CASE(MINT_STINARG_U2
) STINARG(i
, guint16
); MINT_IN_BREAK
;
5345 MINT_IN_CASE(MINT_STINARG_I4
) STINARG(i
, gint32
); MINT_IN_BREAK
;
5346 MINT_IN_CASE(MINT_STINARG_I8
) STINARG(l
, gint64
); MINT_IN_BREAK
;
5347 MINT_IN_CASE(MINT_STINARG_R4
) STINARG(f
, float); MINT_IN_BREAK
;
5348 MINT_IN_CASE(MINT_STINARG_R8
) STINARG(f
, double); MINT_IN_BREAK
;
5349 MINT_IN_CASE(MINT_STINARG_O
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
5350 MINT_IN_CASE(MINT_STINARG_P
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
5352 MINT_IN_CASE(MINT_STINARG_VT
) {
5353 int n
= * (guint16
*)(ip
+ 1);
5354 i32
= READ32(ip
+ 2);
5355 memcpy (frame
->args
+ rtm
->arg_offsets
[n
], frame
->stack_args
[n
].data
.p
, i32
);
5360 MINT_IN_CASE(MINT_PROF_ENTER
) {
5363 if (MONO_PROFILER_ENABLED (method_enter
)) {
5364 MonoProfilerCallContext
*prof_ctx
= NULL
;
5366 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
5367 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
5368 prof_ctx
->interp_frame
= frame
;
5369 prof_ctx
->method
= frame
->imethod
->method
;
5372 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
5380 MINT_IN_CASE(MINT_LDARGA
)
5381 sp
->data
.p
= frame
->args
+ * (guint16
*)(ip
+ 1);
5386 #define LDLOC(datamem, argtype) \
5387 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
5391 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
5392 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
5393 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
5394 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
5395 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
5396 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
5397 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f
, float); MINT_IN_BREAK
;
5398 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
5399 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
5400 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
5402 MINT_IN_CASE(MINT_LDLOC_VT
)
5404 i32
= READ32(ip
+ 2);
5405 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
5406 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5411 MINT_IN_CASE(MINT_LDLOCA_S
)
5412 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
5417 #define STLOC(datamem, argtype) \
5419 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5422 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
5423 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
5424 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
5425 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
5426 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
5427 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
5428 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f
, float); MINT_IN_BREAK
;
5429 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
5430 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
5431 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
5433 #define STLOC_NP(datamem, argtype) \
5434 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
5437 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
5438 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
5440 MINT_IN_CASE(MINT_STLOC_VT
)
5441 i32
= READ32(ip
+ 2);
5443 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
5444 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5448 MINT_IN_CASE(MINT_LOCALLOC
) {
5449 if (sp
!= frame
->stack
+ 1) /*FIX?*/
5450 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
5452 int len
= sp
[-1].data
.i
;
5453 sp
[-1].data
.p
= alloca (len
);
5455 if (frame
->imethod
->init_locals
)
5456 memset (sp
[-1].data
.p
, 0, len
);
5460 MINT_IN_CASE(MINT_ENDFILTER
)
5461 /* top of stack is result of filter */
5462 frame
->retval
= &sp
[-1];
5464 MINT_IN_CASE(MINT_INITOBJ
)
5466 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
5469 MINT_IN_CASE(MINT_CPBLK
)
5471 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
5472 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
5474 /* FIXME: value and size may be int64... */
5475 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
5478 MINT_IN_CASE(MINT_CONSTRAINED_
) {
5480 /* FIXME: implement */
5482 token
= READ32 (ip
);
5487 MINT_IN_CASE(MINT_INITBLK
)
5490 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
5492 /* FIXME: value and size may be int64... */
5493 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
5496 MINT_IN_CASE(MINT_NO_
)
5497 /* FIXME: implement */
5501 MINT_IN_CASE(MINT_RETHROW
) {
5503 * need to clarify what this should actually do:
5504 * start the search from the last found handler in
5505 * this method or continue in the caller or what.
5506 * Also, do we need to run finally/fault handlers after a retrow?
5507 * Well, this implementation will follow the usual search
5508 * for an handler, considering the current ip as throw spot.
5509 * We need to NULL frame->ex_handler for the later code to
5510 * actually run the new found handler.
5512 int exvar_offset
= *(guint16
*)(ip
+ 1);
5513 frame
->ex_handler
= NULL
;
5514 THROW_EX_GENERAL (*(MonoException
**)(frame
->locals
+ exvar_offset
), ip
- 1, TRUE
);
5517 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
5521 del
= (MonoDelegate
*)sp
->data
.p
;
5522 if (!del
->interp_method
) {
5523 /* Not created from interpreted code */
5525 g_assert (del
->method
);
5526 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
5527 mono_error_assert_ok (error
);
5529 g_assert (del
->interp_method
);
5530 sp
->data
.p
= del
->interp_method
;
5535 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
5537 int n
= *(guint16
*)(ip
+ 1);
5538 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
5539 if (!del
->interp_invoke_impl
) {
5541 * First time we are called. Set up the invoke wrapper. We might be able to do this
5542 * in ctor but we would need to handle AllocDelegateLike_internal separately
5545 MonoMethod
*invoke
= mono_get_delegate_invoke (del
->object
.vtable
->klass
);
5546 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
5547 mono_error_assert_ok (error
);
5550 sp
[-1].data
.p
= del
->interp_invoke_impl
;
5555 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-rtm
->code
);
5556 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip
);
5560 g_assert_not_reached ();
5565 MonoExceptionClause
*clause
;
5566 GSList
*old_list
= finally_ips
;
5567 MonoMethod
*method
= frame
->imethod
->method
;
5571 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- rtm
->code
);
5573 if (rtm
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5574 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5577 ip_offset
= frame
->ip
- rtm
->code
;
5579 if (endfinally_ip
!= NULL
)
5580 finally_ips
= g_slist_prepend(finally_ips
, (void *)endfinally_ip
);
5581 for (i
= 0; i
< rtm
->num_clauses
; ++i
)
5582 if (frame
->ex_handler
== &rtm
->clauses
[i
])
5587 clause
= &rtm
->clauses
[i
];
5588 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- rtm
->code
)))) {
5589 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5590 ip
= rtm
->code
+ clause
->handler_offset
;
5591 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5594 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
5600 endfinally_ip
= NULL
;
5602 if (old_list
!= finally_ips
&& finally_ips
) {
5603 ip
= (const guint16
*)finally_ips
->data
;
5604 finally_ips
= g_slist_remove (finally_ips
, ip
);
5605 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5606 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
5616 memcpy (base_frame
->args
, frame
->args
, rtm
->alloca_size
);
5618 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
5619 frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
5620 MonoProfilerCallContext
*prof_ctx
= NULL
;
5622 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
5623 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
5624 prof_ctx
->interp_frame
= frame
;
5625 prof_ctx
->method
= frame
->imethod
->method
;
5627 MonoType
*rtype
= mono_method_signature (frame
->imethod
->method
)->ret
;
5629 switch (rtype
->type
) {
5630 case MONO_TYPE_VOID
:
5632 case MONO_TYPE_VALUETYPE
:
5633 prof_ctx
->return_value
= frame
->retval
->data
.p
;
5636 prof_ctx
->return_value
= frame
->retval
;
5641 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
5644 } else if (frame
->ex
&& frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
5645 MONO_PROFILER_RAISE (method_exception_leave
, (frame
->imethod
->method
, &frame
->ex
->object
));
5651 interp_parse_options (const char *options
)
5658 args
= g_strsplit (options
, ",", -1);
5659 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
5662 if (strncmp (arg
, "jit=", 4) == 0)
5663 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
5664 if (strncmp (arg
, "interp-only=", 4) == 0)
5665 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
5669 typedef int (*TestMethod
) (void);
5672 * interp_set_resume_state:
5674 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5677 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
5679 ThreadContext
*context
;
5682 context
= (ThreadContext
*)jit_tls
->interp_context
;
5685 context
->has_resume_state
= TRUE
;
5686 context
->handler_frame
= (InterpFrame
*)interp_frame
;
5687 context
->handler_ei
= ei
;
5688 /* This is on the stack, so it doesn't need a wbarrier */
5689 context
->handler_frame
->ex
= ex
;
5692 *(MonoException
**)(context
->handler_frame
->locals
+ ei
->exvar_offset
) = ex
;
5693 context
->handler_ip
= handler_ip
;
5697 * interp_run_finally:
5699 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5700 * frame->interp_frame.
5701 * Return TRUE if the finally clause threw an exception.
5704 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
)
5706 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
5707 ThreadContext
*context
= (ThreadContext
*)mono_native_tls_get_value (thread_context_id
);
5708 const unsigned short *old_ip
= iframe
->ip
;
5711 interp_exec_method_full (iframe
, context
, (guint16
*)handler_ip
, NULL
, clause_index
, NULL
);
5712 if (context
->has_resume_state
) {
5715 iframe
->ip
= old_ip
;
5721 * interp_run_filter:
5723 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
5724 * frame->interp_frame.
5727 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
)
5729 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
5730 ThreadContext
*context
= (ThreadContext
*)mono_native_tls_get_value (thread_context_id
);
5731 InterpFrame child_frame
;
5735 * Have to run the clause in a new frame which is a copy of IFRAME, since
5736 * during debugging, there are two copies of the frame on the stack.
5738 memset (&child_frame
, 0, sizeof (InterpFrame
));
5739 child_frame
.imethod
= iframe
->imethod
;
5740 child_frame
.retval
= &retval
;
5741 child_frame
.parent
= iframe
;
5743 interp_exec_method_full (&child_frame
, context
, (guint16
*)handler_ip
, ex
, clause_index
, iframe
);
5744 /* ENDFILTER stores the result into child_frame->retval */
5745 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
5749 InterpFrame
*current
;
5753 * interp_frame_iter_init:
5755 * Initialize an iterator for iterating through interpreted frames.
5758 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
5760 StackIter
*stack_iter
= (StackIter
*)iter
;
5762 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
5766 * interp_frame_iter_next:
5768 * Fill out FRAME with date for the next interpreter frame.
5771 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
5773 StackIter
*stack_iter
= (StackIter
*)iter
;
5774 InterpFrame
*iframe
= stack_iter
->current
;
5776 memset (frame
, 0, sizeof (StackFrameInfo
));
5777 /* pinvoke frames doesn't have imethod set */
5778 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
5779 iframe
= iframe
->parent
;
5783 MonoMethod
*method
= iframe
->imethod
->method
;
5784 frame
->domain
= iframe
->domain
;
5785 frame
->interp_frame
= iframe
;
5786 frame
->method
= method
;
5787 frame
->actual_method
= method
;
5788 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
5789 frame
->native_offset
= -1;
5790 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
5792 frame
->type
= FRAME_TYPE_INTERP
;
5793 /* This is the offset in the interpreter IR */
5794 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
5795 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
5796 frame
->managed
= TRUE
;
5798 frame
->ji
= iframe
->imethod
->jinfo
;
5799 frame
->frame_addr
= iframe
;
5801 stack_iter
->current
= iframe
->parent
;
5807 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
5811 rtm
= lookup_imethod (domain
, method
);
5819 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
5821 guint16
*code
= (guint16
*)ip
;
5822 g_assert (*code
== MINT_SDB_SEQ_POINT
);
5823 *code
= MINT_SDB_BREAKPOINT
;
5827 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
5829 guint16
*code
= (guint16
*)ip
;
5830 g_assert (*code
== MINT_SDB_BREAKPOINT
);
5831 *code
= MINT_SDB_SEQ_POINT
;
5835 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
5837 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5839 g_assert (iframe
->imethod
);
5840 return iframe
->imethod
->jinfo
;
5844 interp_frame_get_ip (MonoInterpFrameHandle frame
)
5846 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5848 g_assert (iframe
->imethod
);
5849 return (gpointer
)iframe
->ip
;
5853 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
5855 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5857 g_assert (iframe
->imethod
);
5859 int arg_offset
= iframe
->imethod
->arg_offsets
[pos
+ (iframe
->imethod
->hasthis
? 1 : 0)];
5861 return iframe
->args
+ arg_offset
;
5865 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
5867 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5869 g_assert (iframe
->imethod
);
5871 return iframe
->locals
+ iframe
->imethod
->local_offsets
[pos
];
5875 interp_frame_get_this (MonoInterpFrameHandle frame
)
5877 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5879 g_assert (iframe
->imethod
);
5880 g_assert (iframe
->imethod
->hasthis
);
5882 int arg_offset
= iframe
->imethod
->arg_offsets
[0];
5884 return iframe
->args
+ arg_offset
;
5887 static MonoInterpFrameHandle
5888 interp_frame_get_parent (MonoInterpFrameHandle frame
)
5890 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5892 return iframe
->parent
;
5896 interp_start_single_stepping (void)
5902 interp_stop_single_stepping (void)
5908 mono_ee_interp_init (const char *opts
)
5910 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
5911 g_assert (!interp_init_done
);
5912 interp_init_done
= TRUE
;
5914 mono_native_tls_alloc (&thread_context_id
, NULL
);
5917 interp_parse_options (opts
);
5918 mono_interp_transform_init ();
5921 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
5922 c
.entry_from_trampoline
= interp_entry_from_trampoline
;
5924 c
.create_method_pointer
= interp_create_method_pointer
;
5925 c
.runtime_invoke
= interp_runtime_invoke
;
5926 c
.init_delegate
= interp_init_delegate
;
5927 c
.delegate_ctor
= interp_delegate_ctor
;
5928 c
.get_remoting_invoke
= interp_get_remoting_invoke
;
5929 c
.set_resume_state
= interp_set_resume_state
;
5930 c
.run_finally
= interp_run_finally
;
5931 c
.run_filter
= interp_run_filter
;
5932 c
.frame_iter_init
= interp_frame_iter_init
;
5933 c
.frame_iter_next
= interp_frame_iter_next
;
5934 c
.find_jit_info
= interp_find_jit_info
;
5935 c
.set_breakpoint
= interp_set_breakpoint
;
5936 c
.clear_breakpoint
= interp_clear_breakpoint
;
5937 c
.frame_get_jit_info
= interp_frame_get_jit_info
;
5938 c
.frame_get_ip
= interp_frame_get_ip
;
5939 c
.frame_get_arg
= interp_frame_get_arg
;
5940 c
.frame_get_local
= interp_frame_get_local
;
5941 c
.frame_get_this
= interp_frame_get_this
;
5942 c
.frame_get_parent
= interp_frame_get_parent
;
5943 c
.frame_arg_to_data
= interp_frame_arg_to_data
;
5944 c
.data_to_frame_arg
= interp_data_to_frame_arg
;
5945 c
.frame_arg_to_storage
= interp_frame_arg_to_storage
;
5946 c
.frame_arg_set_storage
= interp_frame_arg_set_storage
;
5947 c
.start_single_stepping
= interp_start_single_stepping
;
5948 c
.stop_single_stepping
= interp_stop_single_stepping
;
5949 mini_install_interp_callbacks (&c
);