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>
28 #include <mono/utils/mono-math.h>
34 # define alloca __builtin_alloca
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/metadata/gc-internals.h>
60 #include <mono/utils/atomic.h>
63 #include "interp-internals.h"
66 #include <mono/mini/mini.h>
67 #include <mono/mini/mini-runtime.h>
68 #include <mono/mini/aot-runtime.h>
69 #include <mono/mini/llvm-runtime.h>
70 #include <mono/mini/llvmonly-runtime.h>
71 #include <mono/mini/jit-icalls.h>
72 #include <mono/mini/debugger-agent.h>
73 #include <mono/mini/ee.h>
76 #include <mono/mini/mini-arm.h>
78 #include <mono/metadata/icall-decl.h>
81 #pragma warning(disable:4102) // label' : unreferenced label
84 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
86 /* Where we start the frame execution from */
87 guint16
*start_with_ip
;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
94 /* When exiting this clause we also exit the frame */
96 /* Exception that we are filtering */
97 MonoException
*filter_exception
;
98 InterpFrame
*base_frame
;
102 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
104 frame
->parent
= parent_frame
;
105 frame
->stack_args
= method_args
;
106 frame
->retval
= method_retval
;
107 frame
->imethod
= rmethod
;
110 frame
->invoke_trap
= 0;
113 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
114 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
115 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
118 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL)
121 * List of classes whose methods will be executed by transitioning to JITted code.
124 GSList
*mono_interp_jit_classes
;
125 /* Optimizations enabled with interpreter */
126 int mono_interp_opt
= INTERP_OPT_INLINE
;
127 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
128 static gboolean ss_enabled
;
130 static gboolean interp_init_done
= FALSE
;
132 static char* dump_frame (InterpFrame
*inv
);
133 static MonoArray
*get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
);
134 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
);
135 static InterpMethod
* lookup_method_pointer (gpointer addr
);
137 typedef void (*ICallMethod
) (InterpFrame
*frame
);
139 static MonoNativeTlsKey thread_context_id
;
141 static char* dump_args (InterpFrame
*inv
);
143 #define DEBUG_INTERP 0
146 int mono_interp_traceopt
= 2;
147 /* If true, then we output the opcodes as we interpret them */
148 static int global_tracing
= 2;
150 static int debug_indent_level
= 0;
152 static int break_on_method
= 0;
153 static int nested_trace
= 0;
154 static GList
*db_methods
= NULL
;
161 for (h
= 0; h
< debug_indent_level
; h
++)
166 db_match_method (gpointer data
, gpointer user_data
)
168 MonoMethod
*m
= (MonoMethod
*)user_data
;
169 MonoMethodDesc
*desc
= data
;
171 if (mono_method_desc_full_match (desc
, m
))
176 debug_enter (InterpFrame
*frame
, int *tracing
)
179 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
181 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
185 MonoMethod
*method
= frame
->imethod
->method
;
186 char *mn
, *args
= dump_args (frame
);
187 debug_indent_level
++;
189 mn
= mono_method_full_name (method
, FALSE
);
190 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
192 g_print ("%s)\n", args
);
198 #define DEBUG_LEAVE() \
201 args = dump_retval (frame); \
203 mn = mono_method_full_name (frame->imethod->method, FALSE); \
204 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
206 g_print (" => %s\n", args); \
208 debug_indent_level--; \
209 if (tracing == 3) global_tracing = 0; \
214 int mono_interp_traceopt
= 0;
215 static void debug_enter (InterpFrame
*frame
, int *tracing
)
218 #define DEBUG_LEAVE()
223 set_resume_state (ThreadContext
*context
, InterpFrame
*frame
)
226 context
->has_resume_state
= 0;
227 context
->handler_frame
= NULL
;
228 context
->handler_ei
= NULL
;
231 /* Set the current execution state to the resume state in context */
232 #define SET_RESUME_STATE(context) do { \
233 ip = (const guint16*)(context)->handler_ip; \
234 /* spec says stack should be empty at endfinally so it should be at the start too */ \
236 vt_sp = (unsigned char *) sp + rtm->stack_size; \
238 sp->data.p = frame->ex; \
241 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
242 while (finally_ips && \
243 finally_ips->data >= (context)->handler_ei->try_start && \
244 finally_ips->data < (context)->handler_ei->try_end) \
245 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
246 set_resume_state ((context), (frame)); \
251 * If this bit is set, it means the call has thrown the exception, and we
252 * reached this point because the EH code in mono_handle_exception ()
253 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
254 * has set the fields in context to indicate where we have to resume execution.
256 #define CHECK_RESUME_STATE(context) do { \
257 if ((context)->has_resume_state) { \
258 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
259 SET_RESUME_STATE (context); \
266 set_context (ThreadContext
*context
)
268 mono_native_tls_set_value (thread_context_id
, context
);
273 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
274 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
276 /* jit_tls assumes ownership of 'context' */
277 jit_tls
->interp_context
= context
;
280 static ThreadContext
*
283 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
284 if (context
== NULL
) {
285 context
= g_new0 (ThreadContext
, 1);
286 set_context (context
);
292 ves_real_abort (int line
, MonoMethod
*mh
,
293 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
296 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
297 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
298 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
299 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
300 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
301 mono_metadata_free_mh (header
);
304 #define ves_abort() \
306 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
307 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
311 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
314 MonoJitDomainInfo
*info
;
316 info
= domain_jit_info (domain
);
317 mono_domain_jit_code_hash_lock (domain
);
318 rtm
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
319 mono_domain_jit_code_hash_unlock (domain
);
324 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
326 #ifndef DISABLE_REMOTING
327 InterpMethod
*imethod
;
330 imethod
= lookup_method_pointer (addr
);
333 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
334 return_val_if_nok (error
, NULL
);
337 g_assert (mono_use_interpreter
);
339 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
340 return_val_if_nok (error
, NULL
);
341 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
343 g_assert_not_reached ();
349 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
352 MonoJitDomainInfo
*info
;
353 MonoMethodSignature
*sig
;
358 info
= domain_jit_info (domain
);
359 mono_domain_jit_code_hash_lock (domain
);
360 rtm
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
361 mono_domain_jit_code_hash_unlock (domain
);
365 sig
= mono_method_signature_internal (method
);
367 rtm
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
368 rtm
->method
= method
;
369 rtm
->domain
= domain
;
370 rtm
->param_count
= sig
->param_count
;
371 rtm
->hasthis
= sig
->hasthis
;
372 rtm
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
373 rtm
->rtype
= mini_get_underlying_type (sig
->ret
);
374 rtm
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
375 for (i
= 0; i
< sig
->param_count
; ++i
)
376 rtm
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
378 mono_domain_jit_code_hash_lock (domain
);
379 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
380 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, rtm
);
381 mono_domain_jit_code_hash_unlock (domain
);
383 rtm
->prof_flags
= mono_profiler_get_call_instrumentation_flags (rtm
->method
);
388 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM) || defined (_MSC_VER)
389 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
390 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
392 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
393 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
394 * (registers are not accurate), thus resuming to the label does not work. */
395 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
396 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
398 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
399 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
400 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
401 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
402 MONO_CONTEXT_SET_IP (&(ext).ctx, (exit_addr)); \
403 mono_arch_do_ip_adjustment (&(ext).ctx);
405 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) g_error ("requires working mono-context");
408 /* INTERP_PUSH_LMF_WITH_CTX:
410 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
411 * This is needed to resume into the interp when the exception is thrown from
412 * native code (see ./mono/tests/install_eh_callback.exe).
414 * This must be a macro in order to retrieve the right register values for
417 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_addr) \
418 memset (&(ext), 0, sizeof (MonoLMFExt)); \
419 (ext).interp_exit_data = (frame); \
420 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), (exit_addr)); \
421 mono_push_lmf (&(ext));
426 * Push an LMF frame on the LMF stack
427 * to mark the transition to native code.
428 * This is needed for the native code to
429 * be able to do stack walks.
432 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
434 memset (ext
, 0, sizeof (MonoLMFExt
));
435 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
436 ext
->interp_exit_data
= frame
;
442 interp_pop_lmf (MonoLMFExt
*ext
)
444 mono_pop_lmf (&ext
->lmf
);
448 get_virtual_method (InterpMethod
*imethod
, MonoObject
*obj
)
450 MonoMethod
*m
= imethod
->method
;
451 MonoDomain
*domain
= imethod
->domain
;
452 InterpMethod
*ret
= NULL
;
455 #ifndef DISABLE_REMOTING
456 if (mono_object_is_transparent_proxy (obj
)) {
457 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
458 mono_error_assert_ok (error
);
459 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
460 mono_error_assert_ok (error
);
465 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
466 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
467 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
468 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
475 mono_class_setup_vtable (obj
->vtable
->klass
);
477 int slot
= mono_method_get_vtable_slot (m
);
478 if (mono_class_is_interface (m
->klass
)) {
479 g_assert (obj
->vtable
->klass
!= m
->klass
);
480 /* TODO: interface offset lookup is slow, go through IMT instead */
481 gboolean non_exact_match
;
482 slot
+= mono_class_interface_offset_with_variance (obj
->vtable
->klass
, m
->klass
, &non_exact_match
);
485 MonoMethod
*virtual_method
= m_class_get_vtable (mono_object_class (obj
)) [slot
];
486 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
487 MonoGenericContext context
= { NULL
, NULL
};
489 if (mono_class_is_ginst (virtual_method
->klass
))
490 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
491 else if (mono_class_is_gtd (virtual_method
->klass
))
492 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
493 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
495 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
496 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
499 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
500 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
503 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
504 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
505 return virtual_imethod
;
509 InterpMethod
*imethod
;
510 InterpMethod
*target_imethod
;
513 /* domain lock must be held */
515 append_imethod (MonoDomain
*domain
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
518 InterpVTableEntry
*entry
;
520 entry
= (InterpVTableEntry
*) mono_mempool_alloc (domain
->mp
, sizeof (InterpVTableEntry
));
521 entry
->imethod
= imethod
;
522 entry
->target_imethod
= target_imethod
;
523 ret
= g_slist_append_mempool (domain
->mp
, list
, entry
);
529 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
531 while (list
!= NULL
) {
532 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
533 if (entry
->imethod
== imethod
)
534 return entry
->target_imethod
;
541 get_method_table (MonoObject
*obj
, int offset
)
544 return obj
->vtable
->interp_vtable
;
546 return (gpointer
*)obj
->vtable
;
551 alloc_method_table (MonoObject
*obj
, int offset
)
556 table
= mono_domain_alloc0 (obj
->vtable
->domain
, m_class_get_vtable_size (obj
->vtable
->klass
) * sizeof (gpointer
));
557 obj
->vtable
->interp_vtable
= table
;
559 table
= (gpointer
*)obj
->vtable
;
566 get_virtual_method_fast (MonoObject
*obj
, InterpMethod
*imethod
, int offset
)
570 #ifndef DISABLE_REMOTING
572 if (mono_object_is_transparent_proxy (obj
))
573 return get_virtual_method (imethod
, obj
);
576 table
= get_method_table (obj
, offset
);
579 /* Lazily allocate method table */
580 mono_domain_lock (obj
->vtable
->domain
);
581 table
= get_method_table (obj
, offset
);
583 table
= alloc_method_table (obj
, offset
);
584 mono_domain_unlock (obj
->vtable
->domain
);
587 if (!table
[offset
]) {
588 InterpMethod
*target_imethod
= get_virtual_method (imethod
, obj
);
589 /* Lazily initialize the method table slot */
590 mono_domain_lock (obj
->vtable
->domain
);
591 if (!table
[offset
]) {
592 if (imethod
->method
->is_inflated
|| offset
< 0)
593 table
[offset
] = append_imethod (obj
->vtable
->domain
, NULL
, imethod
, target_imethod
);
595 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
597 mono_domain_unlock (obj
->vtable
->domain
);
600 if ((gsize
)table
[offset
] & 0x1) {
601 /* Non generic virtual call. Only one method in slot */
602 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
604 /* Virtual generic or interface call. Multiple methods in slot */
605 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
607 if (!target_imethod
) {
608 target_imethod
= get_virtual_method (imethod
, obj
);
609 mono_domain_lock (obj
->vtable
->domain
);
610 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
611 table
[offset
] = append_imethod (obj
->vtable
->domain
, (GSList
*)table
[offset
], imethod
, target_imethod
);
612 mono_domain_unlock (obj
->vtable
->domain
);
614 return target_imethod
;
619 stackval_from_data (MonoType
*type_
, stackval
*result
, void *data
, gboolean pinvoke
)
621 MonoType
*type
= mini_native_type_replace_type (type_
);
623 switch (type
->type
) {
624 case MONO_TYPE_OBJECT
:
625 case MONO_TYPE_CLASS
:
626 case MONO_TYPE_STRING
:
627 case MONO_TYPE_ARRAY
:
628 case MONO_TYPE_SZARRAY
:
633 result
->data
.p
= *(gpointer
*)data
;
636 switch (type
->type
) {
640 result
->data
.i
= *(gint8
*)data
;
643 case MONO_TYPE_BOOLEAN
:
644 result
->data
.i
= *(guint8
*)data
;
647 result
->data
.i
= *(gint16
*)data
;
651 result
->data
.i
= *(guint16
*)data
;
654 result
->data
.i
= *(gint32
*)data
;
658 result
->data
.nati
= *(mono_i
*)data
;
661 result
->data
.p
= *(gpointer
*)data
;
664 result
->data
.i
= *(guint32
*)data
;
667 /* memmove handles unaligned case */
668 memmove (&result
->data
.f_r4
, data
, sizeof (float));
672 memmove (&result
->data
.l
, data
, sizeof (gint64
));
675 memmove (&result
->data
.f
, data
, sizeof (double));
677 case MONO_TYPE_STRING
:
678 case MONO_TYPE_SZARRAY
:
679 case MONO_TYPE_CLASS
:
680 case MONO_TYPE_OBJECT
:
681 case MONO_TYPE_ARRAY
:
682 result
->data
.p
= *(gpointer
*)data
;
684 case MONO_TYPE_VALUETYPE
:
685 if (m_class_is_enumtype (type
->data
.klass
)) {
686 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
688 } else if (pinvoke
) {
689 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
691 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
694 case MONO_TYPE_GENERICINST
: {
695 if (mono_type_generic_inst_is_valuetype (type
)) {
696 mono_value_copy_internal (result
->data
.vt
, data
, mono_class_from_mono_type_internal (type
));
699 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
703 g_error ("got type 0x%02x", type
->type
);
708 stackval_to_data (MonoType
*type_
, stackval
*val
, void *data
, gboolean pinvoke
)
710 MonoType
*type
= mini_native_type_replace_type (type_
);
712 gpointer
*p
= (gpointer
*)data
;
716 /* printf ("TODAT0 %p\n", data); */
717 switch (type
->type
) {
720 guint8
*p
= (guint8
*)data
;
724 case MONO_TYPE_BOOLEAN
: {
725 guint8
*p
= (guint8
*)data
;
726 *p
= (val
->data
.i
!= 0);
731 case MONO_TYPE_CHAR
: {
732 guint16
*p
= (guint16
*)data
;
737 mono_i
*p
= (mono_i
*)data
;
738 /* In theory the value used by stloc should match the local var type
739 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
740 a native int - both by csc and mcs). Not sure what to do about sign extension
741 as it is outside the spec... doing the obvious */
742 *p
= (mono_i
)val
->data
.nati
;
746 mono_u
*p
= (mono_u
*)data
;
748 *p
= (mono_u
)val
->data
.nati
;
753 gint32
*p
= (gint32
*)data
;
759 memmove (data
, &val
->data
.l
, sizeof (gint64
));
763 /* memmove handles unaligned case */
764 memmove (data
, &val
->data
.f_r4
, sizeof (float));
768 memmove (data
, &val
->data
.f
, sizeof (double));
771 case MONO_TYPE_STRING
:
772 case MONO_TYPE_SZARRAY
:
773 case MONO_TYPE_CLASS
:
774 case MONO_TYPE_OBJECT
:
775 case MONO_TYPE_ARRAY
: {
776 gpointer
*p
= (gpointer
*) data
;
777 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
780 case MONO_TYPE_PTR
: {
781 gpointer
*p
= (gpointer
*) data
;
785 case MONO_TYPE_VALUETYPE
:
786 if (m_class_is_enumtype (type
->data
.klass
)) {
787 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
789 } else if (pinvoke
) {
790 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
792 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
795 case MONO_TYPE_GENERICINST
: {
796 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
798 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
799 mono_value_copy_internal (data
, val
->data
.vt
, mono_class_from_mono_type_internal (type
));
802 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
806 g_error ("got type %x", type
->type
);
811 * Same as stackval_to_data but return address of storage instead
812 * of copying the value.
815 stackval_to_data_addr (MonoType
*type_
, stackval
*val
)
817 MonoType
*type
= mini_native_type_replace_type (type_
);
821 switch (type
->type
) {
824 case MONO_TYPE_BOOLEAN
:
833 return &val
->data
.nati
;
838 return &val
->data
.f_r4
;
841 case MONO_TYPE_STRING
:
842 case MONO_TYPE_SZARRAY
:
843 case MONO_TYPE_CLASS
:
844 case MONO_TYPE_OBJECT
:
845 case MONO_TYPE_ARRAY
:
848 case MONO_TYPE_VALUETYPE
:
849 if (m_class_is_enumtype (type
->data
.klass
))
850 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
853 case MONO_TYPE_TYPEDBYREF
:
855 case MONO_TYPE_GENERICINST
: {
856 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
858 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
860 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
863 g_error ("got type %x", type
->type
);
869 * Throw an exception from the interpreter.
871 static MONO_NEVER_INLINE
void
872 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, gconstpointer ip
, gboolean rethrow
)
877 interp_push_lmf (&ext
, frame
);
878 frame
->ip
= (const guint16
*)ip
;
881 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
882 MonoException
*mono_ex
= (MonoException
*) ex
;
884 mono_ex
->stack_trace
= NULL
;
885 mono_ex
->trace_ips
= NULL
;
888 mono_error_assert_ok (error
);
891 memset (&ctx
, 0, sizeof (MonoContext
));
892 MONO_CONTEXT_SET_SP (&ctx
, frame
);
895 * Call the JIT EH code. The EH code will call back to us using:
896 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
897 * Since ctx.ip is 0, this will start unwinding from the LMF frame
898 * pushed above, which points to our frames.
900 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
901 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
902 /* We need to unwind into non-interpreter code */
903 mono_restore_context (&ctx
);
904 g_assert_not_reached ();
907 interp_pop_lmf (&ext
);
909 g_assert (context
->has_resume_state
);
913 fill_in_trace (MonoException
*exception
, InterpFrame
*frame
)
916 char *stack_trace
= dump_frame (frame
);
917 MonoDomain
*domain
= frame
->imethod
->domain
;
918 (exception
)->stack_trace
= mono_string_new_checked (domain
, stack_trace
, error
);
919 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
920 (exception
)->trace_ips
= get_trace_ips (domain
, frame
);
921 g_free (stack_trace
);
924 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
926 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
928 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
929 CHECK_RESUME_STATE(context); \
932 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
934 #define EXCEPTION_CHECKPOINT \
936 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (rtm->method)) { \
937 MonoException *exc = mono_thread_interruption_checkpoint (); \
939 THROW_EX (exc, ip); \
945 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
948 intptr_t *lower_bounds
;
952 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
953 for (i
= 0; i
< param_count
; ++i
) {
954 lengths
[i
] = values
->data
.i
;
957 if (m_class_get_rank (klass
) == param_count
) {
958 /* Only lengths provided. */
961 /* lower bounds are first. */
962 lower_bounds
= (intptr_t *) lengths
;
963 lengths
+= m_class_get_rank (klass
);
965 obj
= (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
970 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
972 g_assert (!frame
->ex
);
973 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
977 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
978 guint32 idx
= sp
[i
].data
.i
;
979 guint32 lower
= ao
->bounds
[i
].lower_bound
;
980 guint32 len
= ao
->bounds
[i
].length
;
981 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
982 frame
->ex
= mono_get_exception_index_out_of_range ();
983 FILL_IN_TRACE (frame
->ex
, frame
);
986 pos
= (pos
* len
) + idx
- lower
;
990 if (safe
&& pos
>= ao
->max_length
) {
991 frame
->ex
= mono_get_exception_index_out_of_range ();
992 FILL_IN_TRACE (frame
->ex
, frame
);
1000 ves_array_set (InterpFrame
*frame
, stackval
*sp
, MonoMethodSignature
*sig
)
1002 MonoObject
*o
= sp
->data
.o
;
1003 MonoArray
*ao
= (MonoArray
*) o
;
1004 MonoClass
*ac
= o
->vtable
->klass
;
1006 g_assert (m_class_get_rank (ac
) >= 1);
1008 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, TRUE
);
1012 int val_index
= 1 + m_class_get_rank (ac
);
1013 if (sp
[val_index
].data
.p
&& !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o
)))) {
1015 MonoObject
*isinst
= mono_object_isinst_checked (sp
[val_index
].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
1016 mono_error_cleanup (error
);
1018 frame
->ex
= mono_get_exception_array_type_mismatch ();
1019 FILL_IN_TRACE (frame
->ex
, frame
);
1024 gint32 esize
= mono_array_element_size (ac
);
1025 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1027 MonoType
*mt
= sig
->params
[m_class_get_rank (ac
)];
1028 stackval_to_data (mt
, &sp
[val_index
], ea
, FALSE
);
1032 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1034 MonoObject
*o
= sp
->data
.o
;
1035 MonoArray
*ao
= (MonoArray
*) o
;
1036 MonoClass
*ac
= o
->vtable
->klass
;
1038 g_assert (m_class_get_rank (ac
) >= 1);
1040 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, safe
);
1044 gint32 esize
= mono_array_element_size (ac
);
1045 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1047 MonoType
*mt
= sig
->ret
;
1048 stackval_from_data (mt
, retval
, ea
, FALSE
);
1052 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1054 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1056 g_assert (m_class_get_rank (ac
) >= 1);
1058 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
1062 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), m_class_get_element_class (required_type
))) {
1063 frame
->ex
= mono_get_exception_array_type_mismatch ();
1064 FILL_IN_TRACE (frame
->ex
, frame
);
1067 gint32 esize
= mono_array_element_size (ac
);
1068 return mono_array_addr_with_size_fast (ao
, esize
, pos
);
1071 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1072 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1075 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1076 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1078 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1081 g_assert (mono_arm_eabi_supported ());
1082 int i8_align
= mono_arm_i8_align ();
1092 for (int i
= 0; i
< sig
->param_count
; i
++) {
1093 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1095 case MONO_TYPE_BOOLEAN
:
1096 case MONO_TYPE_CHAR
:
1106 case MONO_TYPE_SZARRAY
:
1107 case MONO_TYPE_CLASS
:
1108 case MONO_TYPE_OBJECT
:
1109 case MONO_TYPE_STRING
:
1110 case MONO_TYPE_VALUETYPE
:
1111 case MONO_TYPE_GENERICINST
:
1112 #if SIZEOF_VOID_P == 8
1118 #if SIZEOF_VOID_P == 4
1122 /* pairs begin at even registers */
1123 if (i8_align
== 8 && margs
->ilen
& 1)
1130 #if SIZEOF_VOID_P == 8
1135 #if SIZEOF_VOID_P == 4
1141 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1145 if (margs
->ilen
> 0)
1146 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1148 if (margs
->flen
> 0)
1149 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1151 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1152 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1154 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1155 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1162 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1166 for (int i
= 0; i
< sig
->param_count
; i
++) {
1167 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1169 case MONO_TYPE_BOOLEAN
:
1170 case MONO_TYPE_CHAR
:
1180 case MONO_TYPE_SZARRAY
:
1181 case MONO_TYPE_CLASS
:
1182 case MONO_TYPE_OBJECT
:
1183 case MONO_TYPE_STRING
:
1184 case MONO_TYPE_VALUETYPE
:
1185 case MONO_TYPE_GENERICINST
:
1186 #if SIZEOF_VOID_P == 8
1190 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1192 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1196 #if SIZEOF_VOID_P == 4
1198 case MONO_TYPE_U8
: {
1199 stackval
*sarg
= &frame
->stack_args
[i
];
1201 /* pairs begin at even registers */
1202 if (i8_align
== 8 && int_i
& 1)
1205 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1207 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1209 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
);
1217 if (ptype
== MONO_TYPE_R4
)
1218 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1220 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1222 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
);
1224 #if SIZEOF_VOID_P == 4
1231 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1235 switch (sig
->ret
->type
) {
1236 case MONO_TYPE_BOOLEAN
:
1237 case MONO_TYPE_CHAR
:
1247 case MONO_TYPE_SZARRAY
:
1248 case MONO_TYPE_CLASS
:
1249 case MONO_TYPE_OBJECT
:
1250 case MONO_TYPE_STRING
:
1253 case MONO_TYPE_VALUETYPE
:
1254 case MONO_TYPE_GENERICINST
:
1255 margs
->retval
= &(frame
->retval
->data
.p
);
1256 margs
->is_float_ret
= 0;
1260 margs
->retval
= &(frame
->retval
->data
.p
);
1261 margs
->is_float_ret
= 1;
1263 case MONO_TYPE_VOID
:
1264 margs
->retval
= NULL
;
1267 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1275 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1277 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1280 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1282 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1286 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1288 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1291 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1292 else if (sig
->hasthis
&& index
== 0)
1293 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1295 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1299 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1301 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1304 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1306 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1310 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1312 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1313 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1314 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1316 switch (type
->type
) {
1317 case MONO_TYPE_GENERICINST
:
1318 if (!MONO_TYPE_IS_REFERENCE (type
))
1319 val
->data
.vt
= storage
;
1321 case MONO_TYPE_VALUETYPE
:
1322 val
->data
.vt
= storage
;
1325 g_assert_not_reached ();
1330 get_interp_to_native_trampoline (void)
1332 static MonoPIFunc trampoline
= NULL
;
1335 if (mono_ee_features
.use_aot_trampolines
) {
1336 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1338 MonoTrampInfo
*info
;
1339 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1341 // mono_tramp_info_register (info, NULL);
1343 mono_memory_barrier ();
1349 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1351 get_interp_to_native_trampoline () (addr
, ccontext
);
1354 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1355 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1356 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
)
1363 g_assert (!frame
->imethod
);
1365 static MonoPIFunc entry_func
= NULL
;
1367 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1369 entry_func
= (MonoPIFunc
) mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper ("mono_interp_to_native_trampoline", (gpointer
) mono_interp_to_native_trampoline
), error
);
1370 mono_error_assert_ok (error
);
1372 entry_func
= get_interp_to_native_trampoline ();
1374 mono_memory_barrier ();
1377 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1378 CallContext ccontext
;
1379 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1382 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1386 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, &&exit_pinvoke
);
1387 entry_func ((gpointer
) addr
, args
);
1388 interp_pop_lmf (&ext
);
1390 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1392 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1394 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1395 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1397 g_free (margs
->iargs
);
1398 g_free (margs
->fargs
);
1401 goto exit_pinvoke
; // prevent unused label warning in some configurations
1407 * interp_init_delegate:
1409 * Initialize del->interp_method.
1412 interp_init_delegate (MonoDelegate
*del
)
1417 if (del
->interp_method
) {
1418 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1419 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1420 } else if (del
->method
) {
1421 /* Delegate created dynamically */
1422 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1424 /* Created from JITted code */
1425 g_assert (del
->method_ptr
);
1426 del
->interp_method
= lookup_method_pointer (del
->method_ptr
);
1427 g_assert (del
->interp_method
);
1430 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1433 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1434 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1435 mono_class_is_abstract (method
->klass
))
1436 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
);
1438 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1439 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1440 const char *name
= method
->name
;
1441 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1443 * When invoking the delegate interp_method is executed directly. If it's an
1444 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1446 * FIXME We should do this later, when we also know the delegate on which the
1447 * target method is called.
1449 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1450 mono_error_assert_ok (error
);
1456 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1459 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1461 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1463 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1464 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1465 /* virtual invoke delegates must not have null check */
1466 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1467 && MONO_HANDLE_IS_NULL (target
)) {
1468 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1473 g_assert (imethod
->method
);
1474 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1475 return_if_nok (error
);
1477 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1479 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1484 * runtime specifies that the implementation of the method is automatically
1485 * provided by the runtime and is primarily used for the methods of delegates.
1487 static MONO_NEVER_INLINE
void
1488 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1490 const char *name
= method
->name
;
1491 mono_class_init_internal (method
->klass
);
1493 if (method
->klass
== mono_defaults
.array_class
) {
1494 if (!strcmp (name
, "UnsafeMov")) {
1495 /* TODO: layout checks */
1496 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1499 if (!strcmp (name
, "UnsafeLoad")) {
1500 ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1503 } else if (mini_class_is_system_array (method
->klass
)) {
1504 MonoObject
*obj
= (MonoObject
*) sp
->data
.p
;
1506 frame
->ex
= mono_get_exception_null_reference ();
1507 FILL_IN_TRACE (frame
->ex
, frame
);
1510 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1511 ves_array_set (frame
, sp
, sig
);
1514 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1515 ves_array_get (frame
, sp
, retval
, sig
, TRUE
);
1520 g_error ("Don't know how to exec runtime method %s.%s::%s",
1521 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1527 dump_stack (stackval
*stack
, stackval
*sp
)
1529 stackval
*s
= stack
;
1530 GString
*str
= g_string_new ("");
1533 return g_string_free (str
, FALSE
);
1536 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1539 return g_string_free (str
, FALSE
);
1544 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1546 switch (type
->type
) {
1553 case MONO_TYPE_CHAR
:
1554 case MONO_TYPE_BOOLEAN
:
1555 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1557 case MONO_TYPE_STRING
:
1558 case MONO_TYPE_SZARRAY
:
1559 case MONO_TYPE_CLASS
:
1560 case MONO_TYPE_OBJECT
:
1561 case MONO_TYPE_ARRAY
:
1565 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1567 case MONO_TYPE_VALUETYPE
:
1568 if (m_class_is_enumtype (type
->data
.klass
))
1569 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1571 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1574 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1577 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1582 GString
*res
= g_string_new ("");
1583 mono_type_get_desc (res
, type
, TRUE
);
1584 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1585 g_string_free (res
, TRUE
);
1593 dump_retval (InterpFrame
*inv
)
1595 GString
*str
= g_string_new ("");
1596 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1598 if (ret
->type
!= MONO_TYPE_VOID
)
1599 dump_stackval (str
, inv
->retval
, ret
);
1601 return g_string_free (str
, FALSE
);
1606 dump_args (InterpFrame
*inv
)
1608 GString
*str
= g_string_new ("");
1610 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1612 if (signature
->param_count
== 0 && !signature
->hasthis
)
1613 return g_string_free (str
, FALSE
);
1615 if (signature
->hasthis
) {
1616 MonoMethod
*method
= inv
->imethod
->method
;
1617 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1620 for (i
= 0; i
< signature
->param_count
; ++i
)
1621 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1623 return g_string_free (str
, FALSE
);
1627 dump_frame (InterpFrame
*inv
)
1629 GString
*str
= g_string_new ("");
1634 for (i
= 0; inv
; inv
= inv
->parent
) {
1635 if (inv
->imethod
!= NULL
) {
1636 MonoMethod
*method
= inv
->imethod
->method
;
1639 const char * opname
= "";
1641 gchar
*source
= NULL
;
1643 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1644 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) == 0) {
1645 MonoMethodHeader
*hd
= mono_method_get_header_checked (method
, error
);
1646 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
1650 opname
= mono_interp_opname
[*inv
->ip
];
1651 codep
= inv
->ip
- inv
->imethod
->code
;
1652 source
= g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method
->name
, codep
);
1657 MonoDebugSourceLocation
*minfo
= mono_debug_lookup_method (method
);
1658 source
= mono_debug_method_lookup_location (minfo
, codep
);
1660 mono_metadata_free_mh (hd
);
1663 args
= dump_args (inv
);
1664 name
= mono_method_full_name (method
, TRUE
);
1666 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i
, codep
, opname
, name
, args
, source
);
1668 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s)\n", i
, codep
, opname
, name
, args
);
1675 return g_string_free (str
, FALSE
);
1679 get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
)
1686 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1687 if (inv
->imethod
!= NULL
)
1690 res
= mono_array_new_checked (domain
, mono_defaults
.int_class
, 3 * i
, error
);
1691 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
1693 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1694 if (inv
->imethod
!= NULL
) {
1695 mono_array_set_fast (res
, gpointer
, i
, inv
->imethod
);
1697 mono_array_set_fast (res
, gpointer
, i
, (gpointer
)inv
->ip
);
1699 mono_array_set_fast (res
, gpointer
, i
, NULL
);
1706 #define CHECK_ADD_OVERFLOW(a,b) \
1707 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1708 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1710 #define CHECK_SUB_OVERFLOW(a,b) \
1711 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1712 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1714 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1715 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1717 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1718 (guint32)(a) < (guint32)(b) ? -1 : 0
1720 #define CHECK_ADD_OVERFLOW64(a,b) \
1721 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1722 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1724 #define CHECK_SUB_OVERFLOW64(a,b) \
1725 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1726 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1728 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1729 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1731 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1732 (guint64)(a) < (guint64)(b) ? -1 : 0
1734 #if SIZEOF_VOID_P == 4
1735 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1736 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1738 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1739 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1742 /* Resolves to TRUE if the operands would overflow */
1743 #define CHECK_MUL_OVERFLOW(a,b) \
1744 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1745 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1746 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1747 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1748 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1749 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1750 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1752 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1753 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1754 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1756 #define CHECK_MUL_OVERFLOW64(a,b) \
1757 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1758 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1759 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1760 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1761 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1762 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1763 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1765 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1766 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1767 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1769 #if SIZEOF_VOID_P == 4
1770 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1771 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1773 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1774 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1778 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1781 ThreadContext
*context
= get_context ();
1782 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1783 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1785 MonoMethod
*target_method
= method
;
1793 MonoDomain
*domain
= mono_domain_get ();
1795 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1796 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1797 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1799 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1801 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1805 args
[0].data
.p
= obj
;
1807 args
[0].data
.p
= NULL
;
1808 args
[1].data
.p
= params
;
1809 args
[2].data
.p
= exc
;
1810 args
[3].data
.p
= target_method
;
1812 INIT_FRAME (&frame
, NULL
, args
, &result
, domain
, invoke_wrapper
, error
);
1815 frame
.invoke_trap
= 1;
1817 interp_exec_method (&frame
, context
);
1821 *exc
= (MonoObject
*) frame
.ex
;
1824 mono_error_set_exception_instance (error
, frame
.ex
);
1827 return (MonoObject
*)result
.data
.p
;
1831 InterpMethod
*rmethod
;
1835 gpointer
*many_args
;
1838 /* Main function for entering the interpreter from compiled code */
1840 interp_entry (InterpEntryData
*data
)
1843 InterpMethod
*rmethod
;
1844 ThreadContext
*context
;
1848 MonoMethodSignature
*sig
;
1850 gpointer orig_domain
, attach_cookie
;
1853 if ((gsize
)data
->rmethod
& 1) {
1855 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1856 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1858 rmethod
= data
->rmethod
;
1860 if (rmethod
->needs_thread_attach
)
1861 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1863 context
= get_context ();
1865 method
= rmethod
->method
;
1866 sig
= mono_method_signature_internal (method
);
1868 // FIXME: Optimize this
1870 //printf ("%s\n", mono_method_full_name (method, 1));
1874 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1876 args
[0].data
.p
= data
->this_arg
;
1879 if (data
->many_args
)
1880 params
= data
->many_args
;
1882 params
= data
->args
;
1883 for (i
= 0; i
< sig
->param_count
; ++i
) {
1884 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1885 if (sig
->params
[i
]->byref
) {
1886 args
[a_index
].data
.p
= params
[i
];
1889 type
= rmethod
->param_types
[i
];
1890 switch (type
->type
) {
1891 case MONO_TYPE_VALUETYPE
:
1892 args
[a_index
].data
.p
= params
[i
];
1894 case MONO_TYPE_GENERICINST
:
1895 if (MONO_TYPE_IS_REFERENCE (type
))
1896 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1898 args
[a_index
].data
.vt
= params
[i
];
1901 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1906 memset (&result
, 0, sizeof (result
));
1907 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1909 type
= rmethod
->rtype
;
1910 switch (type
->type
) {
1911 case MONO_TYPE_GENERICINST
:
1912 if (!MONO_TYPE_IS_REFERENCE (type
))
1913 frame
.retval
->data
.vt
= data
->res
;
1915 case MONO_TYPE_VALUETYPE
:
1916 frame
.retval
->data
.vt
= data
->res
;
1922 interp_exec_method (&frame
, context
);
1924 if (rmethod
->needs_thread_attach
)
1925 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
1928 g_assert (frame
.ex
== NULL
);
1930 type
= rmethod
->rtype
;
1931 switch (type
->type
) {
1932 case MONO_TYPE_VOID
:
1934 case MONO_TYPE_OBJECT
:
1935 /* No need for a write barrier */
1936 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1938 case MONO_TYPE_GENERICINST
:
1939 if (MONO_TYPE_IS_REFERENCE (type
)) {
1940 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1942 /* Already set before the call */
1945 case MONO_TYPE_VALUETYPE
:
1946 /* Already set before the call */
1949 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1954 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1955 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
1956 do_icall (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
)
1959 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, &&exit_icall
);
1962 case MINT_ICALL_V_V
: {
1963 typedef void (*T
)(void);
1968 case MINT_ICALL_V_P
: {
1969 typedef gpointer (*T
)(void);
1972 sp
[-1].data
.p
= func ();
1975 case MINT_ICALL_P_V
: {
1976 typedef void (*T
)(gpointer
);
1978 func (sp
[-1].data
.p
);
1982 case MINT_ICALL_P_P
: {
1983 typedef gpointer (*T
)(gpointer
);
1985 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1988 case MINT_ICALL_PP_V
: {
1989 typedef void (*T
)(gpointer
,gpointer
);
1992 func (sp
[0].data
.p
, sp
[1].data
.p
);
1995 case MINT_ICALL_PP_P
: {
1996 typedef gpointer (*T
)(gpointer
,gpointer
);
1999 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
2002 case MINT_ICALL_PPP_V
: {
2003 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
2006 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2009 case MINT_ICALL_PPP_P
: {
2010 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
2013 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
2016 case MINT_ICALL_PPPP_V
: {
2017 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2020 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
2023 case MINT_ICALL_PPPP_P
: {
2024 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2027 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2030 case MINT_ICALL_PPPPP_V
: {
2031 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2034 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
2037 case MINT_ICALL_PPPPP_P
: {
2038 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2041 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
);
2044 case MINT_ICALL_PPPPPP_V
: {
2045 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2048 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
);
2051 case MINT_ICALL_PPPPPP_P
: {
2052 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2055 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
);
2059 g_assert_not_reached ();
2062 /* convert the native representation to the stackval representation */
2064 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2066 interp_pop_lmf (&ext
);
2068 goto exit_icall
; // prevent unused label warning in some configurations
2075 gpointer jit_wrapper
;
2077 MonoFtnDesc
*ftndesc
;
2081 jit_call_cb (gpointer arg
)
2083 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2084 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2085 int pindex
= cb_data
->pindex
;
2086 gpointer
*args
= cb_data
->args
;
2087 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2091 typedef void (*T
)(gpointer
);
2092 T func
= (T
)jit_wrapper
;
2098 typedef void (*T
)(gpointer
, gpointer
);
2099 T func
= (T
)jit_wrapper
;
2101 func (args
[0], &ftndesc
);
2105 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2106 T func
= (T
)jit_wrapper
;
2108 func (args
[0], args
[1], &ftndesc
);
2112 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2113 T func
= (T
)jit_wrapper
;
2115 func (args
[0], args
[1], args
[2], &ftndesc
);
2119 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2120 T func
= (T
)jit_wrapper
;
2122 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2126 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2127 T func
= (T
)jit_wrapper
;
2129 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2133 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2134 T func
= (T
)jit_wrapper
;
2136 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2140 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2141 T func
= (T
)jit_wrapper
;
2143 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2147 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2148 T func
= (T
)jit_wrapper
;
2150 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2154 g_assert_not_reached ();
2159 static MONO_NEVER_INLINE stackval
*
2160 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2162 MonoMethodSignature
*sig
;
2163 MonoFtnDesc ftndesc
;
2164 guint8 res_buf
[256];
2168 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2171 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2172 * by ref and return a return value using an explicit return value argument.
2174 if (!rmethod
->jit_wrapper
) {
2175 MonoMethod
*method
= rmethod
->method
;
2177 sig
= mono_method_signature_internal (method
);
2180 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2181 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2183 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2184 mono_error_assert_ok (error
);
2186 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2187 return_val_if_nok (error
, NULL
);
2190 rmethod
->jit_addr
= addr
;
2191 rmethod
->jit_sig
= sig
;
2192 mono_memory_barrier ();
2193 rmethod
->jit_wrapper
= jit_wrapper
;
2196 sig
= rmethod
->jit_sig
;
2199 sp
-= sig
->param_count
;
2203 ftndesc
.addr
= rmethod
->jit_addr
;
2206 // FIXME: Optimize this
2210 int stack_index
= 0;
2211 if (rmethod
->hasthis
) {
2212 args
[pindex
++] = sp
[0].data
.p
;
2215 type
= rmethod
->rtype
;
2216 if (type
->type
!= MONO_TYPE_VOID
) {
2217 if (MONO_TYPE_ISSTRUCT (type
))
2218 args
[pindex
++] = vt_sp
;
2220 args
[pindex
++] = res_buf
;
2222 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2223 MonoType
*t
= rmethod
->param_types
[i
];
2224 stackval
*sval
= &sp
[stack_index
+ i
];
2225 if (sig
->params
[i
]->byref
) {
2226 args
[pindex
++] = sval
->data
.p
;
2227 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2228 args
[pindex
++] = sval
->data
.p
;
2229 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2230 args
[pindex
++] = &sval
->data
.p
;
2239 case MONO_TYPE_VALUETYPE
:
2240 args
[pindex
++] = &sval
->data
.i
;
2243 case MONO_TYPE_FNPTR
:
2246 case MONO_TYPE_OBJECT
:
2247 args
[pindex
++] = &sval
->data
.p
;
2251 args
[pindex
++] = &sval
->data
.l
;
2254 args
[pindex
++] = &sval
->data
.f_r4
;
2257 args
[pindex
++] = &sval
->data
.f
;
2260 printf ("%s\n", mono_type_full_name (t
));
2261 g_assert_not_reached ();
2266 interp_push_lmf (&ext
, frame
);
2268 JitCallCbData cb_data
;
2269 memset (&cb_data
, 0, sizeof (cb_data
));
2270 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2271 cb_data
.pindex
= pindex
;
2272 cb_data
.args
= args
;
2273 cb_data
.ftndesc
= &ftndesc
;
2275 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2276 /* Catch the exception thrown by the native code using a try-catch */
2277 gboolean thrown
= FALSE
;
2278 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2279 interp_pop_lmf (&ext
);
2281 MonoObject
*obj
= mono_llvm_load_exception ();
2283 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2287 jit_call_cb (&cb_data
);
2288 interp_pop_lmf (&ext
);
2291 MonoType
*rtype
= rmethod
->rtype
;
2292 switch (rtype
->type
) {
2293 case MONO_TYPE_VOID
:
2294 case MONO_TYPE_OBJECT
:
2295 case MONO_TYPE_STRING
:
2296 case MONO_TYPE_CLASS
:
2297 case MONO_TYPE_ARRAY
:
2298 case MONO_TYPE_SZARRAY
:
2302 sp
->data
.p
= *(gpointer
*)res_buf
;
2305 sp
->data
.i
= *(gint8
*)res_buf
;
2308 sp
->data
.i
= *(guint8
*)res_buf
;
2311 sp
->data
.i
= *(gint16
*)res_buf
;
2314 sp
->data
.i
= *(guint16
*)res_buf
;
2317 sp
->data
.i
= *(gint32
*)res_buf
;
2320 sp
->data
.i
= *(guint32
*)res_buf
;
2323 sp
->data
.l
= *(gint64
*)res_buf
;
2326 sp
->data
.l
= *(guint64
*)res_buf
;
2329 sp
->data
.f_r4
= *(float*)res_buf
;
2332 sp
->data
.f
= *(double*)res_buf
;
2334 case MONO_TYPE_TYPEDBYREF
:
2335 case MONO_TYPE_VALUETYPE
:
2336 /* The result was written to vt_sp */
2339 case MONO_TYPE_GENERICINST
:
2340 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2341 sp
->data
.p
= *(gpointer
*)res_buf
;
2343 /* The result was written to vt_sp */
2348 g_print ("%s\n", mono_type_full_name (rtype
));
2349 g_assert_not_reached ();
2356 static MONO_NEVER_INLINE
void
2357 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2360 interp_push_lmf (&ext
, frame
);
2362 interp_pop_lmf (&ext
);
2365 static MONO_NEVER_INLINE
void
2366 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2369 /* Don't push lmf if we have no interp data */
2370 gboolean push_lmf
= frame
->parent
!= NULL
;
2373 /* Use the parent frame as the current frame is not complete yet */
2375 interp_push_lmf (&ext
, frame
->parent
);
2377 mono_interp_transform_method (frame
->imethod
, context
, error
);
2378 frame
->ex
= mono_error_convert_to_exception (error
);
2381 interp_pop_lmf (&ext
);
2385 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, unsigned char **vt_sp
)
2387 char *vt
= *(char**)vt_sp
;
2388 stackval
*first_arg
= sp
- csig
->param_count
;
2391 * We need to have the varargs linearly on the stack so the ArgIterator
2392 * can iterate over them. We pass the signature first and then copy them
2393 * one by one on the vtstack.
2395 *(gpointer
*)vt
= csig
;
2396 vt
+= sizeof (gpointer
);
2398 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2399 int align
, arg_size
;
2400 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2401 vt
= (char*)ALIGN_PTR_TO (vt
, align
);
2403 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt
, FALSE
);
2407 vt
= (char*)ALIGN_PTR_TO (vt
, MINT_VT_ALIGNMENT
);
2409 *(char**)vt_sp
= vt
;
2413 * These functions are the entry points into the interpreter from compiled code.
2414 * They are called by the interp_in wrappers. They have the following signature:
2415 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2416 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2417 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2418 * more wrappers then these functions.
2419 * this/static * ret/void * 16 arguments -> 64 functions.
2422 #define MAX_INTERP_ENTRY_ARGS 8
2424 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2425 InterpEntryData data; \
2426 (data).rmethod = (_method); \
2427 (data).res = (_res); \
2428 (data).this_arg = (_this_arg); \
2429 (data).many_args = NULL;
2431 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2432 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2433 interp_entry (&data); \
2435 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2436 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2437 (data).args [0] = arg1; \
2438 interp_entry (&data); \
2440 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2441 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2442 (data).args [0] = arg1; \
2443 (data).args [1] = arg2; \
2444 interp_entry (&data); \
2446 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2447 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2448 (data).args [0] = arg1; \
2449 (data).args [1] = arg2; \
2450 (data).args [2] = arg3; \
2451 interp_entry (&data); \
2453 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2454 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2455 (data).args [0] = arg1; \
2456 (data).args [1] = arg2; \
2457 (data).args [2] = arg3; \
2458 (data).args [3] = arg4; \
2459 interp_entry (&data); \
2461 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2462 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2463 (data).args [0] = arg1; \
2464 (data).args [1] = arg2; \
2465 (data).args [2] = arg3; \
2466 (data).args [3] = arg4; \
2467 (data).args [4] = arg5; \
2468 interp_entry (&data); \
2470 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2471 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2472 (data).args [0] = arg1; \
2473 (data).args [1] = arg2; \
2474 (data).args [2] = arg3; \
2475 (data).args [3] = arg4; \
2476 (data).args [4] = arg5; \
2477 (data).args [5] = arg6; \
2478 interp_entry (&data); \
2480 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2481 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2482 (data).args [0] = arg1; \
2483 (data).args [1] = arg2; \
2484 (data).args [2] = arg3; \
2485 (data).args [3] = arg4; \
2486 (data).args [4] = arg5; \
2487 (data).args [5] = arg6; \
2488 (data).args [6] = arg7; \
2489 interp_entry (&data); \
2491 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2492 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2493 (data).args [0] = arg1; \
2494 (data).args [1] = arg2; \
2495 (data).args [2] = arg3; \
2496 (data).args [3] = arg4; \
2497 (data).args [4] = arg5; \
2498 (data).args [5] = arg6; \
2499 (data).args [6] = arg7; \
2500 (data).args [7] = arg8; \
2501 interp_entry (&data); \
2504 #define ARGLIST0 InterpMethod *rmethod
2505 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2506 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2507 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2508 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2509 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2510 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2511 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2512 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2514 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2515 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2516 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2517 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2518 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2519 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2520 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2521 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2522 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2523 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2524 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2525 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2526 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2527 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2528 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2529 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2530 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2531 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2532 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2533 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2534 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2535 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2536 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2537 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2538 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2539 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2540 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2541 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2542 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2543 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2544 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2545 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2546 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2547 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2548 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2549 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2551 #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
2553 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2554 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2555 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2556 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2558 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2560 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2562 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2563 data
.many_args
= args
;
2564 interp_entry (&data
);
2567 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2569 // inline so we can alloc on stack
2570 #define alloc_storage_for_stackval(s, t, p) do { \
2571 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2572 (s)->data.vt = alloca (mono_class_value_size ((t)->data.generic_class->container_class, NULL)); \
2573 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2575 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2577 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2582 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2585 ThreadContext
*context
;
2589 MonoMethodSignature
*sig
;
2590 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2591 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2592 gpointer orig_domain
= NULL
, attach_cookie
;
2595 if (rmethod
->needs_thread_attach
)
2596 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2598 context
= get_context ();
2600 method
= rmethod
->method
;
2601 sig
= mono_method_signature_internal (method
);
2605 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2607 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2609 /* Allocate storage for value types */
2610 for (i
= 0; i
< sig
->param_count
; i
++) {
2611 MonoType
*type
= sig
->params
[i
];
2612 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2615 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2616 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2618 /* Copy the args saved in the trampoline to the frame stack */
2619 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2621 interp_exec_method (&frame
, context
);
2623 if (rmethod
->needs_thread_attach
)
2624 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2627 g_assert (frame
.ex
== NULL
);
2629 /* Write back the return value */
2630 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2632 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2634 static InterpMethod
*
2635 lookup_method_pointer (gpointer addr
)
2637 MonoDomain
*domain
= mono_domain_get ();
2638 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2639 InterpMethod
*res
= NULL
;
2641 mono_domain_lock (domain
);
2642 if (info
->interp_method_pointer_hash
)
2643 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2644 mono_domain_unlock (domain
);
2649 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2651 interp_no_native_to_managed (void)
2653 g_error ("interpreter: native-to-managed transition not available on this platform");
2658 no_llvmonly_interp_method_pointer (void)
2660 g_assert_not_reached ();
2664 * interp_create_method_pointer_llvmonly:
2666 * Return an ftndesc for entering the interpreter and executing METHOD.
2669 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2671 MonoDomain
*domain
= mono_domain_get ();
2672 gpointer addr
, entry_func
, entry_wrapper
;
2673 MonoMethodSignature
*sig
;
2674 MonoMethod
*wrapper
;
2675 MonoJitDomainInfo
*info
;
2676 InterpMethod
*imethod
;
2678 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2679 return_val_if_nok (error
, NULL
);
2682 if (imethod
->llvmonly_unbox_entry
)
2683 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2685 if (imethod
->jit_entry
)
2686 return (MonoFtnDesc
*)imethod
->jit_entry
;
2689 sig
= mono_method_signature_internal (method
);
2692 * The entry functions need access to the method to call, so we have
2693 * to use a ftndesc. The caller uses a normal signature, while the
2694 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2695 * a gsharedvt_in_sig wrapper.
2697 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2699 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2700 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2701 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2702 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2704 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2705 g_assert_not_reached ();
2706 //entry_func = (gpointer)interp_entry_general;
2707 } else if (sig
->hasthis
) {
2708 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2709 entry_func
= entry_funcs_instance
[sig
->param_count
];
2711 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2713 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2714 entry_func
= entry_funcs_static
[sig
->param_count
];
2716 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2718 g_assert (entry_func
);
2720 /* Encode unbox in the lower bit of imethod */
2721 gpointer entry_arg
= imethod
;
2723 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2724 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2726 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2728 info
= domain_jit_info (domain
);
2729 mono_domain_lock (domain
);
2730 if (!info
->interp_method_pointer_hash
)
2731 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2732 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2733 mono_domain_unlock (domain
);
2735 mono_memory_barrier ();
2737 imethod
->llvmonly_unbox_entry
= addr
;
2739 imethod
->jit_entry
= addr
;
2741 return (MonoFtnDesc
*)addr
;
2745 * interp_create_method_pointer:
2747 * Return a function pointer which can be used to call METHOD using the
2748 * interpreter. Return NULL for methods which are not supported.
2751 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2753 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2755 return (gpointer
)no_llvmonly_interp_method_pointer
;
2756 return (gpointer
)interp_no_native_to_managed
;
2758 gpointer addr
, entry_func
, entry_wrapper
;
2759 MonoDomain
*domain
= mono_domain_get ();
2760 MonoJitDomainInfo
*info
;
2761 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2764 return (gpointer
)no_llvmonly_interp_method_pointer
;
2767 /* Return any errors from method compilation */
2768 mono_interp_transform_method (imethod
, get_context (), error
);
2769 return_val_if_nok (error
, NULL
);
2772 if (imethod
->jit_entry
)
2773 return imethod
->jit_entry
;
2775 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2778 /* The caller should call interp_create_method_pointer_llvmonly */
2779 g_assert_not_reached ();
2781 /* HACK: method_ptr of delegate should point to a runtime method*/
2782 if (method
->wrapper_type
&& (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
||
2783 (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)))
2786 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2787 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2789 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2790 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2791 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2792 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2794 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2795 entry_func
= (gpointer
)interp_entry_general
;
2796 } else if (sig
->hasthis
) {
2797 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2798 entry_func
= entry_funcs_instance
[sig
->param_count
];
2800 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2802 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2803 entry_func
= entry_funcs_static
[sig
->param_count
];
2805 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2807 g_assert (entry_func
);
2809 if (!mono_native_to_interp_trampoline
) {
2810 if (mono_aot_only
) {
2811 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2813 MonoTrampInfo
*info
;
2814 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2815 mono_tramp_info_register (info
, NULL
);
2818 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2819 /* We need the lmf wrapper only when being called from mixed mode */
2821 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2823 static gpointer cached_func
= NULL
;
2825 cached_func
= mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper ("mono_interp_entry_from_trampoline", (gpointer
) mono_interp_entry_from_trampoline
), error
);
2826 mono_memory_barrier ();
2828 entry_func
= cached_func
;
2831 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2832 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2833 ftndesc
->addr
= entry_func
;
2834 ftndesc
->arg
= imethod
;
2835 mono_error_assert_ok (error
);
2838 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2839 * rgctx register using a trampoline.
2842 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2844 info
= domain_jit_info (domain
);
2845 mono_domain_lock (domain
);
2846 if (!info
->interp_method_pointer_hash
)
2847 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2848 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2849 mono_domain_unlock (domain
);
2851 mono_memory_barrier ();
2852 imethod
->jit_entry
= addr
;
2859 static int opcode_counts
[512];
2861 #define COUNT_OP(op) opcode_counts[op]++
2863 #define COUNT_OP(op)
2867 #define DUMP_INSTR() \
2868 if (tracing > 1) { \
2870 if (sp > frame->stack) { \
2871 ins = dump_stack (frame->stack, sp); \
2873 ins = g_strdup (""); \
2877 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2878 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2879 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2885 #define DUMP_INSTR()
2889 #define USE_COMPUTED_GOTO 1
2891 #if USE_COMPUTED_GOTO
2892 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2893 #define MINT_IN_CASE(x) LAB_ ## x:
2895 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2897 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2899 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2901 #define MINT_IN_SWITCH(op) switch (op)
2902 #define MINT_IN_CASE(x) case x:
2903 #define MINT_IN_BREAK break
2904 #define MINT_IN_DEFAULT default:
2908 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2909 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2912 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
)
2914 InterpFrame child_frame
;
2915 GSList
*finally_ips
= NULL
;
2916 const unsigned short *endfinally_ip
= NULL
;
2917 const unsigned short *ip
= NULL
;
2919 InterpMethod
*rtm
= NULL
;
2921 gint tracing
= global_tracing
;
2922 unsigned char *vtalloc
;
2927 unsigned char *vt_sp
;
2928 unsigned char *locals
= NULL
;
2930 MonoObject
*o
= NULL
;
2932 #if USE_COMPUTED_GOTO
2933 static void *in_labels
[] = {
2934 #define OPDEF(a,b,c,d) \
2936 #include "mintops.def"
2943 debug_enter (frame
, &tracing
);
2945 rtm
= frame
->imethod
;
2946 if (!frame
->imethod
->transformed
) {
2948 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
2949 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2953 do_transform_method (frame
, context
);
2955 THROW_EX (frame
->ex
, NULL
);
2956 EXCEPTION_CHECKPOINT
;
2960 frame
->args
= g_newa (char, rtm
->alloca_size
);
2961 memset (frame
->args
, 0, rtm
->alloca_size
);
2965 ip
= clause_args
->start_with_ip
;
2966 if (clause_args
->base_frame
) {
2967 frame
->args
= g_newa (char, rtm
->alloca_size
);
2968 memcpy (frame
->args
, clause_args
->base_frame
->args
, rtm
->alloca_size
);
2971 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2972 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2976 locals
= (unsigned char *) vt_sp
+ rtm
->vt_stack_size
;
2977 frame
->locals
= locals
;
2978 child_frame
.parent
= frame
;
2980 if (clause_args
&& clause_args
->filter_exception
) {
2981 sp
->data
.p
= clause_args
->filter_exception
;
2985 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2988 * using while (ip < end) may result in a 15% performance drop,
2989 * but it may be useful for debug
2993 /* g_assert (sp >= frame->stack); */
2994 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2996 MINT_IN_SWITCH (*ip
) {
2997 MINT_IN_CASE(MINT_INITLOCALS
)
2998 memset (locals
, 0, rtm
->locals_size
);
3001 MINT_IN_CASE(MINT_NOP
)
3004 MINT_IN_CASE(MINT_NIY
)
3005 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3007 MINT_IN_CASE(MINT_BREAK
)
3009 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3011 MINT_IN_CASE(MINT_BREAKPOINT
)
3015 MINT_IN_CASE(MINT_LDNULL
)
3020 MINT_IN_CASE(MINT_ARGLIST
)
3021 g_assert (frame
->varargs
);
3023 *(gpointer
*)sp
->data
.p
= frame
->varargs
;
3024 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3028 MINT_IN_CASE(MINT_VTRESULT
) {
3029 int ret_size
= * (guint16
*)(ip
+ 1);
3030 unsigned char *ret_vt_sp
= vt_sp
;
3031 vt_sp
-= READ32(ip
+ 2);
3033 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3034 sp
[-1].data
.p
= vt_sp
;
3035 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3040 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3041 MINT_IN_CASE(MINT_LDC_I4_M1
)
3044 MINT_IN_CASE(MINT_LDC_I4_0
)
3047 MINT_IN_CASE(MINT_LDC_I4_1
)
3050 MINT_IN_CASE(MINT_LDC_I4_2
)
3053 MINT_IN_CASE(MINT_LDC_I4_3
)
3056 MINT_IN_CASE(MINT_LDC_I4_4
)
3059 MINT_IN_CASE(MINT_LDC_I4_5
)
3062 MINT_IN_CASE(MINT_LDC_I4_6
)
3065 MINT_IN_CASE(MINT_LDC_I4_7
)
3068 MINT_IN_CASE(MINT_LDC_I4_8
)
3071 MINT_IN_CASE(MINT_LDC_I4_S
)
3072 sp
->data
.i
= *(const short *)(ip
+ 1);
3076 MINT_IN_CASE(MINT_LDC_I4
)
3078 sp
->data
.i
= READ32 (ip
);
3082 MINT_IN_CASE(MINT_LDC_I8
)
3084 sp
->data
.l
= READ64 (ip
);
3088 MINT_IN_CASE(MINT_LDC_R4
) {
3092 sp
->data
.f_r4
= * (float *)&val
;
3097 MINT_IN_CASE(MINT_LDC_R8
)
3098 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3102 MINT_IN_CASE(MINT_DUP
)
3107 MINT_IN_CASE(MINT_DUP_VT
)
3108 i32
= READ32 (ip
+ 1);
3110 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3111 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3115 MINT_IN_CASE(MINT_POP
) {
3116 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
3118 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
3123 MINT_IN_CASE(MINT_JMP
) {
3124 InterpMethod
*new_method
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3125 gboolean realloc_frame
= new_method
->alloca_size
> rtm
->alloca_size
;
3127 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3128 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
3130 if (!new_method
->transformed
) {
3134 mono_interp_transform_method (new_method
, context
, error
);
3135 frame
->ex
= mono_error_convert_to_exception (error
);
3140 rtm
= frame
->imethod
= new_method
;
3142 * We allocate the stack frame from scratch and store the arguments in the
3143 * locals again since it's possible for the caller stack frame to be smaller
3144 * than the callee stack frame (at the interp level)
3146 if (realloc_frame
) {
3147 frame
->args
= g_newa (char, rtm
->alloca_size
);
3148 memset (frame
->args
, 0, rtm
->alloca_size
);
3149 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
3151 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
3155 locals
= vt_sp
+ rtm
->vt_stack_size
;
3156 frame
->locals
= locals
;
3160 ip
= rtm
->new_body_start
; /* bypass storing input args from callers frame */
3163 MINT_IN_CASE(MINT_CALLI
) {
3164 MonoMethodSignature
*csignature
;
3165 stackval
*endsp
= sp
;
3169 csignature
= (MonoMethodSignature
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3173 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
3176 child_frame
.retval
= sp
;
3177 /* decrement by the actual number of args */
3178 sp
-= csignature
->param_count
;
3179 if (csignature
->hasthis
)
3181 child_frame
.stack_args
= sp
;
3183 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3184 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
3185 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3188 if (csignature
->hasthis
) {
3189 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3191 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3192 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3193 sp
[0].data
.p
= unboxed
;
3197 interp_exec_method (&child_frame
, context
);
3199 CHECK_RESUME_STATE (context
);
3201 /* need to handle typedbyref ... */
3202 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3208 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3209 gpointer target_ip
= sp
[-1].data
.p
;
3210 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3211 int opcode
= *(guint16
*)(ip
+ 2);
3216 sp
= do_icall (frame
, csignature
, opcode
, sp
, target_ip
);
3217 EXCEPTION_CHECKPOINT
;
3218 CHECK_RESUME_STATE (context
);
3222 MINT_IN_CASE(MINT_CALLI_NAT
) {
3223 MonoMethodSignature
*csignature
;
3224 stackval
*endsp
= sp
;
3225 unsigned char *code
= NULL
;
3229 csignature
= (MonoMethodSignature
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3233 code
= (guchar
*)sp
->data
.p
;
3234 child_frame
.imethod
= NULL
;
3237 child_frame
.retval
= sp
;
3238 /* decrement by the actual number of args */
3239 sp
-= csignature
->param_count
;
3240 if (csignature
->hasthis
)
3242 child_frame
.stack_args
= sp
;
3243 if (frame
->imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3244 MonoMarshalSpec
**mspecs
;
3245 MonoMethodPInvoke piinfo
;
3248 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3249 mspecs
= g_new0 (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3250 memset (&piinfo
, 0, sizeof (piinfo
));
3252 m
= mono_marshal_get_native_func_wrapper (m_class_get_image (frame
->imethod
->method
->klass
), csignature
, &piinfo
, mspecs
, code
);
3254 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3256 mono_metadata_free_marshal_spec (mspecs
[i
]);
3259 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, m
, error
);
3260 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3262 interp_exec_method (&child_frame
, context
);
3264 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
);
3267 CHECK_RESUME_STATE (context
);
3269 /* need to handle typedbyref ... */
3270 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3276 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3277 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3278 MonoObject
*this_arg
;
3279 MonoClass
*this_class
;
3280 gboolean is_void
= *ip
== MINT_VCALLVIRT_FAST
;
3281 InterpMethod
*imethod
;
3282 stackval
*endsp
= sp
;
3285 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3289 imethod
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3290 slot
= *(gint16
*)(ip
+ 2);
3293 child_frame
.retval
= sp
;
3295 /* decrement by the actual number of args */
3296 sp
-= imethod
->param_count
+ imethod
->hasthis
;
3297 child_frame
.stack_args
= sp
;
3299 this_arg
= (MonoObject
*)sp
->data
.p
;
3300 this_class
= this_arg
->vtable
->klass
;
3302 child_frame
.imethod
= get_virtual_method_fast (this_arg
, imethod
, slot
);
3303 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3305 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3306 sp
[0].data
.p
= unboxed
;
3309 interp_exec_method (&child_frame
, context
);
3311 CHECK_RESUME_STATE (context
);
3314 /* need to handle typedbyref ... */
3320 MINT_IN_CASE(MINT_CALL
)
3321 MINT_IN_CASE(MINT_VCALL
)
3322 MINT_IN_CASE(MINT_CALLVIRT
)
3323 MINT_IN_CASE(MINT_VCALLVIRT
) {
3324 gboolean is_void
= *ip
== MINT_VCALL
|| *ip
== MINT_VCALLVIRT
;
3325 gboolean is_virtual
= *ip
== MINT_CALLVIRT
|| *ip
== MINT_VCALLVIRT
;
3326 stackval
*endsp
= sp
;
3327 int num_varargs
= 0;;
3331 child_frame
.imethod
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3332 if (child_frame
.imethod
->vararg
) {
3333 /* The real signature for vararg calls */
3334 MonoMethodSignature
*csig
= (MonoMethodSignature
*) rtm
->data_items
[* (guint16
*) (ip
+ 2)];
3335 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3336 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
3337 child_frame
.varargs
= (char*) vt_sp
;
3338 copy_varargs_vtstack (csig
, sp
, &vt_sp
);
3340 ip
+= 2 + child_frame
.imethod
->vararg
;
3342 child_frame
.retval
= sp
;
3344 /* decrement by the actual number of args */
3345 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
3346 child_frame
.stack_args
= sp
;
3349 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3350 MonoClass
*this_class
= this_arg
->vtable
->klass
;
3352 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
3353 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3355 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3356 sp
[0].data
.p
= unboxed
;
3360 interp_exec_method (&child_frame
, context
);
3362 CHECK_RESUME_STATE (context
);
3365 /* need to handle typedbyref ... */
3371 MINT_IN_CASE(MINT_JIT_CALL
) {
3372 InterpMethod
*rmethod
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3376 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3377 if (!is_ok (error
)) {
3378 MonoException
*ex
= mono_error_convert_to_exception (error
);
3382 CHECK_RESUME_STATE (context
);
3384 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3389 MINT_IN_CASE(MINT_CALLRUN
) {
3390 MonoMethod
*target_method
= (MonoMethod
*) rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3391 MonoMethodSignature
*sig
= (MonoMethodSignature
*) rtm
->data_items
[* (guint16
*)(ip
+ 2)];
3397 sp
-= sig
->param_count
;
3401 ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3403 THROW_EX (frame
->ex
, ip
);
3405 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3412 MINT_IN_CASE(MINT_RET
)
3414 *frame
->retval
= *sp
;
3415 if (sp
> frame
->stack
)
3416 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3418 MINT_IN_CASE(MINT_RET_VOID
)
3419 if (sp
> frame
->stack
)
3420 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
3422 MINT_IN_CASE(MINT_RET_VT
)
3423 i32
= READ32(ip
+ 1);
3425 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3426 if (sp
> frame
->stack
)
3427 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3429 MINT_IN_CASE(MINT_BR_S
)
3430 ip
+= (short) *(ip
+ 1);
3432 MINT_IN_CASE(MINT_BR
)
3433 ip
+= (gint32
) READ32(ip
+ 1);
3435 #define ZEROP_S(datamem, op) \
3437 if (sp->data.datamem op 0) \
3438 ip += * (gint16 *)(ip + 1); \
3442 #define ZEROP(datamem, op) \
3444 if (sp->data.datamem op 0) \
3445 ip += READ32(ip + 1); \
3449 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3452 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3455 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3458 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3461 MINT_IN_CASE(MINT_BRFALSE_I4
)
3464 MINT_IN_CASE(MINT_BRFALSE_I8
)
3467 MINT_IN_CASE(MINT_BRFALSE_R4
)
3470 MINT_IN_CASE(MINT_BRFALSE_R8
)
3473 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3476 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3479 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
3482 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3485 MINT_IN_CASE(MINT_BRTRUE_I4
)
3488 MINT_IN_CASE(MINT_BRTRUE_I8
)
3491 MINT_IN_CASE(MINT_BRTRUE_R4
)
3494 MINT_IN_CASE(MINT_BRTRUE_R8
)
3497 #define CONDBR_S(cond) \
3500 ip += * (gint16 *)(ip + 1); \
3503 #define BRELOP_S(datamem, op) \
3504 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3506 #define CONDBR(cond) \
3509 ip += READ32(ip + 1); \
3513 #define BRELOP(datamem, op) \
3514 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3516 MINT_IN_CASE(MINT_BEQ_I4_S
)
3519 MINT_IN_CASE(MINT_BEQ_I8_S
)
3522 MINT_IN_CASE(MINT_BEQ_R4_S
)
3523 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3525 MINT_IN_CASE(MINT_BEQ_R8_S
)
3526 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3528 MINT_IN_CASE(MINT_BEQ_I4
)
3531 MINT_IN_CASE(MINT_BEQ_I8
)
3534 MINT_IN_CASE(MINT_BEQ_R4
)
3535 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3537 MINT_IN_CASE(MINT_BEQ_R8
)
3538 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3540 MINT_IN_CASE(MINT_BGE_I4_S
)
3543 MINT_IN_CASE(MINT_BGE_I8_S
)
3546 MINT_IN_CASE(MINT_BGE_R4_S
)
3547 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3549 MINT_IN_CASE(MINT_BGE_R8_S
)
3550 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3552 MINT_IN_CASE(MINT_BGE_I4
)
3555 MINT_IN_CASE(MINT_BGE_I8
)
3558 MINT_IN_CASE(MINT_BGE_R4
)
3559 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3561 MINT_IN_CASE(MINT_BGE_R8
)
3562 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3564 MINT_IN_CASE(MINT_BGT_I4_S
)
3567 MINT_IN_CASE(MINT_BGT_I8_S
)
3570 MINT_IN_CASE(MINT_BGT_R4_S
)
3571 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3573 MINT_IN_CASE(MINT_BGT_R8_S
)
3574 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3576 MINT_IN_CASE(MINT_BGT_I4
)
3579 MINT_IN_CASE(MINT_BGT_I8
)
3582 MINT_IN_CASE(MINT_BGT_R4
)
3583 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3585 MINT_IN_CASE(MINT_BGT_R8
)
3586 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3588 MINT_IN_CASE(MINT_BLT_I4_S
)
3591 MINT_IN_CASE(MINT_BLT_I8_S
)
3594 MINT_IN_CASE(MINT_BLT_R4_S
)
3595 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3597 MINT_IN_CASE(MINT_BLT_R8_S
)
3598 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3600 MINT_IN_CASE(MINT_BLT_I4
)
3603 MINT_IN_CASE(MINT_BLT_I8
)
3606 MINT_IN_CASE(MINT_BLT_R4
)
3607 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3609 MINT_IN_CASE(MINT_BLT_R8
)
3610 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3612 MINT_IN_CASE(MINT_BLE_I4_S
)
3615 MINT_IN_CASE(MINT_BLE_I8_S
)
3618 MINT_IN_CASE(MINT_BLE_R4_S
)
3619 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3621 MINT_IN_CASE(MINT_BLE_R8_S
)
3622 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3624 MINT_IN_CASE(MINT_BLE_I4
)
3627 MINT_IN_CASE(MINT_BLE_I8
)
3630 MINT_IN_CASE(MINT_BLE_R4
)
3631 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3633 MINT_IN_CASE(MINT_BLE_R8
)
3634 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3636 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3639 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3642 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
3643 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3645 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3646 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3648 MINT_IN_CASE(MINT_BNE_UN_I4
)
3651 MINT_IN_CASE(MINT_BNE_UN_I8
)
3654 MINT_IN_CASE(MINT_BNE_UN_R4
)
3655 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3657 MINT_IN_CASE(MINT_BNE_UN_R8
)
3658 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3661 #define BRELOP_S_CAST(datamem, op, type) \
3663 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3664 ip += * (gint16 *)(ip + 1); \
3668 #define BRELOP_CAST(datamem, op, type) \
3670 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3671 ip += READ32(ip + 1); \
3675 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3676 BRELOP_S_CAST(i
, >=, guint32
);
3678 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3679 BRELOP_S_CAST(l
, >=, guint64
);
3681 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
3682 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3684 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3685 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3687 MINT_IN_CASE(MINT_BGE_UN_I4
)
3688 BRELOP_CAST(i
, >=, guint32
);
3690 MINT_IN_CASE(MINT_BGE_UN_I8
)
3691 BRELOP_CAST(l
, >=, guint64
);
3693 MINT_IN_CASE(MINT_BGE_UN_R4
)
3694 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3696 MINT_IN_CASE(MINT_BGE_UN_R8
)
3697 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3699 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3700 BRELOP_S_CAST(i
, >, guint32
);
3702 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3703 BRELOP_S_CAST(l
, >, guint64
);
3705 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
3706 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3708 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3709 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3711 MINT_IN_CASE(MINT_BGT_UN_I4
)
3712 BRELOP_CAST(i
, >, guint32
);
3714 MINT_IN_CASE(MINT_BGT_UN_I8
)
3715 BRELOP_CAST(l
, >, guint64
);
3717 MINT_IN_CASE(MINT_BGT_UN_R4
)
3718 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3720 MINT_IN_CASE(MINT_BGT_UN_R8
)
3721 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3723 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3724 BRELOP_S_CAST(i
, <=, guint32
);
3726 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3727 BRELOP_S_CAST(l
, <=, guint64
);
3729 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
3730 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3732 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3733 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3735 MINT_IN_CASE(MINT_BLE_UN_I4
)
3736 BRELOP_CAST(i
, <=, guint32
);
3738 MINT_IN_CASE(MINT_BLE_UN_I8
)
3739 BRELOP_CAST(l
, <=, guint64
);
3741 MINT_IN_CASE(MINT_BLE_UN_R4
)
3742 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3744 MINT_IN_CASE(MINT_BLE_UN_R8
)
3745 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3747 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3748 BRELOP_S_CAST(i
, <, guint32
);
3750 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3751 BRELOP_S_CAST(l
, <, guint64
);
3753 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
3754 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3756 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3757 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3759 MINT_IN_CASE(MINT_BLT_UN_I4
)
3760 BRELOP_CAST(i
, <, guint32
);
3762 MINT_IN_CASE(MINT_BLT_UN_I8
)
3763 BRELOP_CAST(l
, <, guint64
);
3765 MINT_IN_CASE(MINT_BLT_UN_R4
)
3766 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3768 MINT_IN_CASE(MINT_BLT_UN_R8
)
3769 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3771 MINT_IN_CASE(MINT_SWITCH
) {
3773 const unsigned short *st
;
3779 if ((guint32
)sp
->data
.i
< n
) {
3781 ip
+= 2 * (guint32
)sp
->data
.i
;
3782 offset
= READ32 (ip
);
3789 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
3791 THROW_EX (mono_get_exception_null_reference (), ip
);
3793 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3795 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
3797 THROW_EX (mono_get_exception_null_reference (), ip
);
3799 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3801 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
3803 THROW_EX (mono_get_exception_null_reference (), ip
);
3805 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3807 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
3809 THROW_EX (mono_get_exception_null_reference (), ip
);
3811 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3813 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
3814 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
3816 THROW_EX (mono_get_exception_null_reference (), ip
);
3818 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3820 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
3822 THROW_EX (mono_get_exception_null_reference (), ip
);
3824 /* memmove handles unaligned case */
3825 memmove (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
3827 MINT_IN_CASE(MINT_LDIND_I
) {
3828 guint16 offset
= * (guint16
*)(ip
+ 1);
3829 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3833 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
3835 THROW_EX (mono_get_exception_null_reference (), ip
);
3837 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
3839 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
3841 THROW_EX (mono_get_exception_null_reference (), ip
);
3843 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3845 MINT_IN_CASE(MINT_LDIND_REF
)
3847 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3849 MINT_IN_CASE(MINT_STIND_REF
)
3852 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
3854 MINT_IN_CASE(MINT_STIND_I1
)
3857 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3859 MINT_IN_CASE(MINT_STIND_I2
)
3862 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3864 MINT_IN_CASE(MINT_STIND_I4
)
3867 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3869 MINT_IN_CASE(MINT_STIND_I
)
3872 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3874 MINT_IN_CASE(MINT_STIND_I8
)
3877 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3879 MINT_IN_CASE(MINT_STIND_R4
)
3882 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
3884 MINT_IN_CASE(MINT_STIND_R8
)
3887 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3889 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3892 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3894 #define BINOP(datamem, op) \
3896 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3898 MINT_IN_CASE(MINT_ADD_I4
)
3901 MINT_IN_CASE(MINT_ADD_I8
)
3904 MINT_IN_CASE(MINT_ADD_R4
)
3907 MINT_IN_CASE(MINT_ADD_R8
)
3910 MINT_IN_CASE(MINT_ADD1_I4
)
3914 MINT_IN_CASE(MINT_ADD1_I8
)
3918 MINT_IN_CASE(MINT_SUB_I4
)
3921 MINT_IN_CASE(MINT_SUB_I8
)
3924 MINT_IN_CASE(MINT_SUB_R4
)
3927 MINT_IN_CASE(MINT_SUB_R8
)
3930 MINT_IN_CASE(MINT_SUB1_I4
)
3934 MINT_IN_CASE(MINT_SUB1_I8
)
3938 MINT_IN_CASE(MINT_MUL_I4
)
3941 MINT_IN_CASE(MINT_MUL_I8
)
3944 MINT_IN_CASE(MINT_MUL_R4
)
3947 MINT_IN_CASE(MINT_MUL_R8
)
3950 MINT_IN_CASE(MINT_DIV_I4
)
3951 if (sp
[-1].data
.i
== 0)
3952 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3953 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
3954 THROW_EX (mono_get_exception_overflow (), ip
);
3957 MINT_IN_CASE(MINT_DIV_I8
)
3958 if (sp
[-1].data
.l
== 0)
3959 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3960 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
3961 THROW_EX (mono_get_exception_overflow (), ip
);
3964 MINT_IN_CASE(MINT_DIV_R4
)
3967 MINT_IN_CASE(MINT_DIV_R8
)
3971 #define BINOP_CAST(datamem, op, type) \
3973 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3975 MINT_IN_CASE(MINT_DIV_UN_I4
)
3976 if (sp
[-1].data
.i
== 0)
3977 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3978 BINOP_CAST(i
, /, guint32
);
3980 MINT_IN_CASE(MINT_DIV_UN_I8
)
3981 if (sp
[-1].data
.l
== 0)
3982 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3983 BINOP_CAST(l
, /, guint64
);
3985 MINT_IN_CASE(MINT_REM_I4
)
3986 if (sp
[-1].data
.i
== 0)
3987 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3988 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
3989 THROW_EX (mono_get_exception_overflow (), ip
);
3992 MINT_IN_CASE(MINT_REM_I8
)
3993 if (sp
[-1].data
.l
== 0)
3994 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3995 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
3996 THROW_EX (mono_get_exception_overflow (), ip
);
3999 MINT_IN_CASE(MINT_REM_R4
)
4000 /* FIXME: what do we actually do here? */
4002 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4005 MINT_IN_CASE(MINT_REM_R8
)
4006 /* FIXME: what do we actually do here? */
4008 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4011 MINT_IN_CASE(MINT_REM_UN_I4
)
4012 if (sp
[-1].data
.i
== 0)
4013 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4014 BINOP_CAST(i
, %, guint32
);
4016 MINT_IN_CASE(MINT_REM_UN_I8
)
4017 if (sp
[-1].data
.l
== 0)
4018 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4019 BINOP_CAST(l
, %, guint64
);
4021 MINT_IN_CASE(MINT_AND_I4
)
4024 MINT_IN_CASE(MINT_AND_I8
)
4027 MINT_IN_CASE(MINT_OR_I4
)
4030 MINT_IN_CASE(MINT_OR_I8
)
4033 MINT_IN_CASE(MINT_XOR_I4
)
4036 MINT_IN_CASE(MINT_XOR_I8
)
4040 #define SHIFTOP(datamem, op) \
4042 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4045 MINT_IN_CASE(MINT_SHL_I4
)
4048 MINT_IN_CASE(MINT_SHL_I8
)
4051 MINT_IN_CASE(MINT_SHR_I4
)
4054 MINT_IN_CASE(MINT_SHR_I8
)
4057 MINT_IN_CASE(MINT_SHR_UN_I4
)
4059 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4062 MINT_IN_CASE(MINT_SHR_UN_I8
)
4064 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4067 MINT_IN_CASE(MINT_NEG_I4
)
4068 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4071 MINT_IN_CASE(MINT_NEG_I8
)
4072 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4075 MINT_IN_CASE(MINT_NEG_R4
)
4076 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4079 MINT_IN_CASE(MINT_NEG_R8
)
4080 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4083 MINT_IN_CASE(MINT_NOT_I4
)
4084 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4087 MINT_IN_CASE(MINT_NOT_I8
)
4088 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4091 MINT_IN_CASE(MINT_CONV_I1_I4
)
4092 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4095 MINT_IN_CASE(MINT_CONV_I1_I8
)
4096 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4099 MINT_IN_CASE(MINT_CONV_I1_R4
)
4100 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4103 MINT_IN_CASE(MINT_CONV_I1_R8
)
4104 /* without gint32 cast, C compiler is allowed to use undefined
4105 * behaviour if data.f is bigger than >255. See conv.fpint section
4107 * > The conversion truncates; that is, the fractional part
4108 * > is discarded. The behavior is undefined if the truncated
4109 * > value cannot be represented in the destination type.
4111 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4114 MINT_IN_CASE(MINT_CONV_U1_I4
)
4115 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4118 MINT_IN_CASE(MINT_CONV_U1_I8
)
4119 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4122 MINT_IN_CASE(MINT_CONV_U1_R4
)
4123 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4126 MINT_IN_CASE(MINT_CONV_U1_R8
)
4127 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4130 MINT_IN_CASE(MINT_CONV_I2_I4
)
4131 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4134 MINT_IN_CASE(MINT_CONV_I2_I8
)
4135 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4138 MINT_IN_CASE(MINT_CONV_I2_R4
)
4139 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4142 MINT_IN_CASE(MINT_CONV_I2_R8
)
4143 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4146 MINT_IN_CASE(MINT_CONV_U2_I4
)
4147 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4150 MINT_IN_CASE(MINT_CONV_U2_I8
)
4151 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4154 MINT_IN_CASE(MINT_CONV_U2_R4
)
4155 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4158 MINT_IN_CASE(MINT_CONV_U2_R8
)
4159 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4162 MINT_IN_CASE(MINT_CONV_I4_R4
)
4163 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4166 MINT_IN_CASE(MINT_CONV_I4_R8
)
4167 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4170 MINT_IN_CASE(MINT_CONV_U4_I8
)
4171 MINT_IN_CASE(MINT_CONV_I4_I8
)
4172 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4175 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4176 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4179 MINT_IN_CASE(MINT_CONV_U4_R4
)
4180 /* needed on arm64 */
4181 if (isinf (sp
[-1].data
.f_r4
))
4183 /* needed by wasm */
4184 else if (isnan (sp
[-1].data
.f_r4
))
4187 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4190 MINT_IN_CASE(MINT_CONV_U4_R8
)
4191 /* needed on arm64 */
4192 if (mono_isinf (sp
[-1].data
.f
))
4194 /* needed by wasm */
4195 else if (isnan (sp
[-1].data
.f
))
4198 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
4201 MINT_IN_CASE(MINT_CONV_I8_I4
)
4202 sp
[-1].data
.l
= sp
[-1].data
.i
;
4205 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4206 sp
[-2].data
.l
= sp
[-2].data
.i
;
4209 MINT_IN_CASE(MINT_CONV_I8_U4
)
4210 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4213 MINT_IN_CASE(MINT_CONV_I8_R4
)
4214 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4217 MINT_IN_CASE(MINT_CONV_I8_R8
)
4218 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4221 MINT_IN_CASE(MINT_CONV_R4_I4
)
4222 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4225 MINT_IN_CASE(MINT_CONV_R4_I8
)
4226 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4229 MINT_IN_CASE(MINT_CONV_R4_R8
)
4230 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4233 MINT_IN_CASE(MINT_CONV_R8_I4
)
4234 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4237 MINT_IN_CASE(MINT_CONV_R8_I8
)
4238 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4241 MINT_IN_CASE(MINT_CONV_R8_R4
)
4242 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4245 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4246 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4249 MINT_IN_CASE(MINT_CONV_U8_I4
)
4250 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
4253 MINT_IN_CASE(MINT_CONV_U8_R4
)
4254 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4257 MINT_IN_CASE(MINT_CONV_U8_R8
)
4258 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4261 MINT_IN_CASE(MINT_CPOBJ
) {
4262 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4263 g_assert (m_class_is_valuetype (c
));
4264 /* if this assertion fails, we need to add a write barrier */
4265 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4266 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4271 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4272 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4273 g_assert (m_class_is_valuetype (c
));
4274 /* if this assertion fails, we need to add a write barrier */
4275 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4276 stackval_from_data (m_class_get_byval_arg (c
), &sp
[-2], sp
[-1].data
.p
, FALSE
);
4281 MINT_IN_CASE(MINT_LDOBJ
) {
4283 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4286 stackval_from_data (m_class_get_byval_arg (c
), &sp
[-1], p
, FALSE
);
4289 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4291 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4294 if (!m_class_is_enumtype (c
)) {
4295 int size
= mono_class_value_size (c
, NULL
);
4296 sp
[-1].data
.p
= vt_sp
;
4297 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4299 stackval_from_data (m_class_get_byval_arg (c
), &sp
[-1], p
, FALSE
);
4302 MINT_IN_CASE(MINT_LDSTR
)
4303 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4307 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4308 MonoString
*s
= NULL
;
4309 guint32 strtoken
= (guint32
)(gsize
)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4311 MonoMethod
*method
= frame
->imethod
->method
;
4312 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4313 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4314 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4315 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4317 g_assert_not_reached ();
4324 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4325 MonoClass
*newobj_class
;
4326 InterpMethod
*imethod
;
4327 guint32 token
= * (guint16
*)(ip
+ 1);
4328 guint16 param_count
= * (guint16
*)(ip
+ 2);
4330 imethod
= (InterpMethod
*) rtm
->data_items
[token
];
4331 newobj_class
= imethod
->method
->klass
;
4334 sp
->data
.p
= ves_array_create (rtm
->domain
, newobj_class
, param_count
, sp
, error
);
4335 if (!mono_error_ok (error
))
4336 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4342 MINT_IN_CASE(MINT_NEWOBJ_FAST
)
4343 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4344 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4345 guint16 param_count
;
4346 gboolean vt
= *ip
!= MINT_NEWOBJ_FAST
;
4347 stackval valuetype_this
;
4351 child_frame
.imethod
= (InterpMethod
*) rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4352 param_count
= *(guint16
*)(ip
+ 2);
4356 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
4358 child_frame
.stack_args
= sp
;
4361 gboolean vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4363 memset (vt_sp
, 0, *(guint16
*)(ip
+ 3));
4365 valuetype_this
.data
.p
= vt_sp
;
4368 memset (&valuetype_this
, 0, sizeof (stackval
));
4369 sp
->data
.p
= &valuetype_this
;
4373 MonoVTable
*vtable
= (MonoVTable
*) rtm
->data_items
[*(guint16
*)(ip
+ 3)];
4374 if (G_UNLIKELY (!vtable
->initialized
)) {
4375 mono_runtime_class_init_full (vtable
, error
);
4376 if (!mono_error_ok (error
))
4377 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4379 o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4380 if (G_UNLIKELY (!o
)) {
4381 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4382 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4388 interp_exec_method (&child_frame
, context
);
4390 CHECK_RESUME_STATE (context
);
4393 *sp
= valuetype_this
;
4399 MINT_IN_CASE(MINT_NEWOBJ
) {
4400 MonoClass
*newobj_class
;
4401 MonoMethodSignature
*csig
;
4402 stackval valuetype_this
;
4408 token
= * (guint16
*)(ip
+ 1);
4411 child_frame
.ip
= NULL
;
4412 child_frame
.ex
= NULL
;
4414 child_frame
.imethod
= (InterpMethod
*)rtm
->data_items
[token
];
4415 csig
= mono_method_signature_internal (child_frame
.imethod
->method
);
4416 newobj_class
= child_frame
.imethod
->method
->klass
;
4417 /*if (profiling_classes) {
4418 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4420 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4423 g_assert (csig
->hasthis
);
4424 if (csig
->param_count
) {
4425 sp
-= csig
->param_count
;
4426 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
4428 child_frame
.stack_args
= sp
;
4431 * First arg is the object.
4433 if (m_class_is_valuetype (newobj_class
)) {
4434 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
4435 memset (&valuetype_this
, 0, sizeof (stackval
));
4436 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
4438 valuetype_this
.data
.p
= vt_sp
;
4440 sp
->data
.p
= &valuetype_this
;
4443 if (newobj_class
!= mono_defaults
.string_class
) {
4444 MonoVTable
*vtable
= mono_class_vtable_checked (rtm
->domain
, newobj_class
, error
);
4445 if (!mono_error_ok (error
) || !mono_runtime_class_init_full (vtable
, error
))
4446 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4447 o
= mono_object_new_checked (rtm
->domain
, newobj_class
, error
);
4448 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4449 EXCEPTION_CHECKPOINT
;
4451 #ifndef DISABLE_REMOTING
4452 if (mono_object_is_transparent_proxy (o
)) {
4453 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
.imethod
->method
, error
);
4454 mono_error_assert_ok (error
);
4455 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, remoting_invoke_method
, error
);
4456 mono_error_assert_ok (error
);
4461 child_frame
.retval
= &retval
;
4465 interp_exec_method (&child_frame
, context
);
4467 CHECK_RESUME_STATE (context
);
4470 * a constructor returns void, but we need to return the object we created
4472 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
4473 *sp
= valuetype_this
;
4474 } else if (newobj_class
== mono_defaults
.string_class
) {
4482 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
4488 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
4489 MonoMethodSignature
*csig
;
4493 token
= * (guint16
*)(ip
+ 1);
4496 InterpMethod
*cmethod
= (InterpMethod
*)rtm
->data_items
[token
];
4497 csig
= mono_method_signature_internal (cmethod
->method
);
4499 g_assert (csig
->hasthis
);
4500 sp
-= csig
->param_count
;
4502 gpointer arg0
= sp
[0].data
.p
;
4504 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
4505 *byreference_this
= arg0
;
4507 /* Followed by a VTRESULT opcode which will push the result on the stack */
4512 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4513 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4514 sp
[-1].data
.p
= *byreference_this
;
4519 MINT_IN_CASE(MINT_CASTCLASS
)
4520 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4521 if ((o
= sp
[-1].data
.o
)) {
4522 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4523 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4525 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4529 MINT_IN_CASE(MINT_ISINST
)
4530 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4531 if ((o
= sp
[-1].data
.o
)) {
4532 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4533 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4535 sp
[-1].data
.p
= NULL
;
4539 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4540 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4543 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4544 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4547 MINT_IN_CASE(MINT_UNBOX
)
4548 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4552 THROW_EX (mono_get_exception_null_reference (), ip
);
4554 MonoObject
*isinst_obj
;
4555 isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4556 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4557 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
)))))
4558 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4560 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
4563 MINT_IN_CASE(MINT_THROW
)
4566 sp
->data
.p
= mono_get_exception_null_reference ();
4568 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4570 MINT_IN_CASE(MINT_CHECKPOINT
)
4571 /* Do synchronous checking of abort requests */
4572 EXCEPTION_CHECKPOINT
;
4575 MINT_IN_CASE(MINT_SAFEPOINT
)
4576 /* Do synchronous checking of abort requests */
4577 EXCEPTION_CHECKPOINT
;
4578 /* Poll safepoint */
4579 mono_threads_safepoint ();
4582 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
4584 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4587 MINT_IN_CASE(MINT_LDFLDA
)
4590 THROW_EX (mono_get_exception_null_reference (), ip
);
4591 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4594 MINT_IN_CASE(MINT_CKNULL
)
4597 THROW_EX (mono_get_exception_null_reference (), ip
);
4600 MINT_IN_CASE(MINT_CKNULL_N
) {
4601 /* Same as CKNULL, but further down the stack */
4602 int n
= *(guint16
*)(ip
+ 1);
4605 THROW_EX (mono_get_exception_null_reference (), ip
);
4610 #define LDFLD(datamem, fieldtype) \
4611 o = sp [-1].data.o; \
4613 THROW_EX (mono_get_exception_null_reference (), ip); \
4614 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4617 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4618 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4619 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4620 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4621 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4622 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4623 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
4624 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4625 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4626 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4628 MINT_IN_CASE(MINT_LDFLD_VT
) {
4631 THROW_EX (mono_get_exception_null_reference (), ip
);
4633 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 2)];
4634 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4635 i32
= mono_class_value_size (klass
, NULL
);
4637 sp
[-1].data
.p
= vt_sp
;
4638 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
4639 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4644 MINT_IN_CASE(MINT_LDRMFLD
) {
4645 MonoClassField
*field
;
4650 THROW_EX (mono_get_exception_null_reference (), ip
);
4651 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4653 #ifndef DISABLE_REMOTING
4654 if (mono_object_is_transparent_proxy (o
)) {
4656 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4658 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4659 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4662 addr
= (char*)o
+ field
->offset
;
4664 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
4668 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
4669 MonoClassField
*field
;
4674 THROW_EX (mono_get_exception_null_reference (), ip
);
4676 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4677 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4678 i32
= mono_class_value_size (klass
, NULL
);
4681 #ifndef DISABLE_REMOTING
4682 if (mono_object_is_transparent_proxy (o
)) {
4684 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4685 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4686 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4689 addr
= (char*)o
+ field
->offset
;
4691 sp
[-1].data
.p
= vt_sp
;
4692 memcpy(sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
4693 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4694 memcpy(sp
[-1].data
.p
, addr
, i32
);
4698 #define STFLD(datamem, fieldtype) \
4699 o = sp [-2].data.o; \
4701 THROW_EX (mono_get_exception_null_reference (), ip); \
4703 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4706 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
4707 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
4708 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
4709 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
4710 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
4711 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
4712 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
4713 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
4714 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
4715 MINT_IN_CASE(MINT_STFLD_O
)
4718 THROW_EX (mono_get_exception_null_reference (), ip
);
4720 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.o
);
4724 MINT_IN_CASE(MINT_STFLD_VT
) {
4727 THROW_EX (mono_get_exception_null_reference (), ip
);
4730 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 2)];
4731 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4732 i32
= mono_class_value_size (klass
, NULL
);
4734 guint16 offset
= * (guint16
*)(ip
+ 1);
4735 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
4737 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4741 MINT_IN_CASE(MINT_STRMFLD
) {
4742 MonoClassField
*field
;
4746 THROW_EX (mono_get_exception_null_reference (), ip
);
4748 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4751 #ifndef DISABLE_REMOTING
4752 if (mono_object_is_transparent_proxy (o
)) {
4753 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4754 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4755 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4758 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
4763 MINT_IN_CASE(MINT_STRMFLD_VT
) {
4764 MonoClassField
*field
;
4768 THROW_EX (mono_get_exception_null_reference (), ip
);
4769 field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4770 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4771 i32
= mono_class_value_size (klass
, NULL
);
4774 #ifndef DISABLE_REMOTING
4775 if (mono_object_is_transparent_proxy (o
)) {
4776 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4777 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4778 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4781 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
4784 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4787 MINT_IN_CASE(MINT_LDSFLDA
) {
4788 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4789 sp
->data
.p
= mono_class_static_field_address (rtm
->domain
, field
);
4790 EXCEPTION_CHECKPOINT
;
4796 /* We init class here to preserve cctor order */
4797 #define LDSFLD(datamem, fieldtype) { \
4798 MonoVTable *vtable = (MonoVTable*) rtm->data_items [*(guint16*)(ip + 1)]; \
4799 if (G_UNLIKELY (!vtable->initialized)) { \
4800 mono_runtime_class_init_full (vtable, error); \
4801 if (!mono_error_ok (error)) \
4802 THROW_EX (mono_error_convert_to_exception (error), ip); \
4804 sp[0].data.datamem = * (fieldtype *)(rtm->data_items [* (guint16 *)(ip + 2)]) ; \
4809 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
4810 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
4811 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
4812 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
4813 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
4814 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
4815 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
4816 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
4817 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
4818 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
4820 MINT_IN_CASE(MINT_LDSFLD
) {
4821 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4822 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4823 EXCEPTION_CHECKPOINT
;
4824 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
4829 MINT_IN_CASE(MINT_LDSFLD_VT
) {
4830 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4831 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4832 EXCEPTION_CHECKPOINT
;
4833 int size
= READ32 (ip
+ 2);
4837 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4838 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
4843 #define STSFLD(datamem, fieldtype) { \
4844 MonoVTable *vtable = (MonoVTable*) rtm->data_items [*(guint16*)(ip + 1)]; \
4845 if (G_UNLIKELY (!vtable->initialized)) { \
4846 mono_runtime_class_init_full (vtable, error); \
4847 if (!mono_error_ok (error)) \
4848 THROW_EX (mono_error_convert_to_exception (error), ip); \
4851 * (fieldtype *)(rtm->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
4855 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
4856 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
4857 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
4858 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
4859 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
4860 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
4861 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
4862 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
4863 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
4864 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
4866 MINT_IN_CASE(MINT_STSFLD
) {
4867 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4868 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4869 EXCEPTION_CHECKPOINT
;
4872 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
4875 MINT_IN_CASE(MINT_STSFLD_VT
) {
4876 MonoClassField
*field
= (MonoClassField
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4877 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
4878 EXCEPTION_CHECKPOINT
;
4879 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4880 i32
= mono_class_value_size (klass
, NULL
);
4884 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
4885 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4888 MINT_IN_CASE(MINT_STOBJ_VT
) {
4890 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4892 size
= mono_class_value_size (c
, NULL
);
4893 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
4894 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4898 MINT_IN_CASE(MINT_STOBJ
) {
4899 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4902 g_assert (!m_class_get_byval_arg (c
)->byref
);
4903 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)))
4904 mono_gc_wbarrier_generic_store_internal (sp
[-2].data
.o
, sp
[-1].data
.o
);
4906 stackval_to_data (m_class_get_byval_arg (c
), &sp
[-1], sp
[-2].data
.p
, FALSE
);
4910 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
4911 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
4912 THROW_EX (mono_get_exception_overflow (), ip
);
4913 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4916 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
4917 if (sp
[-1].data
.i
< 0)
4918 THROW_EX (mono_get_exception_overflow (), ip
);
4919 sp
[-1].data
.l
= sp
[-1].data
.i
;
4922 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
4923 if (sp
[-1].data
.l
< 0)
4924 THROW_EX (mono_get_exception_overflow (), ip
);
4927 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
4928 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
4929 THROW_EX (mono_get_exception_overflow (), ip
);
4932 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
4933 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
4934 THROW_EX (mono_get_exception_overflow (), ip
);
4935 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
4938 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
4939 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
4940 THROW_EX (mono_get_exception_overflow (), ip
);
4941 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4944 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
4945 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
4946 THROW_EX (mono_get_exception_overflow (), ip
);
4947 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4950 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
4951 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
4952 THROW_EX (mono_get_exception_overflow (), ip
);
4953 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
4956 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
4957 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
4958 THROW_EX (mono_get_exception_overflow (), ip
);
4959 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4962 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
4963 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
4964 THROW_EX (mono_get_exception_overflow (), ip
);
4965 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4968 MINT_IN_CASE(MINT_BOX
) {
4969 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4970 guint16 offset
= * (guint16
*)(ip
+ 2);
4972 stackval_to_data (m_class_get_byval_arg (c
), &sp
[-1 - offset
], (char *) &sp
[-1 - offset
], FALSE
);
4973 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, &sp
[-1 - offset
], error
);
4974 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4979 MINT_IN_CASE(MINT_BOX_VT
) {
4980 c
= (MonoClass
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4981 guint16 offset
= * (guint16
*)(ip
+ 2);
4982 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
4983 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
4985 int size
= mono_class_value_size (c
, NULL
);
4986 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, sp
[-1 - offset
].data
.p
, error
);
4987 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4988 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4995 MINT_IN_CASE(MINT_NEWARR
)
4996 sp
[-1].data
.p
= (MonoObject
*) mono_array_new_checked (rtm
->domain
, (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)], sp
[-1].data
.i
, error
);
4997 if (!mono_error_ok (error
)) {
4998 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5000 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5002 /*if (profiling_classes) {
5003 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5005 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5009 MINT_IN_CASE(MINT_LDLEN
)
5012 THROW_EX (mono_get_exception_null_reference (), ip
);
5013 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5016 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5018 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 1);
5020 THROW_EX (mono_get_exception_null_reference (), ip
);
5021 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5025 MINT_IN_CASE(MINT_GETCHR
) {
5027 s
= (MonoString
*)sp
[-2].data
.p
;
5029 THROW_EX (mono_get_exception_null_reference (), ip
);
5030 i32
= sp
[-1].data
.i
;
5031 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5032 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5034 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5038 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5039 guint8
*span
= (guint8
*) sp
[-2].data
.p
;
5040 int index
= sp
[-1].data
.i
;
5041 gsize element_size
= (gsize
) *(gint16
*) (ip
+ 1);
5042 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 2);
5043 gsize offset_pointer
= (gsize
) *(gint16
*) (ip
+ 3);
5047 THROW_EX (mono_get_exception_null_reference (), ip
);
5049 gint32 length
= *(gint32
*) (span
+ offset_length
);
5050 if (index
< 0 || index
>= length
)
5051 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5053 gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5054 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5059 MINT_IN_CASE(MINT_STRLEN
)
5063 THROW_EX (mono_get_exception_null_reference (), ip
);
5064 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5066 MINT_IN_CASE(MINT_ARRAY_RANK
)
5069 THROW_EX (mono_get_exception_null_reference (), ip
);
5070 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
5073 MINT_IN_CASE(MINT_LDELEMA
)
5074 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5075 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
5077 MonoClass
*klass
= (MonoClass
*)rtm
->data_items
[*(guint16
*) (ip
+ 1)];
5078 guint16 numargs
= *(guint16
*) (ip
+ 2);
5084 THROW_EX (mono_get_exception_null_reference (), ip
);
5085 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
5087 THROW_EX (frame
->ex
, ip
);
5092 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
5093 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
5094 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
5095 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
5096 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
5097 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
5098 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
5099 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
5100 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
5101 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
5102 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
5103 MINT_IN_CASE(MINT_LDELEM_VT
) {
5109 o
= (MonoArray
*)sp
[0].data
.p
;
5111 THROW_EX (mono_get_exception_null_reference (), ip
);
5113 aindex
= sp
[1].data
.i
;
5114 if (aindex
>= mono_array_length_internal (o
))
5115 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5118 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5121 case MINT_LDELEM_I1
:
5122 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
5124 case MINT_LDELEM_U1
:
5125 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
5127 case MINT_LDELEM_I2
:
5128 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
5130 case MINT_LDELEM_U2
:
5131 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
5134 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
5136 case MINT_LDELEM_I4
:
5137 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
5139 case MINT_LDELEM_U4
:
5140 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
5142 case MINT_LDELEM_I8
:
5143 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
5145 case MINT_LDELEM_R4
:
5146 sp
[0].data
.f_r4
= mono_array_get_fast (o
, float, aindex
);
5148 case MINT_LDELEM_R8
:
5149 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
5151 case MINT_LDELEM_REF
:
5152 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
5154 case MINT_LDELEM_VT
: {
5155 MonoClass
*klass_vt
= (MonoClass
*)rtm
->data_items
[*(guint16
*) (ip
+ 1)];
5156 i32
= READ32 (ip
+ 2);
5157 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5158 sp
[0].data
.vt
= vt_sp
;
5159 stackval_from_data (m_class_get_byval_arg (klass_vt
), sp
, src_addr
, FALSE
);
5160 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5172 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
5173 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
5174 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
5175 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
5176 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
5177 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
5178 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
5179 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
5180 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
5181 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
5182 MINT_IN_CASE(MINT_STELEM_VT
) {
5189 THROW_EX (mono_get_exception_null_reference (), ip
);
5191 aindex
= sp
[1].data
.i
;
5192 if (aindex
>= mono_array_length_internal ((MonoArray
*)o
))
5193 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5197 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
5199 case MINT_STELEM_I1
:
5200 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
5202 case MINT_STELEM_U1
:
5203 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
5205 case MINT_STELEM_I2
:
5206 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
5208 case MINT_STELEM_U2
:
5209 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
5211 case MINT_STELEM_I4
:
5212 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
5214 case MINT_STELEM_I8
:
5215 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
5217 case MINT_STELEM_R4
:
5218 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f_r4
);
5220 case MINT_STELEM_R8
:
5221 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
5223 case MINT_STELEM_REF
: {
5224 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
5225 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5226 if (sp
[2].data
.p
&& !isinst_obj
)
5227 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5228 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5231 case MINT_STELEM_VT
: {
5232 MonoClass
*klass_vt
= (MonoClass
*)rtm
->data_items
[*(guint16
*) (ip
+ 1)];
5233 i32
= READ32 (ip
+ 2);
5234 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5236 stackval_to_data (m_class_get_byval_arg (klass_vt
), &sp
[2], dst_addr
, FALSE
);
5237 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5248 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5249 if (sp
[-1].data
.i
< 0)
5250 THROW_EX (mono_get_exception_overflow (), ip
);
5253 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5254 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5255 THROW_EX (mono_get_exception_overflow (), ip
);
5256 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5259 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5260 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5261 THROW_EX (mono_get_exception_overflow (), ip
);
5262 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5265 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5266 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
)
5267 THROW_EX (mono_get_exception_overflow (), ip
);
5268 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5271 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5272 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
5273 THROW_EX (mono_get_exception_overflow (), ip
);
5274 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5277 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5278 if (sp
[-1].data
.i
< 0)
5279 THROW_EX (mono_get_exception_overflow (), ip
);
5282 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5283 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5284 THROW_EX (mono_get_exception_overflow (), ip
);
5285 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5288 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5289 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
)
5290 THROW_EX (mono_get_exception_overflow (), ip
);
5291 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5294 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5295 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
5296 THROW_EX (mono_get_exception_overflow (), ip
);
5297 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5300 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5301 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5302 THROW_EX (mono_get_exception_overflow (), ip
);
5305 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
5306 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
5307 THROW_EX (mono_get_exception_overflow (), ip
);
5310 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
5311 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
5312 THROW_EX (mono_get_exception_overflow (), ip
);
5313 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5316 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
5317 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
5318 THROW_EX (mono_get_exception_overflow (), ip
);
5319 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5322 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
5323 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
5324 THROW_EX (mono_get_exception_overflow (), ip
);
5325 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5328 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
5329 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
5330 THROW_EX (mono_get_exception_overflow (), ip
);
5331 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5334 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
5335 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
5336 THROW_EX (mono_get_exception_overflow (), ip
);
5339 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
5340 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
5341 THROW_EX (mono_get_exception_overflow (), ip
);
5342 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
5345 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
5346 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
5347 THROW_EX (mono_get_exception_overflow (), ip
);
5348 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
5351 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
5352 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
5353 THROW_EX (mono_get_exception_overflow (), ip
);
5356 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
5357 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
5358 THROW_EX (mono_get_exception_overflow (), ip
);
5361 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
5362 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
5363 THROW_EX (mono_get_exception_overflow (), ip
);
5364 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5367 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
5368 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
5369 THROW_EX (mono_get_exception_overflow (), ip
);
5370 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5373 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
5374 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
5375 THROW_EX (mono_get_exception_overflow (), ip
);
5376 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5379 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
5380 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
5381 THROW_EX (mono_get_exception_overflow (), ip
);
5382 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5385 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
5386 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
5387 THROW_EX (mono_get_exception_overflow (), ip
);
5390 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
5391 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
5392 THROW_EX (mono_get_exception_overflow (), ip
);
5393 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
5396 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
5397 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
5398 THROW_EX (mono_get_exception_overflow (), ip
);
5399 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
5403 MINT_IN_CASE(MINT_LDELEM
)
5404 MINT_IN_CASE(MINT_STELEM
)
5405 MINT_IN_CASE(MINT_UNBOX_ANY
)
5407 MINT_IN_CASE(MINT_CKFINITE
)
5408 if (!mono_isfinite (sp
[-1].data
.f
))
5409 THROW_EX (mono_get_exception_arithmetic (), ip
);
5412 MINT_IN_CASE(MINT_MKREFANY
) {
5413 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
5415 /* The value address is on the stack */
5416 gpointer addr
= sp
[-1].data
.p
;
5417 /* Push the typedref value on the stack */
5418 sp
[-1].data
.p
= vt_sp
;
5419 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5421 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5423 tref
->type
= m_class_get_byval_arg (c
);
5429 MINT_IN_CASE(MINT_REFANYTYPE
) {
5430 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5431 MonoType
*type
= tref
->type
;
5433 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5434 sp
[-1].data
.p
= vt_sp
;
5436 *(gpointer
*)sp
[-1].data
.p
= type
;
5440 MINT_IN_CASE(MINT_REFANYVAL
) {
5441 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5442 gpointer addr
= tref
->value
;
5444 c
= (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)];
5445 if (c
!= tref
->klass
)
5446 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5448 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5450 sp
[-1].data
.p
= addr
;
5454 MINT_IN_CASE(MINT_LDTOKEN
)
5457 * (gpointer
*)sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
5461 MINT_IN_CASE(MINT_ADD_OVF_I4
)
5462 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5463 THROW_EX (mono_get_exception_overflow (), ip
);
5466 MINT_IN_CASE(MINT_ADD_OVF_I8
)
5467 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5468 THROW_EX (mono_get_exception_overflow (), ip
);
5471 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
5472 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5473 THROW_EX (mono_get_exception_overflow (), ip
);
5474 BINOP_CAST(i
, +, guint32
);
5476 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
5477 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5478 THROW_EX (mono_get_exception_overflow (), ip
);
5479 BINOP_CAST(l
, +, guint64
);
5481 MINT_IN_CASE(MINT_MUL_OVF_I4
)
5482 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5483 THROW_EX (mono_get_exception_overflow (), ip
);
5486 MINT_IN_CASE(MINT_MUL_OVF_I8
)
5487 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5488 THROW_EX (mono_get_exception_overflow (), ip
);
5491 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
5492 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5493 THROW_EX (mono_get_exception_overflow (), ip
);
5494 BINOP_CAST(i
, *, guint32
);
5496 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
5497 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5498 THROW_EX (mono_get_exception_overflow (), ip
);
5499 BINOP_CAST(l
, *, guint64
);
5501 MINT_IN_CASE(MINT_SUB_OVF_I4
)
5502 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5503 THROW_EX (mono_get_exception_overflow (), ip
);
5506 MINT_IN_CASE(MINT_SUB_OVF_I8
)
5507 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5508 THROW_EX (mono_get_exception_overflow (), ip
);
5511 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
5512 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5513 THROW_EX (mono_get_exception_overflow (), ip
);
5514 BINOP_CAST(i
, -, guint32
);
5516 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
5517 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5518 THROW_EX (mono_get_exception_overflow (), ip
);
5519 BINOP_CAST(l
, -, guint64
);
5521 MINT_IN_CASE(MINT_START_ABORT_PROT
)
5522 mono_threads_begin_abort_protected_block ();
5525 MINT_IN_CASE(MINT_ENDFINALLY
) {
5527 int clause_index
= *ip
;
5528 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
5530 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
5532 while (sp
> frame
->stack
) {
5536 ip
= (const guint16
*)finally_ips
->data
;
5537 finally_ips
= g_slist_remove (finally_ips
, ip
);
5538 /* Throw abort after the last finally block to avoid confusing EH */
5539 if (pending_abort
&& !finally_ips
)
5540 EXCEPTION_CHECKPOINT
;
5547 MINT_IN_CASE(MINT_LEAVE
) /* Fall through */
5548 MINT_IN_CASE(MINT_LEAVE_S
)
5549 while (sp
> frame
->stack
) {
5554 if (*ip
== MINT_LEAVE_S
) {
5555 ip
+= (short) *(ip
+ 1);
5557 ip
+= (gint32
) READ32 (ip
+ 1);
5560 goto handle_finally
;
5562 MINT_IN_CASE(MINT_LEAVE_CHECK
)
5563 MINT_IN_CASE(MINT_LEAVE_S_CHECK
)
5564 while (sp
> frame
->stack
) {
5569 if (frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
5572 child_frame
.parent
= frame
;
5573 child_frame
.imethod
= NULL
;
5575 * We need for mono_thread_get_undeniable_exception to be able to unwind
5576 * to check the abort threshold. For this to work we use child_frame as a
5577 * dummy frame that is stored in the lmf and serves as the transition frame
5579 do_icall (&child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
);
5581 MonoException
*abort_exc
= (MonoException
*)tmp_sp
.data
.p
;
5583 THROW_EX (abort_exc
, frame
->ip
);
5586 if (*ip
== MINT_LEAVE_S_CHECK
) {
5587 ip
+= (short) *(ip
+ 1);
5589 ip
+= (gint32
) READ32 (ip
+ 1);
5592 goto handle_finally
;
5594 MINT_IN_CASE(MINT_ICALL_V_V
)
5595 MINT_IN_CASE(MINT_ICALL_V_P
)
5596 MINT_IN_CASE(MINT_ICALL_P_V
)
5597 MINT_IN_CASE(MINT_ICALL_P_P
)
5598 MINT_IN_CASE(MINT_ICALL_PP_V
)
5599 MINT_IN_CASE(MINT_ICALL_PP_P
)
5600 MINT_IN_CASE(MINT_ICALL_PPP_V
)
5601 MINT_IN_CASE(MINT_ICALL_PPP_P
)
5602 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
5603 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
5604 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
5605 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
5606 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
5607 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
5609 sp
= do_icall (frame
, NULL
, *ip
, sp
, rtm
->data_items
[*(guint16
*)(ip
+ 1)]);
5610 EXCEPTION_CHECKPOINT
;
5611 CHECK_RESUME_STATE (context
);
5614 MINT_IN_CASE(MINT_MONO_LDPTR
)
5615 sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
5619 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
5620 sp
->data
.p
= mono_object_new_checked (rtm
->domain
, (MonoClass
*)rtm
->data_items
[*(guint16
*)(ip
+ 1)], error
);
5621 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5625 MINT_IN_CASE(MINT_MONO_FREE
)
5628 g_error ("that doesn't seem right");
5629 g_free (sp
->data
.p
);
5631 MINT_IN_CASE(MINT_MONO_RETOBJ
)
5634 stackval_from_data (mono_method_signature_internal (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
5635 mono_method_signature_internal (frame
->imethod
->method
)->pinvoke
);
5636 if (sp
> frame
->stack
)
5637 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
5639 MINT_IN_CASE(MINT_MONO_TLS
) {
5640 MonoTlsKey key
= (MonoTlsKey
)*(gint32
*)(ip
+ 1);
5641 sp
->data
.p
= ((gpointer (*)(void)) mono_tls_get_tls_getter (key
, FALSE
)) ();
5646 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
5648 mono_memory_barrier ();
5651 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
5652 sp
->data
.p
= mono_domain_get ();
5656 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
5657 if (G_UNLIKELY (ss_enabled
)) {
5658 typedef void (*T
) (void);
5662 void *tramp
= mini_get_single_step_trampoline ();
5663 mono_memory_barrier ();
5664 ss_tramp
= (T
)tramp
;
5668 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5669 * the address of that instruction is stored as the seq point address.
5674 * Use the same trampoline as the JIT. This ensures that
5675 * the debugger has the context for the last interpreter
5678 do_debugger_tramp (ss_tramp
, frame
);
5680 CHECK_RESUME_STATE (context
);
5684 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
5685 /* Just a placeholder for a breakpoint */
5688 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
5689 typedef void (*T
) (void);
5692 void *tramp
= mini_get_breakpoint_trampoline ();
5693 mono_memory_barrier ();
5694 bp_tramp
= (T
)tramp
;
5699 /* Use the same trampoline as the JIT */
5700 do_debugger_tramp (bp_tramp
, frame
);
5702 CHECK_RESUME_STATE (context
);
5708 #define RELOP(datamem, op) \
5710 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5713 #define RELOP_FP(datamem, op, noorder) \
5715 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5716 sp [-1].data.i = noorder; \
5718 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5721 MINT_IN_CASE(MINT_CEQ_I4
)
5724 MINT_IN_CASE(MINT_CEQ0_I4
)
5725 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
5728 MINT_IN_CASE(MINT_CEQ_I8
)
5731 MINT_IN_CASE(MINT_CEQ_R4
)
5732 RELOP_FP(f_r4
, ==, 0);
5734 MINT_IN_CASE(MINT_CEQ_R8
)
5737 MINT_IN_CASE(MINT_CNE_I4
)
5740 MINT_IN_CASE(MINT_CNE_I8
)
5743 MINT_IN_CASE(MINT_CNE_R4
)
5744 RELOP_FP(f_r4
, !=, 1);
5746 MINT_IN_CASE(MINT_CNE_R8
)
5749 MINT_IN_CASE(MINT_CGT_I4
)
5752 MINT_IN_CASE(MINT_CGT_I8
)
5755 MINT_IN_CASE(MINT_CGT_R4
)
5756 RELOP_FP(f_r4
, >, 0);
5758 MINT_IN_CASE(MINT_CGT_R8
)
5761 MINT_IN_CASE(MINT_CGE_I4
)
5764 MINT_IN_CASE(MINT_CGE_I8
)
5767 MINT_IN_CASE(MINT_CGE_R4
)
5768 RELOP_FP(f_r4
, >=, 0);
5770 MINT_IN_CASE(MINT_CGE_R8
)
5774 #define RELOP_CAST(datamem, op, type) \
5776 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5779 MINT_IN_CASE(MINT_CGE_UN_I4
)
5780 RELOP_CAST(l
, >=, guint32
);
5782 MINT_IN_CASE(MINT_CGE_UN_I8
)
5783 RELOP_CAST(l
, >=, guint64
);
5786 MINT_IN_CASE(MINT_CGT_UN_I4
)
5787 RELOP_CAST(i
, >, guint32
);
5789 MINT_IN_CASE(MINT_CGT_UN_I8
)
5790 RELOP_CAST(l
, >, guint64
);
5792 MINT_IN_CASE(MINT_CGT_UN_R4
)
5793 RELOP_FP(f_r4
, >, 1);
5795 MINT_IN_CASE(MINT_CGT_UN_R8
)
5798 MINT_IN_CASE(MINT_CLT_I4
)
5801 MINT_IN_CASE(MINT_CLT_I8
)
5804 MINT_IN_CASE(MINT_CLT_R4
)
5805 RELOP_FP(f_r4
, <, 0);
5807 MINT_IN_CASE(MINT_CLT_R8
)
5810 MINT_IN_CASE(MINT_CLT_UN_I4
)
5811 RELOP_CAST(i
, <, guint32
);
5813 MINT_IN_CASE(MINT_CLT_UN_I8
)
5814 RELOP_CAST(l
, <, guint64
);
5816 MINT_IN_CASE(MINT_CLT_UN_R4
)
5817 RELOP_FP(f_r4
, <, 1);
5819 MINT_IN_CASE(MINT_CLT_UN_R8
)
5822 MINT_IN_CASE(MINT_CLE_I4
)
5825 MINT_IN_CASE(MINT_CLE_I8
)
5828 MINT_IN_CASE(MINT_CLE_UN_I4
)
5829 RELOP_CAST(l
, <=, guint32
);
5831 MINT_IN_CASE(MINT_CLE_UN_I8
)
5832 RELOP_CAST(l
, <=, guint64
);
5834 MINT_IN_CASE(MINT_CLE_R4
)
5835 RELOP_FP(f_r4
, <=, 0);
5837 MINT_IN_CASE(MINT_CLE_R8
)
5845 MINT_IN_CASE(MINT_LDFTN
) {
5846 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
5851 MINT_IN_CASE(MINT_LDVIRTFTN
) {
5852 InterpMethod
*m
= (InterpMethod
*)rtm
->data_items
[* (guint16
*)(ip
+ 1)];
5856 THROW_EX (mono_get_exception_null_reference (), ip
- 2);
5858 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
);
5863 #define LDARG(datamem, argtype) \
5864 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
5868 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
5869 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
5870 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
5871 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
5872 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
5873 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
5874 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
5875 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
5876 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
5877 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
5879 MINT_IN_CASE(MINT_LDARG_VT
)
5881 i32
= READ32(ip
+ 2);
5882 memcpy(sp
->data
.p
, frame
->args
+ * (guint16
*)(ip
+ 1), i32
);
5883 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5888 #define STARG(datamem, argtype) \
5890 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5893 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
5894 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
5895 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
5896 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
5897 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
5898 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
5899 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
5900 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
5901 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
5902 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
5904 MINT_IN_CASE(MINT_STARG_VT
)
5905 i32
= READ32(ip
+ 2);
5907 memcpy(frame
->args
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
5908 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5912 #define STINARG(datamem, argtype) \
5914 int n = * (guint16 *)(ip + 1); \
5915 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
5919 MINT_IN_CASE(MINT_STINARG_I1
) STINARG(i
, gint8
); MINT_IN_BREAK
;
5920 MINT_IN_CASE(MINT_STINARG_U1
) STINARG(i
, guint8
); MINT_IN_BREAK
;
5921 MINT_IN_CASE(MINT_STINARG_I2
) STINARG(i
, gint16
); MINT_IN_BREAK
;
5922 MINT_IN_CASE(MINT_STINARG_U2
) STINARG(i
, guint16
); MINT_IN_BREAK
;
5923 MINT_IN_CASE(MINT_STINARG_I4
) STINARG(i
, gint32
); MINT_IN_BREAK
;
5924 MINT_IN_CASE(MINT_STINARG_I8
) STINARG(l
, gint64
); MINT_IN_BREAK
;
5925 MINT_IN_CASE(MINT_STINARG_R4
) STINARG(f_r4
, float); MINT_IN_BREAK
;
5926 MINT_IN_CASE(MINT_STINARG_R8
) STINARG(f
, double); MINT_IN_BREAK
;
5927 MINT_IN_CASE(MINT_STINARG_O
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
5928 MINT_IN_CASE(MINT_STINARG_P
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
5930 MINT_IN_CASE(MINT_STINARG_VT
) {
5931 int n
= * (guint16
*)(ip
+ 1);
5932 i32
= READ32(ip
+ 2);
5933 memcpy (frame
->args
+ rtm
->arg_offsets
[n
], frame
->stack_args
[n
].data
.p
, i32
);
5938 MINT_IN_CASE(MINT_PROF_ENTER
) {
5941 if (MONO_PROFILER_ENABLED (method_enter
)) {
5942 MonoProfilerCallContext
*prof_ctx
= NULL
;
5944 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
5945 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
5946 prof_ctx
->interp_frame
= frame
;
5947 prof_ctx
->method
= frame
->imethod
->method
;
5950 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
5958 MINT_IN_CASE(MINT_LDARGA
)
5959 sp
->data
.p
= frame
->args
+ * (guint16
*)(ip
+ 1);
5964 #define LDLOC(datamem, argtype) \
5965 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
5969 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
5970 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
5971 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
5972 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
5973 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
5974 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
5975 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
5976 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
5977 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
5978 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
5980 MINT_IN_CASE(MINT_LDLOC_VT
)
5982 i32
= READ32(ip
+ 2);
5983 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
5984 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5989 MINT_IN_CASE(MINT_LDLOCA_S
)
5990 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
5995 #define STLOC(datamem, argtype) \
5997 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6000 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6001 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6002 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6003 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6004 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6005 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6006 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6007 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6008 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6009 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6011 #define STLOC_NP(datamem, argtype) \
6012 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6015 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6016 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6018 MINT_IN_CASE(MINT_STLOC_VT
)
6019 i32
= READ32(ip
+ 2);
6021 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
6022 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6026 MINT_IN_CASE(MINT_LOCALLOC
) {
6027 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6028 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6030 int len
= sp
[-1].data
.i
;
6031 sp
[-1].data
.p
= alloca (len
);
6033 if (frame
->imethod
->init_locals
)
6034 memset (sp
[-1].data
.p
, 0, len
);
6038 MINT_IN_CASE(MINT_ENDFILTER
)
6039 /* top of stack is result of filter */
6040 frame
->retval
= &sp
[-1];
6042 MINT_IN_CASE(MINT_INITOBJ
)
6044 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6047 MINT_IN_CASE(MINT_CPBLK
)
6049 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6050 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6052 /* FIXME: value and size may be int64... */
6053 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6056 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6058 /* FIXME: implement */
6060 token
= READ32 (ip
);
6065 MINT_IN_CASE(MINT_INITBLK
)
6068 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6070 /* FIXME: value and size may be int64... */
6071 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6074 MINT_IN_CASE(MINT_NO_
)
6075 /* FIXME: implement */
6079 MINT_IN_CASE(MINT_RETHROW
) {
6080 int exvar_offset
= *(guint16
*)(ip
+ 1);
6081 THROW_EX_GENERAL (*(MonoException
**)(frame
->locals
+ exvar_offset
), ip
, TRUE
);
6084 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6086 * need to clarify what this should actually do:
6088 * Takes an exception from the stack and rethrows it.
6089 * This is useful for wrappers that don't want to have to
6090 * use CEE_THROW and lose the exception stacktrace.
6095 sp
->data
.p
= mono_get_exception_null_reference ();
6097 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6100 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6104 del
= (MonoDelegate
*)sp
->data
.p
;
6105 if (!del
->interp_method
) {
6106 /* Not created from interpreted code */
6108 g_assert (del
->method
);
6109 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6110 mono_error_assert_ok (error
);
6112 g_assert (del
->interp_method
);
6113 sp
->data
.p
= del
->interp_method
;
6118 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6120 int n
= *(guint16
*)(ip
+ 1);
6121 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6122 if (!del
->interp_invoke_impl
) {
6124 * First time we are called. Set up the invoke wrapper. We might be able to do this
6125 * in ctor but we would need to handle AllocDelegateLike_internal separately
6128 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6129 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6130 mono_error_assert_ok (error
);
6133 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6138 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-rtm
->code
);
6139 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip
);
6143 g_assert_not_reached ();
6148 MonoExceptionClause
*clause
;
6149 GSList
*old_list
= finally_ips
;
6150 MonoMethod
*method
= frame
->imethod
->method
;
6154 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- rtm
->code
);
6156 if (rtm
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
6157 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
6160 ip_offset
= frame
->ip
- rtm
->code
;
6162 if (endfinally_ip
!= NULL
)
6163 finally_ips
= g_slist_prepend(finally_ips
, (void *)endfinally_ip
);
6165 for (i
= rtm
->num_clauses
- 1; i
>= 0; i
--) {
6166 clause
= &rtm
->clauses
[i
];
6167 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- rtm
->code
)))) {
6168 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6169 ip
= rtm
->code
+ clause
->handler_offset
;
6170 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
6173 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
6179 endfinally_ip
= NULL
;
6181 if (old_list
!= finally_ips
&& finally_ips
) {
6182 ip
= (const guint16
*)finally_ips
->data
;
6183 finally_ips
= g_slist_remove (finally_ips
, ip
);
6184 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
6185 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
6194 if (clause_args
&& clause_args
->base_frame
)
6195 memcpy (clause_args
->base_frame
->args
, frame
->args
, rtm
->alloca_size
);
6197 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
6198 frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
6199 MonoProfilerCallContext
*prof_ctx
= NULL
;
6201 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
6202 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6203 prof_ctx
->interp_frame
= frame
;
6204 prof_ctx
->method
= frame
->imethod
->method
;
6206 MonoType
*rtype
= mono_method_signature_internal (frame
->imethod
->method
)->ret
;
6208 switch (rtype
->type
) {
6209 case MONO_TYPE_VOID
:
6211 case MONO_TYPE_VALUETYPE
:
6212 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6215 prof_ctx
->return_value
= frame
->retval
;
6220 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
6223 } else if (frame
->ex
&& frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
6224 MONO_PROFILER_RAISE (method_exception_leave
, (frame
->imethod
->method
, &frame
->ex
->object
));
6230 interp_parse_options (const char *options
)
6237 args
= g_strsplit (options
, ",", -1);
6238 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
6241 if (strncmp (arg
, "jit=", 4) == 0)
6242 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
6243 if (strncmp (arg
, "interp-only=", 4) == 0)
6244 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
6245 if (strncmp (arg
, "-inline", 7) == 0)
6246 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6250 typedef int (*TestMethod
) (void);
6253 * interp_set_resume_state:
6255 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6258 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
6260 ThreadContext
*context
;
6263 context
= (ThreadContext
*)jit_tls
->interp_context
;
6266 context
->has_resume_state
= TRUE
;
6267 context
->handler_frame
= (InterpFrame
*)interp_frame
;
6268 context
->handler_ei
= ei
;
6269 /* This is on the stack, so it doesn't need a wbarrier */
6270 context
->handler_frame
->ex
= ex
;
6273 *(MonoException
**)(context
->handler_frame
->locals
+ ei
->exvar_offset
) = ex
;
6274 context
->handler_ip
= (guint16
*) handler_ip
;
6278 * interp_run_finally:
6280 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6281 * frame->interp_frame.
6282 * Return TRUE if the finally clause threw an exception.
6285 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6287 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6288 ThreadContext
*context
= get_context ();
6289 const unsigned short *old_ip
= iframe
->ip
;
6290 FrameClauseArgs clause_args
;
6292 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6293 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6294 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6295 clause_args
.exit_clause
= clause_index
;
6297 interp_exec_method_full (iframe
, context
, &clause_args
);
6298 if (context
->has_resume_state
) {
6301 iframe
->ip
= old_ip
;
6307 * interp_run_filter:
6309 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6310 * frame->interp_frame.
6313 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6315 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6316 ThreadContext
*context
= get_context ();
6317 InterpFrame child_frame
;
6319 FrameClauseArgs clause_args
;
6322 * Have to run the clause in a new frame which is a copy of IFRAME, since
6323 * during debugging, there are two copies of the frame on the stack.
6325 memset (&child_frame
, 0, sizeof (InterpFrame
));
6326 child_frame
.imethod
= iframe
->imethod
;
6327 child_frame
.retval
= &retval
;
6328 child_frame
.parent
= iframe
;
6330 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6331 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6332 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6333 clause_args
.filter_exception
= ex
;
6334 clause_args
.base_frame
= iframe
;
6336 interp_exec_method_full (&child_frame
, context
, &clause_args
);
6337 /* ENDFILTER stores the result into child_frame->retval */
6338 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
6342 InterpFrame
*current
;
6346 * interp_frame_iter_init:
6348 * Initialize an iterator for iterating through interpreted frames.
6351 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
6353 StackIter
*stack_iter
= (StackIter
*)iter
;
6355 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
6359 * interp_frame_iter_next:
6361 * Fill out FRAME with date for the next interpreter frame.
6364 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
6366 StackIter
*stack_iter
= (StackIter
*)iter
;
6367 InterpFrame
*iframe
= stack_iter
->current
;
6369 memset (frame
, 0, sizeof (StackFrameInfo
));
6370 /* pinvoke frames doesn't have imethod set */
6371 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
6372 iframe
= iframe
->parent
;
6376 MonoMethod
*method
= iframe
->imethod
->method
;
6377 frame
->domain
= iframe
->imethod
->domain
;
6378 frame
->interp_frame
= iframe
;
6379 frame
->method
= method
;
6380 frame
->actual_method
= method
;
6381 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
6382 frame
->native_offset
= -1;
6383 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
6385 frame
->type
= FRAME_TYPE_INTERP
;
6386 /* This is the offset in the interpreter IR */
6387 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
6388 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6389 frame
->managed
= TRUE
;
6391 frame
->ji
= iframe
->imethod
->jinfo
;
6392 frame
->frame_addr
= iframe
;
6394 stack_iter
->current
= iframe
->parent
;
6400 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
6404 rtm
= lookup_imethod (domain
, method
);
6412 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6414 guint16
*code
= (guint16
*)ip
;
6415 g_assert (*code
== MINT_SDB_SEQ_POINT
);
6416 *code
= MINT_SDB_BREAKPOINT
;
6420 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6422 guint16
*code
= (guint16
*)ip
;
6423 g_assert (*code
== MINT_SDB_BREAKPOINT
);
6424 *code
= MINT_SDB_SEQ_POINT
;
6428 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
6430 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6432 g_assert (iframe
->imethod
);
6433 return iframe
->imethod
->jinfo
;
6437 interp_frame_get_ip (MonoInterpFrameHandle frame
)
6439 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6441 g_assert (iframe
->imethod
);
6442 return (gpointer
)iframe
->ip
;
6446 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
6448 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6450 g_assert (iframe
->imethod
);
6452 int arg_offset
= iframe
->imethod
->arg_offsets
[pos
+ (iframe
->imethod
->hasthis
? 1 : 0)];
6454 return iframe
->args
+ arg_offset
;
6458 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
6460 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6462 g_assert (iframe
->imethod
);
6464 return iframe
->locals
+ iframe
->imethod
->local_offsets
[pos
];
6468 interp_frame_get_this (MonoInterpFrameHandle frame
)
6470 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6472 g_assert (iframe
->imethod
);
6473 g_assert (iframe
->imethod
->hasthis
);
6475 int arg_offset
= iframe
->imethod
->arg_offsets
[0];
6477 return iframe
->args
+ arg_offset
;
6480 static MonoInterpFrameHandle
6481 interp_frame_get_parent (MonoInterpFrameHandle frame
)
6483 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6485 return iframe
->parent
;
6489 interp_start_single_stepping (void)
6495 interp_stop_single_stepping (void)
6501 mono_ee_interp_init (const char *opts
)
6503 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
6504 g_assert (!interp_init_done
);
6505 interp_init_done
= TRUE
;
6507 mono_native_tls_alloc (&thread_context_id
, NULL
);
6510 interp_parse_options (opts
);
6511 if (mini_get_debug_options ()->mdb_optimizations
)
6512 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6513 mono_interp_transform_init ();
6516 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
6517 c
.entry_from_trampoline
= interp_entry_from_trampoline
;
6519 c
.to_native_trampoline
= interp_to_native_trampoline
;
6520 c
.create_method_pointer
= interp_create_method_pointer
;
6521 c
.create_method_pointer_llvmonly
= interp_create_method_pointer_llvmonly
;
6522 c
.runtime_invoke
= interp_runtime_invoke
;
6523 c
.init_delegate
= interp_init_delegate
;
6524 c
.delegate_ctor
= interp_delegate_ctor
;
6525 c
.get_remoting_invoke
= interp_get_remoting_invoke
;
6526 c
.set_resume_state
= interp_set_resume_state
;
6527 c
.run_finally
= interp_run_finally
;
6528 c
.run_filter
= interp_run_filter
;
6529 c
.frame_iter_init
= interp_frame_iter_init
;
6530 c
.frame_iter_next
= interp_frame_iter_next
;
6531 c
.find_jit_info
= interp_find_jit_info
;
6532 c
.set_breakpoint
= interp_set_breakpoint
;
6533 c
.clear_breakpoint
= interp_clear_breakpoint
;
6534 c
.frame_get_jit_info
= interp_frame_get_jit_info
;
6535 c
.frame_get_ip
= interp_frame_get_ip
;
6536 c
.frame_get_arg
= interp_frame_get_arg
;
6537 c
.frame_get_local
= interp_frame_get_local
;
6538 c
.frame_get_this
= interp_frame_get_this
;
6539 c
.frame_get_parent
= interp_frame_get_parent
;
6540 c
.frame_arg_to_data
= interp_frame_arg_to_data
;
6541 c
.data_to_frame_arg
= interp_data_to_frame_arg
;
6542 c
.frame_arg_to_storage
= interp_frame_arg_to_storage
;
6543 c
.frame_arg_set_storage
= interp_frame_arg_set_storage
;
6544 c
.start_single_stepping
= interp_start_single_stepping
;
6545 c
.stop_single_stepping
= interp_stop_single_stepping
;
6546 mini_install_interp_callbacks (&c
);