4 * interp.c: Interpreter for CIL byte codes
7 * Paolo Molaro (lupus@ximian.com)
8 * Miguel de Icaza (miguel@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2001, 2002 Ximian, Inc.
25 #include <mono/utils/gc_wrapper.h>
26 #include <mono/utils/mono-math.h>
27 #include <mono/utils/mono-counters.h>
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
62 #include "interp-internals.h"
65 #include <mono/mini/mini.h>
66 #include <mono/mini/mini-runtime.h>
67 #include <mono/mini/aot-runtime.h>
68 #include <mono/mini/llvm-runtime.h>
69 #include <mono/mini/llvmonly-runtime.h>
70 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
73 #include <mono/mini/trace.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 const 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.
93 const guint16
*end_at_ip
;
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
;
111 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
114 * List of classes whose methods will be executed by transitioning to JITted code.
117 GSList
*mono_interp_jit_classes
;
118 /* Optimizations enabled with interpreter */
119 int mono_interp_opt
= INTERP_OPT_DEFAULT
;
120 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
121 static gboolean ss_enabled
;
123 static gboolean interp_init_done
= FALSE
;
125 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
);
126 static InterpMethod
* lookup_method_pointer (gpointer addr
);
128 typedef void (*ICallMethod
) (InterpFrame
*frame
);
130 static MonoNativeTlsKey thread_context_id
;
132 #define DEBUG_INTERP 0
136 int mono_interp_traceopt
= 2;
137 /* If true, then we output the opcodes as we interpret them */
138 static int global_tracing
= 2;
140 static int debug_indent_level
= 0;
142 static int break_on_method
= 0;
143 static int nested_trace
= 0;
144 static GList
*db_methods
= NULL
;
145 static char* dump_args (InterpFrame
*inv
);
152 for (h
= 0; h
< debug_indent_level
; h
++)
157 db_match_method (gpointer data
, gpointer user_data
)
159 MonoMethod
*m
= (MonoMethod
*)user_data
;
160 MonoMethodDesc
*desc
= data
;
162 if (mono_method_desc_full_match (desc
, m
))
167 debug_enter (InterpFrame
*frame
, int *tracing
)
170 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
172 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
176 MonoMethod
*method
= frame
->imethod
->method
;
177 char *mn
, *args
= dump_args (frame
);
178 debug_indent_level
++;
180 mn
= mono_method_full_name (method
, FALSE
);
181 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
183 g_print ("%s)\n", args
);
189 #define DEBUG_LEAVE() \
192 args = dump_retval (frame); \
194 mn = mono_method_full_name (frame->imethod->method, FALSE); \
195 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
197 g_print (" => %s\n", args); \
199 debug_indent_level--; \
200 if (tracing == 3) global_tracing = 0; \
205 int mono_interp_traceopt
= 0;
206 #define DEBUG_LEAVE()
210 #if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP
211 #define USE_COMPUTED_GOTO 1
214 #if USE_COMPUTED_GOTO
216 #define MINT_IN_SWITCH(op) goto *in_labels[op];
217 #define MINT_IN_CASE(x) LAB_ ## x:
218 #define MINT_IN_DISPATCH(op) goto *in_labels[op];
219 #define MINT_IN_BREAK { goto *in_labels[*ip]; }
220 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
224 #define MINT_IN_SWITCH(op) COUNT_OP(op); switch (op)
225 #define MINT_IN_CASE(x) case x:
226 #define MINT_IN_DISPATCH(op) goto main_loop;
227 #define MINT_IN_BREAK break
228 #define MINT_IN_DEFAULT default:
233 clear_resume_state (ThreadContext
*context
, GSList
*finally_ips
)
235 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
236 while (finally_ips
&&
237 finally_ips
->data
>= context
->handler_ei
->try_start
&&
238 finally_ips
->data
< context
->handler_ei
->try_end
)
239 finally_ips
= g_slist_remove (finally_ips
, finally_ips
->data
);
240 context
->has_resume_state
= 0;
241 context
->handler_frame
= NULL
;
242 context
->handler_ei
= NULL
;
243 g_assert (context
->exc_gchandle
);
244 mono_gchandle_free_internal (context
->exc_gchandle
);
245 context
->exc_gchandle
= 0;
250 * If this bit is set, it means the call has thrown the exception, and we
251 * reached this point because the EH code in mono_handle_exception ()
252 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
253 * has set the fields in context to indicate where we have to resume execution.
255 #define CHECK_RESUME_STATE(context) do { \
256 if ((context)->has_resume_state) \
261 set_context (ThreadContext
*context
)
263 mono_native_tls_set_value (thread_context_id
, context
);
268 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
269 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
271 /* jit_tls assumes ownership of 'context' */
272 jit_tls
->interp_context
= context
;
275 static ThreadContext
*
278 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
279 if (context
== NULL
) {
280 context
= g_new0 (ThreadContext
, 1);
281 set_context (context
);
287 mono_interp_error_cleanup (MonoError
* error
)
289 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
290 error_init_reuse (error
); // one instruction, so this function is good inline candidate
293 static MONO_NEVER_INLINE
void
294 ves_real_abort (int line
, MonoMethod
*mh
,
295 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
298 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
299 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
300 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
301 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
302 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
303 mono_metadata_free_mh (header
);
306 #define ves_abort() \
308 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
313 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
315 InterpMethod
*imethod
;
316 MonoJitDomainInfo
*info
;
318 info
= domain_jit_info (domain
);
319 mono_domain_jit_code_hash_lock (domain
);
320 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
321 mono_domain_jit_code_hash_unlock (domain
);
326 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
328 #ifndef DISABLE_REMOTING
329 InterpMethod
*imethod
;
332 imethod
= lookup_method_pointer (addr
);
335 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
336 return_val_if_nok (error
, NULL
);
339 g_assert (mono_use_interpreter
);
341 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
342 return_val_if_nok (error
, NULL
);
343 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
345 g_assert_not_reached ();
351 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
353 InterpMethod
*imethod
;
354 MonoJitDomainInfo
*info
;
355 MonoMethodSignature
*sig
;
360 info
= domain_jit_info (domain
);
361 mono_domain_jit_code_hash_lock (domain
);
362 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
363 mono_domain_jit_code_hash_unlock (domain
);
367 sig
= mono_method_signature_internal (method
);
369 imethod
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
370 imethod
->method
= method
;
371 imethod
->domain
= domain
;
372 imethod
->param_count
= sig
->param_count
;
373 imethod
->hasthis
= sig
->hasthis
;
374 imethod
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
375 imethod
->rtype
= mini_get_underlying_type (sig
->ret
);
376 imethod
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
377 for (i
= 0; i
< sig
->param_count
; ++i
)
378 imethod
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
380 mono_domain_jit_code_hash_lock (domain
);
381 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
382 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, imethod
);
383 mono_domain_jit_code_hash_unlock (domain
);
385 imethod
->prof_flags
= mono_profiler_get_call_instrumentation_flags (imethod
->method
);
390 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
391 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
392 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
394 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
395 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
396 * (registers are not accurate), thus resuming to the label does not work. */
397 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
398 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
399 #elif defined (_MSC_VER)
400 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
401 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
402 (ext).interp_exit_label_set = FALSE; \
403 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
404 if ((ext).interp_exit_label_set == FALSE) \
405 mono_arch_do_ip_adjustment (&(ext).ctx); \
406 if ((ext).interp_exit_label_set == TRUE) \
408 (ext).interp_exit_label_set = TRUE;
409 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
410 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
411 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
412 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
413 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
414 mono_arch_do_ip_adjustment (&(ext).ctx);
416 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
419 /* INTERP_PUSH_LMF_WITH_CTX:
421 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
422 * This is needed to resume into the interp when the exception is thrown from
423 * native code (see ./mono/tests/install_eh_callback.exe).
425 * This must be a macro in order to retrieve the right register values for
428 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
429 memset (&(ext), 0, sizeof (MonoLMFExt)); \
430 (ext).interp_exit_data = (frame); \
431 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
432 mono_push_lmf (&(ext));
437 * Push an LMF frame on the LMF stack
438 * to mark the transition to native code.
439 * This is needed for the native code to
440 * be able to do stack walks.
443 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
445 memset (ext
, 0, sizeof (MonoLMFExt
));
446 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
447 ext
->interp_exit_data
= frame
;
453 interp_pop_lmf (MonoLMFExt
*ext
)
455 mono_pop_lmf (&ext
->lmf
);
458 static MONO_NEVER_INLINE InterpMethod
*
459 get_virtual_method (InterpMethod
*imethod
, MonoVTable
*vtable
)
461 MonoMethod
*m
= imethod
->method
;
462 MonoDomain
*domain
= imethod
->domain
;
463 InterpMethod
*ret
= NULL
;
465 #ifndef DISABLE_REMOTING
466 if (mono_class_is_transparent_proxy (vtable
->klass
)) {
468 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
469 mono_error_assert_ok (error
);
470 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
471 mono_error_assert_ok (error
);
476 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
477 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
479 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
480 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
487 mono_class_setup_vtable (vtable
->klass
);
489 int slot
= mono_method_get_vtable_slot (m
);
490 if (mono_class_is_interface (m
->klass
)) {
491 g_assert (vtable
->klass
!= m
->klass
);
492 /* TODO: interface offset lookup is slow, go through IMT instead */
493 gboolean non_exact_match
;
494 slot
+= mono_class_interface_offset_with_variance (vtable
->klass
, m
->klass
, &non_exact_match
);
497 MonoMethod
*virtual_method
= m_class_get_vtable (vtable
->klass
) [slot
];
498 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
499 MonoGenericContext context
= { NULL
, NULL
};
501 if (mono_class_is_ginst (virtual_method
->klass
))
502 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
503 else if (mono_class_is_gtd (virtual_method
->klass
))
504 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
505 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
508 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
509 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
512 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
513 virtual_method
= mono_marshal_get_native_wrapper (virtual_method
, FALSE
, FALSE
);
516 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
517 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
521 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
522 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
523 return virtual_imethod
;
527 InterpMethod
*imethod
;
528 InterpMethod
*target_imethod
;
531 /* domain lock must be held */
533 append_imethod (MonoDomain
*domain
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
536 InterpVTableEntry
*entry
;
538 entry
= (InterpVTableEntry
*) mono_mempool_alloc (domain
->mp
, sizeof (InterpVTableEntry
));
539 entry
->imethod
= imethod
;
540 entry
->target_imethod
= target_imethod
;
541 ret
= g_slist_append_mempool (domain
->mp
, list
, entry
);
547 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
549 while (list
!= NULL
) {
550 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
551 if (entry
->imethod
== imethod
)
552 return entry
->target_imethod
;
559 get_method_table (MonoVTable
*vtable
, int offset
)
562 return vtable
->interp_vtable
;
564 return (gpointer
*)vtable
;
568 alloc_method_table (MonoVTable
*vtable
, int offset
)
573 table
= mono_domain_alloc0 (vtable
->domain
, m_class_get_vtable_size (vtable
->klass
) * sizeof (gpointer
));
574 vtable
->interp_vtable
= table
;
576 table
= (gpointer
*)vtable
;
582 static MONO_NEVER_INLINE InterpMethod
* // Inlining causes additional stack use in caller.
583 get_virtual_method_fast (InterpMethod
*imethod
, MonoVTable
*vtable
, int offset
)
587 #ifndef DISABLE_REMOTING
589 if (mono_class_is_transparent_proxy (vtable
->klass
))
590 return get_virtual_method (imethod
, vtable
);
593 table
= get_method_table (vtable
, offset
);
596 /* Lazily allocate method table */
597 mono_domain_lock (vtable
->domain
);
598 table
= get_method_table (vtable
, offset
);
600 table
= alloc_method_table (vtable
, offset
);
601 mono_domain_unlock (vtable
->domain
);
604 if (!table
[offset
]) {
605 InterpMethod
*target_imethod
= get_virtual_method (imethod
, vtable
);
606 /* Lazily initialize the method table slot */
607 mono_domain_lock (vtable
->domain
);
608 if (!table
[offset
]) {
609 if (imethod
->method
->is_inflated
|| offset
< 0)
610 table
[offset
] = append_imethod (vtable
->domain
, NULL
, imethod
, target_imethod
);
612 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
614 mono_domain_unlock (vtable
->domain
);
617 if ((gsize
)table
[offset
] & 0x1) {
618 /* Non generic virtual call. Only one method in slot */
619 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
621 /* Virtual generic or interface call. Multiple methods in slot */
622 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
624 if (!target_imethod
) {
625 target_imethod
= get_virtual_method (imethod
, vtable
);
626 mono_domain_lock (vtable
->domain
);
627 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
628 table
[offset
] = append_imethod (vtable
->domain
, (GSList
*)table
[offset
], imethod
, target_imethod
);
629 mono_domain_unlock (vtable
->domain
);
631 return target_imethod
;
636 stackval_from_data (MonoType
*type
, stackval
*result
, const void *data
, gboolean pinvoke
)
638 type
= mini_native_type_replace_type (type
);
640 switch (type
->type
) {
641 case MONO_TYPE_OBJECT
:
642 case MONO_TYPE_CLASS
:
643 case MONO_TYPE_STRING
:
644 case MONO_TYPE_ARRAY
:
645 case MONO_TYPE_SZARRAY
:
650 result
->data
.p
= *(gpointer
*)data
;
653 switch (type
->type
) {
657 result
->data
.i
= *(gint8
*)data
;
660 case MONO_TYPE_BOOLEAN
:
661 result
->data
.i
= *(guint8
*)data
;
664 result
->data
.i
= *(gint16
*)data
;
668 result
->data
.i
= *(guint16
*)data
;
671 result
->data
.i
= *(gint32
*)data
;
675 result
->data
.nati
= *(mono_i
*)data
;
678 result
->data
.p
= *(gpointer
*)data
;
681 result
->data
.i
= *(guint32
*)data
;
684 /* memmove handles unaligned case */
685 memmove (&result
->data
.f_r4
, data
, sizeof (float));
689 memmove (&result
->data
.l
, data
, sizeof (gint64
));
692 memmove (&result
->data
.f
, data
, sizeof (double));
694 case MONO_TYPE_STRING
:
695 case MONO_TYPE_SZARRAY
:
696 case MONO_TYPE_CLASS
:
697 case MONO_TYPE_OBJECT
:
698 case MONO_TYPE_ARRAY
:
699 result
->data
.p
= *(gpointer
*)data
;
701 case MONO_TYPE_VALUETYPE
:
702 if (m_class_is_enumtype (type
->data
.klass
)) {
703 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
705 } else if (pinvoke
) {
706 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
708 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
711 case MONO_TYPE_GENERICINST
: {
712 if (mono_type_generic_inst_is_valuetype (type
)) {
713 mono_value_copy_internal (result
->data
.vt
, data
, mono_class_from_mono_type_internal (type
));
716 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
720 g_error ("got type 0x%02x", type
->type
);
725 stackval_to_data (MonoType
*type
, stackval
*val
, void *data
, gboolean pinvoke
)
727 type
= mini_native_type_replace_type (type
);
729 gpointer
*p
= (gpointer
*)data
;
733 /* printf ("TODAT0 %p\n", data); */
734 switch (type
->type
) {
737 guint8
*p
= (guint8
*)data
;
741 case MONO_TYPE_BOOLEAN
: {
742 guint8
*p
= (guint8
*)data
;
743 *p
= (val
->data
.i
!= 0);
748 case MONO_TYPE_CHAR
: {
749 guint16
*p
= (guint16
*)data
;
754 mono_i
*p
= (mono_i
*)data
;
755 /* In theory the value used by stloc should match the local var type
756 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
757 a native int - both by csc and mcs). Not sure what to do about sign extension
758 as it is outside the spec... doing the obvious */
759 *p
= (mono_i
)val
->data
.nati
;
763 mono_u
*p
= (mono_u
*)data
;
765 *p
= (mono_u
)val
->data
.nati
;
770 gint32
*p
= (gint32
*)data
;
776 memmove (data
, &val
->data
.l
, sizeof (gint64
));
780 /* memmove handles unaligned case */
781 memmove (data
, &val
->data
.f_r4
, sizeof (float));
785 memmove (data
, &val
->data
.f
, sizeof (double));
788 case MONO_TYPE_STRING
:
789 case MONO_TYPE_SZARRAY
:
790 case MONO_TYPE_CLASS
:
791 case MONO_TYPE_OBJECT
:
792 case MONO_TYPE_ARRAY
: {
793 gpointer
*p
= (gpointer
*) data
;
794 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
797 case MONO_TYPE_PTR
: {
798 gpointer
*p
= (gpointer
*) data
;
802 case MONO_TYPE_VALUETYPE
:
803 if (m_class_is_enumtype (type
->data
.klass
)) {
804 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
806 } else if (pinvoke
) {
807 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
809 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
812 case MONO_TYPE_GENERICINST
: {
813 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
815 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
816 mono_value_copy_internal (data
, val
->data
.vt
, mono_class_from_mono_type_internal (type
));
819 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
823 g_error ("got type %x", type
->type
);
828 * Same as stackval_to_data but return address of storage instead
829 * of copying the value.
832 stackval_to_data_addr (MonoType
*type
, stackval
*val
)
834 type
= mini_native_type_replace_type (type
);
838 switch (type
->type
) {
841 case MONO_TYPE_BOOLEAN
:
850 return &val
->data
.nati
;
855 return &val
->data
.f_r4
;
858 case MONO_TYPE_STRING
:
859 case MONO_TYPE_SZARRAY
:
860 case MONO_TYPE_CLASS
:
861 case MONO_TYPE_OBJECT
:
862 case MONO_TYPE_ARRAY
:
865 case MONO_TYPE_VALUETYPE
:
866 if (m_class_is_enumtype (type
->data
.klass
))
867 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
870 case MONO_TYPE_TYPEDBYREF
:
872 case MONO_TYPE_GENERICINST
: {
873 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
875 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
877 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
880 g_error ("got type %x", type
->type
);
886 * Throw an exception from the interpreter.
888 static MONO_NEVER_INLINE
void
889 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, const guint16
* ip
, gboolean rethrow
)
894 interp_push_lmf (&ext
, frame
);
897 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
898 MonoException
*mono_ex
= ex
;
900 mono_ex
->stack_trace
= NULL
;
901 mono_ex
->trace_ips
= NULL
;
904 mono_error_assert_ok (error
);
907 memset (&ctx
, 0, sizeof (MonoContext
));
908 MONO_CONTEXT_SET_SP (&ctx
, frame
);
911 * Call the JIT EH code. The EH code will call back to us using:
912 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
913 * Since ctx.ip is 0, this will start unwinding from the LMF frame
914 * pushed above, which points to our frames.
916 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
917 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
918 /* We need to unwind into non-interpreter code */
919 mono_restore_context (&ctx
);
920 g_assert_not_reached ();
923 interp_pop_lmf (&ext
);
925 g_assert (context
->has_resume_state
);
928 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
930 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
934 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
936 #define NULL_CHECK(o) do { \
937 if (G_UNLIKELY (!(o))) \
941 #define EXCEPTION_CHECKPOINT \
943 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
944 MonoException *exc = mono_thread_interruption_checkpoint (); \
946 THROW_EX (exc, ip); \
951 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
953 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
954 MonoException *exc = mono_thread_interruption_checkpoint (); \
961 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
964 intptr_t *lower_bounds
;
967 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
968 for (i
= 0; i
< param_count
; ++i
) {
969 lengths
[i
] = values
->data
.i
;
972 if (m_class_get_rank (klass
) == param_count
) {
973 /* Only lengths provided. */
976 /* lower bounds are first. */
977 lower_bounds
= (intptr_t *) lengths
;
978 lengths
+= m_class_get_rank (klass
);
980 return (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
984 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, gboolean safe
)
986 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
990 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
991 guint32 idx
= sp
[i
].data
.i
;
992 guint32 lower
= ao
->bounds
[i
].lower_bound
;
993 guint32 len
= ao
->bounds
[i
].length
;
994 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
))
996 pos
= (pos
* len
) + idx
- lower
;
1000 if (safe
&& pos
>= ao
->max_length
)
1006 static MonoException
*
1007 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1009 MonoObject
*o
= sp
->data
.o
;
1010 MonoArray
*ao
= (MonoArray
*) o
;
1011 MonoClass
*ac
= o
->vtable
->klass
;
1013 g_assert (m_class_get_rank (ac
) >= 1);
1015 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, safe
);
1017 return mono_get_exception_index_out_of_range ();
1019 gint32 esize
= mono_array_element_size (ac
);
1020 gconstpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1022 MonoType
*mt
= sig
->ret
;
1023 stackval_from_data (mt
, retval
, ea
, FALSE
);
1027 static MONO_NEVER_INLINE MonoException
*
1028 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1030 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1032 g_assert (m_class_get_rank (ac
) >= 1);
1034 gint32 pos
= ves_array_calculate_index (ao
, sp
, TRUE
);
1036 return mono_get_exception_index_out_of_range ();
1038 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
))
1039 return mono_get_exception_array_type_mismatch ();
1040 gint32 esize
= mono_array_element_size (ac
);
1041 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1045 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1046 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1049 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1050 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1052 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1055 g_assert (mono_arm_eabi_supported ());
1056 int i8_align
= mono_arm_i8_align ();
1066 for (int i
= 0; i
< sig
->param_count
; i
++) {
1067 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1069 case MONO_TYPE_BOOLEAN
:
1070 case MONO_TYPE_CHAR
:
1080 case MONO_TYPE_SZARRAY
:
1081 case MONO_TYPE_CLASS
:
1082 case MONO_TYPE_OBJECT
:
1083 case MONO_TYPE_STRING
:
1084 case MONO_TYPE_VALUETYPE
:
1085 case MONO_TYPE_GENERICINST
:
1086 #if SIZEOF_VOID_P == 8
1092 #if SIZEOF_VOID_P == 4
1096 /* pairs begin at even registers */
1097 if (i8_align
== 8 && margs
->ilen
& 1)
1104 #if SIZEOF_VOID_P == 8
1109 #if SIZEOF_VOID_P == 4
1115 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1119 if (margs
->ilen
> 0)
1120 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1122 if (margs
->flen
> 0)
1123 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1125 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1126 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1128 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1129 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1136 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1140 for (int i
= 0; i
< sig
->param_count
; i
++) {
1141 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1143 case MONO_TYPE_BOOLEAN
:
1144 case MONO_TYPE_CHAR
:
1154 case MONO_TYPE_SZARRAY
:
1155 case MONO_TYPE_CLASS
:
1156 case MONO_TYPE_OBJECT
:
1157 case MONO_TYPE_STRING
:
1158 case MONO_TYPE_VALUETYPE
:
1159 case MONO_TYPE_GENERICINST
:
1160 #if SIZEOF_VOID_P == 8
1164 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1166 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1170 #if SIZEOF_VOID_P == 4
1172 case MONO_TYPE_U8
: {
1173 stackval
*sarg
= &frame
->stack_args
[i
];
1175 /* pairs begin at even registers */
1176 if (i8_align
== 8 && int_i
& 1)
1179 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1181 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1183 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
);
1191 if (ptype
== MONO_TYPE_R4
)
1192 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1194 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1196 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
);
1198 #if SIZEOF_VOID_P == 4
1205 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1209 switch (sig
->ret
->type
) {
1210 case MONO_TYPE_BOOLEAN
:
1211 case MONO_TYPE_CHAR
:
1221 case MONO_TYPE_SZARRAY
:
1222 case MONO_TYPE_CLASS
:
1223 case MONO_TYPE_OBJECT
:
1224 case MONO_TYPE_STRING
:
1227 case MONO_TYPE_VALUETYPE
:
1228 case MONO_TYPE_GENERICINST
:
1229 margs
->retval
= &(frame
->retval
->data
.p
);
1230 margs
->is_float_ret
= 0;
1234 margs
->retval
= &(frame
->retval
->data
.p
);
1235 margs
->is_float_ret
= 1;
1237 case MONO_TYPE_VOID
:
1238 margs
->retval
= NULL
;
1241 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1249 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1251 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1254 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1256 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1260 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gconstpointer data
)
1262 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1265 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1266 else if (sig
->hasthis
&& index
== 0)
1267 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1269 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1273 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1275 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1278 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1280 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1284 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1286 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1287 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1288 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1290 switch (type
->type
) {
1291 case MONO_TYPE_GENERICINST
:
1292 if (!MONO_TYPE_IS_REFERENCE (type
))
1293 val
->data
.vt
= storage
;
1295 case MONO_TYPE_VALUETYPE
:
1296 val
->data
.vt
= storage
;
1299 g_assert_not_reached ();
1304 get_interp_to_native_trampoline (void)
1306 static MonoPIFunc trampoline
= NULL
;
1309 if (mono_ee_features
.use_aot_trampolines
) {
1310 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1312 MonoTrampInfo
*info
;
1313 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1314 mono_tramp_info_register (info
, NULL
);
1316 mono_memory_barrier ();
1322 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1324 get_interp_to_native_trampoline () (addr
, ccontext
);
1327 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1329 #pragma optimize ("", off)
1331 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1332 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, ThreadContext
*context
, gboolean save_last_error
)
1337 g_assert (!frame
->imethod
);
1339 static MonoPIFunc entry_func
= NULL
;
1341 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1343 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
);
1344 mono_error_assert_ok (error
);
1346 entry_func
= get_interp_to_native_trampoline ();
1348 mono_memory_barrier ();
1351 #ifdef ENABLE_NETCORE
1352 if (save_last_error
) {
1353 mono_marshal_clear_last_error ();
1357 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1358 CallContext ccontext
;
1359 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1362 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1366 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_pinvoke
);
1367 entry_func ((gpointer
) addr
, args
);
1368 if (save_last_error
)
1369 mono_marshal_set_last_error ();
1370 interp_pop_lmf (&ext
);
1372 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1373 if (!context
->has_resume_state
)
1374 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1376 if (ccontext
.stack
!= NULL
)
1377 g_free (ccontext
.stack
);
1379 if (!context
->has_resume_state
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1380 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1382 g_free (margs
->iargs
);
1383 g_free (margs
->fargs
);
1386 goto exit_pinvoke
; // prevent unused label warning in some configurations
1391 #pragma optimize ("", on)
1395 * interp_init_delegate:
1397 * Initialize del->interp_method.
1400 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1404 if (del
->interp_method
) {
1405 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1406 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1407 } else if (del
->method
) {
1408 /* Delegate created dynamically */
1409 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1411 /* Created from JITted code */
1412 g_assert_not_reached ();
1415 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1418 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1419 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1420 mono_class_is_abstract (method
->klass
))
1421 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1423 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1424 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1425 const char *name
= method
->name
;
1426 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1428 * When invoking the delegate interp_method is executed directly. If it's an
1429 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1431 * FIXME We should do this later, when we also know the delegate on which the
1432 * target method is called.
1434 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1435 mono_error_assert_ok (error
);
1439 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1440 /* Return any errors from method compilation */
1441 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1442 return_if_nok (error
);
1447 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1450 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1452 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1454 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1455 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1456 /* virtual invoke delegates must not have null check */
1457 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1458 && MONO_HANDLE_IS_NULL (target
)) {
1459 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1464 g_assert (imethod
->method
);
1465 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1466 return_if_nok (error
);
1468 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1470 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1475 * runtime specifies that the implementation of the method is automatically
1476 * provided by the runtime and is primarily used for the methods of delegates.
1478 static MONO_NEVER_INLINE MonoException
*
1479 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1481 const char *name
= method
->name
;
1482 mono_class_init_internal (method
->klass
);
1484 if (method
->klass
== mono_defaults
.array_class
) {
1485 if (!strcmp (name
, "UnsafeMov")) {
1486 /* TODO: layout checks */
1487 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1490 if (!strcmp (name
, "UnsafeLoad"))
1491 return ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1494 g_error ("Don't know how to exec runtime method %s.%s::%s",
1495 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1501 dump_stack (stackval
*stack
, stackval
*sp
)
1503 stackval
*s
= stack
;
1504 GString
*str
= g_string_new ("");
1507 return g_string_free (str
, FALSE
);
1510 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1513 return g_string_free (str
, FALSE
);
1517 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1519 switch (type
->type
) {
1526 case MONO_TYPE_CHAR
:
1527 case MONO_TYPE_BOOLEAN
:
1528 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1530 case MONO_TYPE_STRING
:
1531 case MONO_TYPE_SZARRAY
:
1532 case MONO_TYPE_CLASS
:
1533 case MONO_TYPE_OBJECT
:
1534 case MONO_TYPE_ARRAY
:
1538 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1540 case MONO_TYPE_VALUETYPE
:
1541 if (m_class_is_enumtype (type
->data
.klass
))
1542 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1544 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1547 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1550 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1555 GString
*res
= g_string_new ("");
1556 mono_type_get_desc (res
, type
, TRUE
);
1557 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1558 g_string_free (res
, TRUE
);
1565 dump_retval (InterpFrame
*inv
)
1567 GString
*str
= g_string_new ("");
1568 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1570 if (ret
->type
!= MONO_TYPE_VOID
)
1571 dump_stackval (str
, inv
->retval
, ret
);
1573 return g_string_free (str
, FALSE
);
1577 dump_args (InterpFrame
*inv
)
1579 GString
*str
= g_string_new ("");
1581 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1583 if (signature
->param_count
== 0 && !signature
->hasthis
)
1584 return g_string_free (str
, FALSE
);
1586 if (signature
->hasthis
) {
1587 MonoMethod
*method
= inv
->imethod
->method
;
1588 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1591 for (i
= 0; i
< signature
->param_count
; ++i
)
1592 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1594 return g_string_free (str
, FALSE
);
1598 #define CHECK_ADD_OVERFLOW(a,b) \
1599 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1600 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1602 #define CHECK_SUB_OVERFLOW(a,b) \
1603 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1604 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1606 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1607 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1609 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1610 (guint32)(a) < (guint32)(b) ? -1 : 0
1612 #define CHECK_ADD_OVERFLOW64(a,b) \
1613 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1614 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1616 #define CHECK_SUB_OVERFLOW64(a,b) \
1617 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1618 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1620 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1621 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1623 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1624 (guint64)(a) < (guint64)(b) ? -1 : 0
1626 #if SIZEOF_VOID_P == 4
1627 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1628 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1630 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1631 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1634 /* Resolves to TRUE if the operands would overflow */
1635 #define CHECK_MUL_OVERFLOW(a,b) \
1636 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1637 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1638 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1639 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1640 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1641 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1642 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1644 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1645 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1646 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1648 #define CHECK_MUL_OVERFLOW64(a,b) \
1649 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1650 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1651 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1652 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1653 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1654 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1655 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1657 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1658 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1659 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1661 #if SIZEOF_VOID_P == 4
1662 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1663 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1665 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1666 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1670 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1673 ThreadContext
*context
= get_context ();
1674 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1675 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1677 MonoMethod
*target_method
= method
;
1683 MonoDomain
*domain
= mono_domain_get ();
1685 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1686 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1687 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1689 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1691 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1695 args
[0].data
.p
= obj
;
1697 args
[0].data
.p
= NULL
;
1698 args
[1].data
.p
= params
;
1699 args
[2].data
.p
= exc
;
1700 args
[3].data
.p
= target_method
;
1702 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1703 mono_error_assert_ok (error
);
1704 init_frame (&frame
, NULL
, imethod
, args
, &result
);
1706 interp_exec_method (&frame
, context
, error
);
1708 if (context
->has_resume_state
) {
1709 // This can happen on wasm !?
1710 MonoException
*thrown_exc
= (MonoException
*) mono_gchandle_get_target_internal (context
->exc_gchandle
);
1712 *exc
= (MonoObject
*)thrown_exc
;
1714 mono_error_set_exception_instance (error
, thrown_exc
);
1717 return (MonoObject
*)result
.data
.p
;
1721 InterpMethod
*rmethod
;
1725 gpointer
*many_args
;
1728 /* Main function for entering the interpreter from compiled code */
1730 interp_entry (InterpEntryData
*data
)
1733 InterpMethod
*rmethod
;
1734 ThreadContext
*context
;
1738 MonoMethodSignature
*sig
;
1740 gpointer orig_domain
= NULL
, attach_cookie
;
1743 if ((gsize
)data
->rmethod
& 1) {
1745 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1746 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1748 rmethod
= data
->rmethod
;
1750 if (rmethod
->needs_thread_attach
)
1751 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1753 context
= get_context ();
1755 method
= rmethod
->method
;
1756 sig
= mono_method_signature_internal (method
);
1758 // FIXME: Optimize this
1760 //printf ("%s\n", mono_method_full_name (method, 1));
1762 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1764 args
[0].data
.p
= data
->this_arg
;
1767 if (data
->many_args
)
1768 params
= data
->many_args
;
1770 params
= data
->args
;
1771 for (i
= 0; i
< sig
->param_count
; ++i
) {
1772 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1773 if (sig
->params
[i
]->byref
) {
1774 args
[a_index
].data
.p
= params
[i
];
1777 type
= rmethod
->param_types
[i
];
1778 switch (type
->type
) {
1779 case MONO_TYPE_VALUETYPE
:
1780 args
[a_index
].data
.p
= params
[i
];
1782 case MONO_TYPE_GENERICINST
:
1783 if (MONO_TYPE_IS_REFERENCE (type
))
1784 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1786 args
[a_index
].data
.vt
= params
[i
];
1789 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1794 memset (&result
, 0, sizeof (result
));
1795 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1797 type
= rmethod
->rtype
;
1798 switch (type
->type
) {
1799 case MONO_TYPE_GENERICINST
:
1800 if (!MONO_TYPE_IS_REFERENCE (type
))
1801 frame
.retval
->data
.vt
= data
->res
;
1803 case MONO_TYPE_VALUETYPE
:
1804 frame
.retval
->data
.vt
= data
->res
;
1811 interp_exec_method (&frame
, context
, error
);
1813 g_assert (!context
->has_resume_state
);
1815 if (rmethod
->needs_thread_attach
)
1816 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
1818 if (mono_llvm_only
) {
1819 if (context
->has_resume_state
)
1820 mono_llvm_reraise_exception ((MonoException
*)mono_gchandle_get_target_internal (context
->exc_gchandle
));
1822 g_assert (!context
->has_resume_state
);
1825 type
= rmethod
->rtype
;
1826 switch (type
->type
) {
1827 case MONO_TYPE_VOID
:
1829 case MONO_TYPE_OBJECT
:
1830 /* No need for a write barrier */
1831 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1833 case MONO_TYPE_GENERICINST
:
1834 if (MONO_TYPE_IS_REFERENCE (type
)) {
1835 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1837 /* Already set before the call */
1840 case MONO_TYPE_VALUETYPE
:
1841 /* Already set before the call */
1844 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1850 do_icall (MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
1852 #ifdef ENABLE_NETCORE
1853 if (save_last_error
)
1854 mono_marshal_clear_last_error ();
1858 case MINT_ICALL_V_V
: {
1859 typedef void (*T
)(void);
1864 case MINT_ICALL_V_P
: {
1865 typedef gpointer (*T
)(void);
1868 sp
[-1].data
.p
= func ();
1871 case MINT_ICALL_P_V
: {
1872 typedef void (*T
)(gpointer
);
1874 func (sp
[-1].data
.p
);
1878 case MINT_ICALL_P_P
: {
1879 typedef gpointer (*T
)(gpointer
);
1881 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1884 case MINT_ICALL_PP_V
: {
1885 typedef void (*T
)(gpointer
,gpointer
);
1888 func (sp
[0].data
.p
, sp
[1].data
.p
);
1891 case MINT_ICALL_PP_P
: {
1892 typedef gpointer (*T
)(gpointer
,gpointer
);
1895 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1898 case MINT_ICALL_PPP_V
: {
1899 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
1902 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1905 case MINT_ICALL_PPP_P
: {
1906 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
1909 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
1912 case MINT_ICALL_PPPP_V
: {
1913 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1916 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1919 case MINT_ICALL_PPPP_P
: {
1920 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1923 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1926 case MINT_ICALL_PPPPP_V
: {
1927 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1930 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
1933 case MINT_ICALL_PPPPP_P
: {
1934 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1937 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
);
1940 case MINT_ICALL_PPPPPP_V
: {
1941 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1944 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
);
1947 case MINT_ICALL_PPPPPP_P
: {
1948 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1951 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
);
1955 g_assert_not_reached ();
1958 if (save_last_error
)
1959 mono_marshal_set_last_error ();
1961 /* convert the native representation to the stackval representation */
1963 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
1968 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1970 #pragma optimize ("", off)
1972 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
1973 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
1976 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
1978 sp
= do_icall (sig
, op
, sp
, ptr
, save_last_error
);
1980 interp_pop_lmf (&ext
);
1982 goto exit_icall
; // prevent unused label warning in some configurations
1987 #pragma optimize ("", on)
1992 gpointer jit_wrapper
;
1994 MonoFtnDesc
*ftndesc
;
1998 jit_call_cb (gpointer arg
)
2000 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2001 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2002 int pindex
= cb_data
->pindex
;
2003 gpointer
*args
= cb_data
->args
;
2004 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2008 typedef void (*T
)(gpointer
);
2009 T func
= (T
)jit_wrapper
;
2015 typedef void (*T
)(gpointer
, gpointer
);
2016 T func
= (T
)jit_wrapper
;
2018 func (args
[0], &ftndesc
);
2022 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2023 T func
= (T
)jit_wrapper
;
2025 func (args
[0], args
[1], &ftndesc
);
2029 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2030 T func
= (T
)jit_wrapper
;
2032 func (args
[0], args
[1], args
[2], &ftndesc
);
2036 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2037 T func
= (T
)jit_wrapper
;
2039 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2043 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2044 T func
= (T
)jit_wrapper
;
2046 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2050 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2051 T func
= (T
)jit_wrapper
;
2053 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2057 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2058 T func
= (T
)jit_wrapper
;
2060 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2064 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2065 T func
= (T
)jit_wrapper
;
2067 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2071 g_assert_not_reached ();
2076 static MONO_NEVER_INLINE stackval
*
2077 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2079 MonoMethodSignature
*sig
;
2080 MonoFtnDesc ftndesc
;
2081 guint8 res_buf
[256];
2085 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2088 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2089 * by ref and return a return value using an explicit return value argument.
2091 if (!rmethod
->jit_wrapper
) {
2092 MonoMethod
*method
= rmethod
->method
;
2094 sig
= mono_method_signature_internal (method
);
2097 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2098 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2100 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2101 mono_error_assert_ok (error
);
2103 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2104 return_val_if_nok (error
, NULL
);
2107 rmethod
->jit_addr
= addr
;
2108 rmethod
->jit_sig
= sig
;
2109 mono_memory_barrier ();
2110 rmethod
->jit_wrapper
= jit_wrapper
;
2113 sig
= rmethod
->jit_sig
;
2116 sp
-= sig
->param_count
;
2120 ftndesc
.addr
= rmethod
->jit_addr
;
2123 // FIXME: Optimize this
2127 int stack_index
= 0;
2128 if (rmethod
->hasthis
) {
2129 args
[pindex
++] = sp
[0].data
.p
;
2132 type
= rmethod
->rtype
;
2133 if (type
->type
!= MONO_TYPE_VOID
) {
2134 if (MONO_TYPE_ISSTRUCT (type
))
2135 args
[pindex
++] = vt_sp
;
2137 args
[pindex
++] = res_buf
;
2139 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2140 MonoType
*t
= rmethod
->param_types
[i
];
2141 stackval
*sval
= &sp
[stack_index
+ i
];
2142 if (sig
->params
[i
]->byref
) {
2143 args
[pindex
++] = sval
->data
.p
;
2144 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2145 args
[pindex
++] = sval
->data
.p
;
2146 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2147 args
[pindex
++] = &sval
->data
.p
;
2156 case MONO_TYPE_VALUETYPE
:
2157 args
[pindex
++] = &sval
->data
.i
;
2160 case MONO_TYPE_FNPTR
:
2163 case MONO_TYPE_OBJECT
:
2164 args
[pindex
++] = &sval
->data
.p
;
2168 args
[pindex
++] = &sval
->data
.l
;
2171 args
[pindex
++] = &sval
->data
.f_r4
;
2174 args
[pindex
++] = &sval
->data
.f
;
2177 printf ("%s\n", mono_type_full_name (t
));
2178 g_assert_not_reached ();
2183 interp_push_lmf (&ext
, frame
);
2185 JitCallCbData cb_data
;
2186 memset (&cb_data
, 0, sizeof (cb_data
));
2187 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2188 cb_data
.pindex
= pindex
;
2189 cb_data
.args
= args
;
2190 cb_data
.ftndesc
= &ftndesc
;
2192 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2193 /* Catch the exception thrown by the native code using a try-catch */
2194 gboolean thrown
= FALSE
;
2195 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2196 interp_pop_lmf (&ext
);
2198 MonoObject
*obj
= mono_llvm_load_exception ();
2200 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2204 jit_call_cb (&cb_data
);
2205 interp_pop_lmf (&ext
);
2208 MonoType
*rtype
= rmethod
->rtype
;
2209 switch (rtype
->type
) {
2210 case MONO_TYPE_VOID
:
2211 case MONO_TYPE_OBJECT
:
2212 case MONO_TYPE_STRING
:
2213 case MONO_TYPE_CLASS
:
2214 case MONO_TYPE_ARRAY
:
2215 case MONO_TYPE_SZARRAY
:
2219 sp
->data
.p
= *(gpointer
*)res_buf
;
2222 sp
->data
.i
= *(gint8
*)res_buf
;
2225 sp
->data
.i
= *(guint8
*)res_buf
;
2228 sp
->data
.i
= *(gint16
*)res_buf
;
2231 sp
->data
.i
= *(guint16
*)res_buf
;
2234 sp
->data
.i
= *(gint32
*)res_buf
;
2237 sp
->data
.i
= *(guint32
*)res_buf
;
2240 sp
->data
.l
= *(gint64
*)res_buf
;
2243 sp
->data
.l
= *(guint64
*)res_buf
;
2246 sp
->data
.f_r4
= *(float*)res_buf
;
2249 sp
->data
.f
= *(double*)res_buf
;
2251 case MONO_TYPE_TYPEDBYREF
:
2252 case MONO_TYPE_VALUETYPE
:
2253 /* The result was written to vt_sp */
2256 case MONO_TYPE_GENERICINST
:
2257 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2258 sp
->data
.p
= *(gpointer
*)res_buf
;
2260 /* The result was written to vt_sp */
2265 g_print ("%s\n", mono_type_full_name (rtype
));
2266 g_assert_not_reached ();
2273 static MONO_NEVER_INLINE
void
2274 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2277 interp_push_lmf (&ext
, frame
);
2279 interp_pop_lmf (&ext
);
2282 static MONO_NEVER_INLINE MonoException
*
2283 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2286 /* Don't push lmf if we have no interp data */
2287 gboolean push_lmf
= frame
->parent
!= NULL
;
2290 /* Use the parent frame as the current frame is not complete yet */
2292 interp_push_lmf (&ext
, frame
->parent
);
2294 mono_interp_transform_method (frame
->imethod
, context
, error
);
2297 interp_pop_lmf (&ext
);
2299 return mono_error_convert_to_exception (error
);
2302 static MONO_NEVER_INLINE guchar
*
2303 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, guchar
*vt_sp_start
)
2305 stackval
*first_arg
= sp
- csig
->param_count
;
2306 guchar
*vt_sp
= vt_sp_start
;
2309 * We need to have the varargs linearly on the stack so the ArgIterator
2310 * can iterate over them. We pass the signature first and then copy them
2311 * one by one on the vtstack. At the end we pass the original vt_stack
2312 * so the callee (MINT_ARGLIST) can find the varargs space.
2314 *(gpointer
*)vt_sp
= csig
;
2315 vt_sp
+= sizeof (gpointer
);
2317 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2318 int align
, arg_size
;
2319 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2320 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, align
);
2322 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt_sp
, FALSE
);
2326 vt_sp
+= sizeof (gpointer
);
2327 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, MINT_VT_ALIGNMENT
);
2329 ((gpointer
*)vt_sp
) [-1] = vt_sp_start
;
2335 * These functions are the entry points into the interpreter from compiled code.
2336 * They are called by the interp_in wrappers. They have the following signature:
2337 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2338 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2339 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2340 * more wrappers then these functions.
2341 * this/static * ret/void * 16 arguments -> 64 functions.
2344 #define MAX_INTERP_ENTRY_ARGS 8
2346 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2347 InterpEntryData data; \
2348 (data).rmethod = (_method); \
2349 (data).res = (_res); \
2350 (data).this_arg = (_this_arg); \
2351 (data).many_args = NULL;
2353 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2354 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2355 interp_entry (&data); \
2357 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2358 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2359 (data).args [0] = arg1; \
2360 interp_entry (&data); \
2362 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2363 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2364 (data).args [0] = arg1; \
2365 (data).args [1] = arg2; \
2366 interp_entry (&data); \
2368 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2369 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2370 (data).args [0] = arg1; \
2371 (data).args [1] = arg2; \
2372 (data).args [2] = arg3; \
2373 interp_entry (&data); \
2375 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2376 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2377 (data).args [0] = arg1; \
2378 (data).args [1] = arg2; \
2379 (data).args [2] = arg3; \
2380 (data).args [3] = arg4; \
2381 interp_entry (&data); \
2383 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2384 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2385 (data).args [0] = arg1; \
2386 (data).args [1] = arg2; \
2387 (data).args [2] = arg3; \
2388 (data).args [3] = arg4; \
2389 (data).args [4] = arg5; \
2390 interp_entry (&data); \
2392 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2393 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2394 (data).args [0] = arg1; \
2395 (data).args [1] = arg2; \
2396 (data).args [2] = arg3; \
2397 (data).args [3] = arg4; \
2398 (data).args [4] = arg5; \
2399 (data).args [5] = arg6; \
2400 interp_entry (&data); \
2402 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2403 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2404 (data).args [0] = arg1; \
2405 (data).args [1] = arg2; \
2406 (data).args [2] = arg3; \
2407 (data).args [3] = arg4; \
2408 (data).args [4] = arg5; \
2409 (data).args [5] = arg6; \
2410 (data).args [6] = arg7; \
2411 interp_entry (&data); \
2413 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2414 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2415 (data).args [0] = arg1; \
2416 (data).args [1] = arg2; \
2417 (data).args [2] = arg3; \
2418 (data).args [3] = arg4; \
2419 (data).args [4] = arg5; \
2420 (data).args [5] = arg6; \
2421 (data).args [6] = arg7; \
2422 (data).args [7] = arg8; \
2423 interp_entry (&data); \
2426 #define ARGLIST0 InterpMethod *rmethod
2427 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2428 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2429 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2430 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2431 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2432 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2433 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2434 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2436 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2437 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2438 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2439 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2440 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2441 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2442 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2443 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2444 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2445 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2446 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2447 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2448 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2449 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2450 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2451 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2452 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2453 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2454 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2455 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2456 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2457 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2458 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2459 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2460 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2461 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2462 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2463 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2464 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2465 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2466 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2467 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2468 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2469 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2470 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2471 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2473 #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
2475 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2476 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2477 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2478 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2480 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2482 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2484 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2485 data
.many_args
= args
;
2486 interp_entry (&data
);
2489 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2491 // inline so we can alloc on stack
2492 #define alloc_storage_for_stackval(s, t, p) do { \
2493 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2494 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2495 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2497 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2499 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2504 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2507 ThreadContext
*context
;
2511 MonoMethodSignature
*sig
;
2512 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2513 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2514 gpointer orig_domain
= NULL
, attach_cookie
;
2517 if (rmethod
->needs_thread_attach
)
2518 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2520 context
= get_context ();
2522 method
= rmethod
->method
;
2523 sig
= mono_method_signature_internal (method
);
2525 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2527 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2529 /* Allocate storage for value types */
2530 for (i
= 0; i
< sig
->param_count
; i
++) {
2531 MonoType
*type
= sig
->params
[i
];
2532 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2535 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2536 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2538 /* Copy the args saved in the trampoline to the frame stack */
2539 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2542 interp_exec_method (&frame
, context
, error
);
2544 g_assert (!context
->has_resume_state
);
2546 if (rmethod
->needs_thread_attach
)
2547 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2549 /* Write back the return value */
2550 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2556 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2558 g_assert_not_reached ();
2561 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2563 static InterpMethod
*
2564 lookup_method_pointer (gpointer addr
)
2566 MonoDomain
*domain
= mono_domain_get ();
2567 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2568 InterpMethod
*res
= NULL
;
2570 mono_domain_lock (domain
);
2571 if (info
->interp_method_pointer_hash
)
2572 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2573 mono_domain_unlock (domain
);
2578 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2580 interp_no_native_to_managed (void)
2582 g_error ("interpreter: native-to-managed transition not available on this platform");
2587 no_llvmonly_interp_method_pointer (void)
2589 g_assert_not_reached ();
2593 * interp_create_method_pointer_llvmonly:
2595 * Return an ftndesc for entering the interpreter and executing METHOD.
2598 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2600 MonoDomain
*domain
= mono_domain_get ();
2601 gpointer addr
, entry_func
, entry_wrapper
;
2602 MonoMethodSignature
*sig
;
2603 MonoMethod
*wrapper
;
2604 MonoJitDomainInfo
*info
;
2605 InterpMethod
*imethod
;
2607 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2608 return_val_if_nok (error
, NULL
);
2611 if (imethod
->llvmonly_unbox_entry
)
2612 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2614 if (imethod
->jit_entry
)
2615 return (MonoFtnDesc
*)imethod
->jit_entry
;
2618 sig
= mono_method_signature_internal (method
);
2621 * The entry functions need access to the method to call, so we have
2622 * to use a ftndesc. The caller uses a normal signature, while the
2623 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2624 * a gsharedvt_in_sig wrapper.
2626 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2628 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2629 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2630 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2631 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2633 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2634 g_assert_not_reached ();
2635 //entry_func = (gpointer)interp_entry_general;
2636 } else if (sig
->hasthis
) {
2637 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2638 entry_func
= entry_funcs_instance
[sig
->param_count
];
2640 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2642 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2643 entry_func
= entry_funcs_static
[sig
->param_count
];
2645 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2647 g_assert (entry_func
);
2649 /* Encode unbox in the lower bit of imethod */
2650 gpointer entry_arg
= imethod
;
2652 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2653 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2655 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2657 info
= domain_jit_info (domain
);
2658 mono_domain_lock (domain
);
2659 if (!info
->interp_method_pointer_hash
)
2660 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2661 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2662 mono_domain_unlock (domain
);
2664 mono_memory_barrier ();
2666 imethod
->llvmonly_unbox_entry
= addr
;
2668 imethod
->jit_entry
= addr
;
2670 return (MonoFtnDesc
*)addr
;
2674 * interp_create_method_pointer:
2676 * Return a function pointer which can be used to call METHOD using the
2677 * interpreter. Return NULL for methods which are not supported.
2680 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2682 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2684 return (gpointer
)no_llvmonly_interp_method_pointer
;
2685 return (gpointer
)interp_no_native_to_managed
;
2687 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2688 MonoDomain
*domain
= mono_domain_get ();
2689 MonoJitDomainInfo
*info
;
2690 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2693 return (gpointer
)no_llvmonly_interp_method_pointer
;
2695 if (imethod
->jit_entry
)
2696 return imethod
->jit_entry
;
2698 if (compile
&& !imethod
->transformed
) {
2699 /* Return any errors from method compilation */
2700 mono_interp_transform_method (imethod
, get_context (), error
);
2701 return_val_if_nok (error
, NULL
);
2704 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2707 /* The caller should call interp_create_method_pointer_llvmonly */
2708 g_assert_not_reached ();
2710 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2713 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2715 * Interp in wrappers get the argument in the rgctx register. If
2716 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2717 * on that arch the rgctx register is not scratch, so we use a
2718 * separate temp register. We should update the wrappers for this
2719 * if we really care about those architectures (arm).
2721 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2723 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2725 if (entry_wrapper
) {
2726 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2727 entry_func
= (gpointer
)interp_entry_general
;
2728 } else if (sig
->hasthis
) {
2729 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2730 entry_func
= entry_funcs_instance
[sig
->param_count
];
2732 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2734 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2735 entry_func
= entry_funcs_static
[sig
->param_count
];
2737 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2740 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2741 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2742 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2743 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2745 mono_error_cleanup (error
);
2746 error_init_reuse (error
);
2747 if (!mono_native_to_interp_trampoline
) {
2748 if (mono_aot_only
) {
2749 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2751 MonoTrampInfo
*info
;
2752 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2753 mono_tramp_info_register (info
, NULL
);
2756 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2757 /* We need the lmf wrapper only when being called from mixed mode */
2759 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2761 static gpointer cached_func
= NULL
;
2763 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
);
2764 mono_memory_barrier ();
2766 entry_func
= cached_func
;
2771 g_assert (entry_func
);
2772 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2773 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2774 ftndesc
->addr
= entry_func
;
2775 ftndesc
->arg
= imethod
;
2776 mono_error_assert_ok (error
);
2779 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2780 * rgctx register using a trampoline.
2783 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2785 info
= domain_jit_info (domain
);
2786 mono_domain_lock (domain
);
2787 if (!info
->interp_method_pointer_hash
)
2788 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2789 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2790 mono_domain_unlock (domain
);
2792 mono_memory_barrier ();
2793 imethod
->jit_entry
= addr
;
2800 static long opcode_counts
[MINT_LASTOP
];
2802 #define COUNT_OP(op) opcode_counts[op]++
2804 #define COUNT_OP(op)
2808 #define DUMP_INSTR() \
2809 if (tracing > 1) { \
2811 if (sp > frame->stack) { \
2812 ins = dump_stack (frame->stack, sp); \
2814 ins = g_strdup (""); \
2818 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2819 char *disasm = mono_interp_dis_mintop (frame->imethod->code, ip); \
2820 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2826 #define DUMP_INSTR()
2829 #define INIT_VTABLE(vtable) do { \
2830 if (G_UNLIKELY (!(vtable)->initialized)) { \
2831 mono_runtime_class_init_full ((vtable), error); \
2832 if (!is_ok (error)) \
2833 goto throw_error_label; \
2837 static MONO_NEVER_INLINE MonoObject
*
2838 mono_interp_new (MonoDomain
* domain
, MonoClass
* klass
)
2841 MonoObject
* const object
= mono_object_new_checked (domain
, klass
, error
);
2842 mono_error_cleanup (error
); // FIXME: do not swallow the error
2847 #ifndef DISABLE_REMOTING
2848 MONO_NEVER_INLINE
// To reduce stack.
2851 mono_interp_load_remote_field (
2852 InterpMethod
* imethod
,
2857 g_assert (o
); // Caller checks and throws exception properly.
2860 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
2862 #ifndef DISABLE_REMOTING
2864 if (mono_object_is_transparent_proxy (o
)) {
2865 MonoClass
* const klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
2867 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
2868 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2871 addr
= (char*)o
+ field
->offset
;
2872 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
2876 #ifndef DISABLE_REMOTING
2877 MONO_NEVER_INLINE
// To reduce stack.
2879 guchar
* // Return new vt_sp instead of take-address.
2880 mono_interp_load_remote_field_vt (
2881 InterpMethod
* imethod
,
2887 g_assert (o
); // Caller checks and throws exception properly.
2890 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
2891 MonoClass
* klass
= mono_class_from_mono_type_internal (field
->type
);
2892 int const i32
= mono_class_value_size (klass
, NULL
);
2894 #ifndef DISABLE_REMOTING
2896 if (mono_object_is_transparent_proxy (o
)) {
2897 klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
2899 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
2900 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2903 addr
= (char*)o
+ field
->offset
;
2904 sp
[-1].data
.p
= vt_sp
;
2905 memcpy (vt_sp
, addr
, i32
);
2906 return vt_sp
+ ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
2909 static MONO_NEVER_INLINE gboolean
2910 mono_interp_isinst (MonoObject
* object
, MonoClass
* klass
)
2913 const gboolean isinst
= mono_object_isinst_checked (object
, klass
, error
) != NULL
;
2914 mono_error_cleanup (error
); // FIXME: do not swallow the error
2918 // This function is outlined to help save stack in its caller, on the premise
2919 // that it is relatively rarely called. This also lets it use alloca.
2920 static MONO_NEVER_INLINE
void
2921 mono_interp_calli_nat_dynamic_pinvoke (
2922 // Parameters are sorted by name.
2923 InterpFrame
* child_frame
,
2925 ThreadContext
* context
,
2926 MonoMethodSignature
* csignature
,
2929 // Recompute to limit parameters, which can also contribute to caller stack.
2930 InterpMethod
* const imethod
= child_frame
->parent
->imethod
;
2932 g_assert (imethod
->method
->dynamic
&& csignature
->pinvoke
);
2934 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
2935 MonoMarshalSpec
** mspecs
= g_newa (MonoMarshalSpec
*, csignature
->param_count
+ 1);
2936 memset (mspecs
, 0, sizeof (MonoMarshalSpec
*) * (csignature
->param_count
+ 1));
2938 MonoMethodPInvoke iinfo
;
2939 memset (&iinfo
, 0, sizeof (iinfo
));
2941 MonoMethod
* m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &iinfo
, mspecs
, code
);
2943 for (int i
= csignature
->param_count
; i
>= 0; i
--)
2945 mono_metadata_free_marshal_spec (mspecs
[i
]);
2949 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
2950 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2953 interp_exec_method (child_frame
, context
, error
);
2956 // Leave is split into pieces in order to consume less stack,
2957 // but not have to change how exception handling macros access labels and locals.
2958 static MONO_NEVER_INLINE MonoException
*
2959 mono_interp_leave (InterpFrame
* child_frame
)
2963 * We need for mono_thread_get_undeniable_exception to be able to unwind
2964 * to check the abort threshold. For this to work we use child_frame as a
2965 * dummy frame that is stored in the lmf and serves as the transition frame
2967 do_icall_wrapper (child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
2969 return (MonoException
*)tmp_sp
.data
.p
;
2972 static MONO_NEVER_INLINE
void
2973 mono_interp_newobj_vt (
2974 // Parameters are sorted by name and parameter list is minimized
2975 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
2976 // use no stack in caller).
2977 InterpFrame
* child_frame
,
2978 ThreadContext
* context
,
2981 stackval
* const sp
= child_frame
->stack_args
;
2983 stackval valuetype_this
;
2985 memset (&valuetype_this
, 0, sizeof (stackval
));
2986 sp
->data
.p
= &valuetype_this
;
2988 // FIXME It is unfortunate to outline a recursive case as it
2989 // increases its stack usage. We do this however as it conserves
2990 // stack for all the other recursive cases.
2991 interp_exec_method (child_frame
, context
, error
);
2993 CHECK_RESUME_STATE (context
);
2995 *sp
= valuetype_this
;
3000 static MONO_NEVER_INLINE MonoException
*
3001 mono_interp_newobj (
3002 // Parameters are sorted by name and parameter list is minimized
3003 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3004 // use no stack in caller).
3005 InterpFrame
* child_frame
,
3006 ThreadContext
* context
,
3010 InterpFrame
* const frame
= child_frame
->parent
;
3011 InterpMethod
* const imethod
= frame
->imethod
;
3012 stackval
* const sp
= child_frame
->stack_args
;
3014 MonoObject
* o
= NULL
; // See the comment about GC safety.
3015 stackval valuetype_this
;
3018 MonoClass
* const newobj_class
= child_frame
->imethod
->method
->klass
;
3019 /*if (profiling_classes) {
3020 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3022 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3026 * First arg is the object.
3028 if (m_class_is_valuetype (newobj_class
)) {
3029 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
3030 memset (&valuetype_this
, 0, sizeof (stackval
));
3031 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3033 valuetype_this
.data
.p
= vt_sp
;
3035 sp
->data
.p
= &valuetype_this
;
3038 if (newobj_class
!= mono_defaults
.string_class
) {
3039 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
3040 if (!is_ok (error
) || !mono_runtime_class_init_full (vtable
, error
)) {
3041 MonoException
* const exc
= mono_error_convert_to_exception (error
);
3046 OBJREF (o
) = mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
3047 mono_error_cleanup (error
); // FIXME: do not swallow the error
3048 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION
;
3050 #ifndef DISABLE_REMOTING
3051 if (mono_object_is_transparent_proxy (o
)) {
3052 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
->imethod
->method
, error
);
3053 mono_error_assert_ok (error
);
3054 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
3055 mono_error_assert_ok (error
);
3060 child_frame
->retval
= &retval
;
3064 interp_exec_method (child_frame
, context
, error
);
3066 CHECK_RESUME_STATE (context
);
3069 * a constructor returns void, but we need to return the object we created
3071 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
3072 *sp
= valuetype_this
;
3073 } else if (newobj_class
== mono_defaults
.string_class
) {
3082 static MONO_NEVER_INLINE
void
3083 mono_interp_enum_hasflag (stackval
* sp
, MonoClass
* klass
)
3085 guint64 a_val
= 0, b_val
= 0;
3087 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &b_val
, FALSE
);
3088 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &a_val
, FALSE
);
3089 sp
->data
.i
= (a_val
& b_val
) == b_val
;
3092 static MONO_NEVER_INLINE
int
3093 mono_interp_box_nullable (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3095 InterpMethod
* const imethod
= frame
->imethod
;
3096 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[ip
[1]];
3098 int const size
= mono_class_value_size (c
, NULL
);
3100 guint16 offset
= ip
[2];
3101 gboolean
const pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
3102 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
3104 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
3105 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3107 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3110 static MONO_NEVER_INLINE
int
3111 mono_interp_box_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3113 InterpMethod
* const imethod
= frame
->imethod
;
3115 MonoObject
* o
; // See the comment about GC safety.
3116 MonoVTable
* const vtable
= (MonoVTable
*)imethod
->data_items
[ip
[1]];
3117 MonoClass
* const c
= vtable
->klass
;
3119 int const size
= mono_class_value_size (c
, NULL
);
3121 guint16 offset
= ip
[2];
3122 gboolean
const pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
3123 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
3125 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3126 mono_value_copy_internal (mono_object_get_data (o
), sp
[-1 - offset
].data
.p
, c
);
3128 sp
[-1 - offset
].data
.p
= o
;
3129 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3132 static MONO_NEVER_INLINE
void
3133 mono_interp_box (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3135 MonoObject
*o
; // See the comment about GC safety.
3136 MonoVTable
* const vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
3138 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3140 guint16
const offset
= ip
[2];
3142 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (o
), FALSE
);
3144 sp
[-1 - offset
].data
.p
= o
;
3147 static MONO_NEVER_INLINE
int
3148 mono_interp_store_remote_field_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3150 InterpMethod
* const imethod
= frame
->imethod
;
3151 MonoClassField
*field
;
3153 MonoObject
* const o
= sp
[-2].data
.o
;
3155 field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3156 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
3157 int const i32
= mono_class_value_size (klass
, NULL
);
3159 #ifndef DISABLE_REMOTING
3160 if (mono_object_is_transparent_proxy (o
)) {
3161 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3162 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
3163 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3166 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3168 return ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3171 static MONO_ALWAYS_INLINE stackval
*
3172 mono_interp_call (InterpFrame
*frame
, ThreadContext
*context
, InterpFrame
*child_frame
, const guint16
*ip
, stackval
*sp
, guchar
*vt_sp
, gboolean is_virtual
)
3176 child_frame
->imethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3179 child_frame
->retval
= sp
;
3181 /* decrement by the actual number of args */
3182 sp
-= child_frame
->imethod
->param_count
+ child_frame
->imethod
->hasthis
;
3185 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3187 child_frame
->imethod
= get_virtual_method (child_frame
->imethod
, this_arg
->vtable
);
3188 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (child_frame
->imethod
->method
->klass
)) {
3190 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3191 sp
[0].data
.p
= unboxed
;
3198 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3199 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3200 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3201 * to return error information.
3203 * Currently this method uses 0x88 of stack space on 64bit gcc. Make sure to keep it under control.
3206 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
)
3208 InterpFrame child_frame
;
3209 GSList
*finally_ips
= NULL
;
3210 const guint16
*ip
= NULL
;
3213 gint tracing
= global_tracing
;
3214 unsigned char *vtalloc
;
3216 unsigned char *vt_sp
;
3217 unsigned char *locals
= NULL
;
3218 #if USE_COMPUTED_GOTO
3219 static void * const in_labels
[] = {
3220 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3221 #include "mintops.def"
3226 debug_enter (frame
, &tracing
);
3229 if (!frame
->imethod
->transformed
) {
3231 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
3232 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
3237 MonoException
*ex
= do_transform_method (frame
, context
);
3239 THROW_EX (ex
, NULL
);
3240 EXCEPTION_CHECKPOINT
;
3244 frame
->stack
= (stackval
*)g_alloca (frame
->imethod
->alloca_size
);
3245 ip
= frame
->imethod
->code
;
3247 ip
= clause_args
->start_with_ip
;
3248 if (clause_args
->base_frame
) {
3249 frame
->stack
= (stackval
*)g_alloca (frame
->imethod
->alloca_size
);
3250 memcpy (frame
->stack
, clause_args
->base_frame
->stack
, frame
->imethod
->alloca_size
);
3254 vt_sp
= (unsigned char *) sp
+ frame
->imethod
->stack_size
;
3258 locals
= (unsigned char *) vt_sp
+ frame
->imethod
->vt_stack_size
;
3259 child_frame
.parent
= frame
;
3261 if (clause_args
&& clause_args
->filter_exception
) {
3262 sp
->data
.p
= clause_args
->filter_exception
;
3266 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3269 * using while (ip < end) may result in a 15% performance drop,
3270 * but it may be useful for debug
3274 /* g_assert (sp >= frame->stack); */
3275 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3277 MINT_IN_SWITCH (*ip
) {
3278 MINT_IN_CASE(MINT_INITLOCALS
)
3279 memset (locals
, 0, frame
->imethod
->locals_size
);
3282 MINT_IN_CASE(MINT_NOP
)
3283 MINT_IN_CASE(MINT_NIY
)
3284 g_assert_not_reached ();
3286 MINT_IN_CASE(MINT_BREAK
)
3288 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3290 MINT_IN_CASE(MINT_BREAKPOINT
)
3294 MINT_IN_CASE(MINT_LDNULL
)
3299 MINT_IN_CASE(MINT_ARGLIST
)
3301 *(gpointer
*)sp
->data
.p
= ((gpointer
*)frame
->retval
->data
.p
) [-1];
3302 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3306 MINT_IN_CASE(MINT_VTRESULT
) {
3307 int ret_size
= ip
[1];
3308 unsigned char *ret_vt_sp
= vt_sp
;
3309 vt_sp
-= READ32(ip
+ 2);
3311 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3312 sp
[-1].data
.p
= vt_sp
;
3313 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3318 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3319 MINT_IN_CASE(MINT_LDC_I4_M1
)
3322 MINT_IN_CASE(MINT_LDC_I4_0
)
3325 MINT_IN_CASE(MINT_LDC_I4_1
)
3328 MINT_IN_CASE(MINT_LDC_I4_2
)
3331 MINT_IN_CASE(MINT_LDC_I4_3
)
3334 MINT_IN_CASE(MINT_LDC_I4_4
)
3337 MINT_IN_CASE(MINT_LDC_I4_5
)
3340 MINT_IN_CASE(MINT_LDC_I4_6
)
3343 MINT_IN_CASE(MINT_LDC_I4_7
)
3346 MINT_IN_CASE(MINT_LDC_I4_8
)
3349 MINT_IN_CASE(MINT_LDC_I4_S
)
3350 sp
->data
.i
= (short)ip
[1];
3354 MINT_IN_CASE(MINT_LDC_I4
)
3356 sp
->data
.i
= READ32 (ip
);
3360 MINT_IN_CASE(MINT_LDC_I8
)
3362 sp
->data
.l
= READ64 (ip
);
3366 MINT_IN_CASE(MINT_LDC_I8_S
)
3367 sp
->data
.l
= (short)ip
[1];
3371 MINT_IN_CASE(MINT_LDC_R4
) {
3375 sp
->data
.f_r4
= * (float *)&val
;
3380 MINT_IN_CASE(MINT_LDC_R8
)
3381 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3385 MINT_IN_CASE(MINT_DUP
)
3390 MINT_IN_CASE(MINT_DUP_VT
) {
3391 int const i32
= READ32 (ip
+ 1);
3393 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3394 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3399 MINT_IN_CASE(MINT_POP
) {
3400 guint16 u16
= (ip
[1]) + 1;
3402 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
3407 MINT_IN_CASE(MINT_JMP
) {
3408 g_assert (sp
== frame
->stack
);
3409 InterpMethod
*new_method
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3411 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3412 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
3414 if (!new_method
->transformed
) {
3415 MONO_API_ERROR_INIT (error
);
3418 mono_interp_transform_method (new_method
, context
, error
);
3419 MonoException
*ex
= mono_error_convert_to_exception (error
);
3424 const gboolean realloc_frame
= new_method
->alloca_size
> frame
->imethod
->alloca_size
;
3425 frame
->imethod
= new_method
;
3427 * We allocate the stack frame from scratch and store the arguments in the
3428 * locals again since it's possible for the caller stack frame to be smaller
3429 * than the callee stack frame (at the interp level)
3431 if (realloc_frame
) {
3432 frame
->stack
= (stackval
*)g_alloca (frame
->imethod
->alloca_size
);
3433 memset (frame
->stack
, 0, frame
->imethod
->alloca_size
);
3436 vt_sp
= (unsigned char *) sp
+ frame
->imethod
->stack_size
;
3440 locals
= vt_sp
+ frame
->imethod
->vt_stack_size
;
3441 ip
= frame
->imethod
->code
;
3444 MINT_IN_CASE(MINT_CALLI
) {
3445 MonoMethodSignature
*csignature
;
3449 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3452 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
3455 child_frame
.retval
= sp
;
3456 /* decrement by the actual number of args */
3457 sp
-= csignature
->param_count
;
3458 if (csignature
->hasthis
)
3461 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3462 child_frame
.imethod
= mono_interp_get_imethod (frame
->imethod
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
3463 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3466 if (csignature
->hasthis
) {
3467 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3469 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3470 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3471 sp
[0].data
.p
= unboxed
;
3475 if (csignature
->ret
->type
!= MONO_TYPE_VOID
)
3479 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3480 gpointer target_ip
= sp
[-1].data
.p
;
3481 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3482 int opcode
= ip
[2];
3483 gboolean save_last_error
= ip
[3];
3488 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3489 EXCEPTION_CHECKPOINT
;
3490 CHECK_RESUME_STATE (context
);
3494 MINT_IN_CASE(MINT_CALLI_NAT
) {
3498 MonoMethodSignature
* csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3502 guchar
* const code
= (guchar
*)sp
->data
.p
;
3503 child_frame
.imethod
= NULL
;
3506 child_frame
.retval
= sp
;
3507 /* decrement by the actual number of args */
3508 sp
-= csignature
->param_count
;
3509 if (csignature
->hasthis
)
3511 child_frame
.stack_args
= sp
;
3513 if (frame
->imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3514 mono_interp_calli_nat_dynamic_pinvoke (&child_frame
, code
, context
, csignature
, error
);
3516 const gboolean save_last_error
= ip
[-3 + 2];
3517 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, context
, save_last_error
);
3520 /* need to handle typedbyref ... */
3521 if (csignature
->ret
->type
!= MONO_TYPE_VOID
)
3525 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3526 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3527 MonoObject
*this_arg
;
3528 InterpMethod
*target_imethod
;
3531 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3535 target_imethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3536 slot
= (gint16
)ip
[2];
3539 child_frame
.retval
= sp
;
3541 /* decrement by the actual number of args */
3542 sp
-= target_imethod
->param_count
+ target_imethod
->hasthis
;
3544 this_arg
= (MonoObject
*)sp
->data
.p
;
3546 child_frame
.imethod
= get_virtual_method_fast (target_imethod
, this_arg
->vtable
, slot
);
3547 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3549 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3550 sp
[0].data
.p
= unboxed
;
3552 const gboolean is_void
= ip
[-3] == MINT_VCALLVIRT_FAST
;
3557 MINT_IN_CASE(MINT_CALL_VARARG
) {
3558 int num_varargs
= 0;
3559 MonoMethodSignature
*csig
;
3563 child_frame
.imethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3564 /* The real signature for vararg calls */
3565 csig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3566 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3567 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
3568 vt_sp
= copy_varargs_vtstack (csig
, sp
, vt_sp
);
3572 child_frame
.retval
= sp
;
3574 /* decrement by the actual number of args */
3575 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
3577 if (csig
->ret
->type
!= MONO_TYPE_VOID
)
3581 MINT_IN_CASE(MINT_CALL
)
3582 sp
= mono_interp_call (frame
, context
, &child_frame
, (ip
+= 2) - 2, sp
, vt_sp
, FALSE
);
3584 child_frame
.stack_args
= sp
;
3585 interp_exec_method (&child_frame
, context
, error
);
3587 /* need to handle typedbyref ... */
3588 *sp
= *child_frame
.retval
;
3591 CHECK_RESUME_STATE (context
);
3594 MINT_IN_CASE(MINT_VCALL
)
3595 sp
= mono_interp_call (frame
, context
, &child_frame
, (ip
+= 2) - 2, sp
, vt_sp
, FALSE
);
3597 child_frame
.stack_args
= sp
;
3598 interp_exec_method (&child_frame
, context
, error
);
3601 MINT_IN_CASE(MINT_CALLVIRT
)
3602 sp
= mono_interp_call (frame
, context
, &child_frame
, (ip
+= 2) - 2, sp
, vt_sp
, TRUE
);
3605 MINT_IN_CASE(MINT_VCALLVIRT
)
3606 sp
= mono_interp_call (frame
, context
, &child_frame
, (ip
+= 2) - 2, sp
, vt_sp
, TRUE
);
3609 MINT_IN_CASE(MINT_JIT_CALL
) {
3610 InterpMethod
*rmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3611 MONO_API_ERROR_INIT (error
);
3613 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3614 if (!is_ok (error
)) {
3615 MonoException
*ex
= mono_error_convert_to_exception (error
);
3620 CHECK_RESUME_STATE (context
);
3622 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3627 MINT_IN_CASE(MINT_CALLRUN
) {
3628 MonoMethod
*target_method
= (MonoMethod
*) frame
->imethod
->data_items
[ip
[1]];
3629 MonoMethodSignature
*sig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3635 sp
-= sig
->param_count
;
3639 MonoException
*ex
= ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3643 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3650 MINT_IN_CASE(MINT_RET
)
3652 *frame
->retval
= *sp
;
3653 if (sp
> frame
->stack
)
3654 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3656 MINT_IN_CASE(MINT_RET_VOID
)
3657 if (sp
> frame
->stack
)
3658 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
3660 MINT_IN_CASE(MINT_RET_VT
) {
3661 int const i32
= READ32 (ip
+ 1);
3663 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3664 if (sp
> frame
->stack
)
3665 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3668 MINT_IN_CASE(MINT_BR_S
)
3669 ip
+= (short) *(ip
+ 1);
3671 MINT_IN_CASE(MINT_BR
)
3672 ip
+= (gint32
) READ32(ip
+ 1);
3674 #define ZEROP_S(datamem, op) \
3676 if (sp->data.datamem op 0) \
3677 ip += (gint16)ip [1]; \
3681 #define ZEROP(datamem, op) \
3683 if (sp->data.datamem op 0) \
3684 ip += (gint32)READ32(ip + 1); \
3688 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3691 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3694 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3697 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3700 MINT_IN_CASE(MINT_BRFALSE_I4
)
3703 MINT_IN_CASE(MINT_BRFALSE_I8
)
3706 MINT_IN_CASE(MINT_BRFALSE_R4
)
3709 MINT_IN_CASE(MINT_BRFALSE_R8
)
3712 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3715 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3718 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
3721 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3724 MINT_IN_CASE(MINT_BRTRUE_I4
)
3727 MINT_IN_CASE(MINT_BRTRUE_I8
)
3730 MINT_IN_CASE(MINT_BRTRUE_R4
)
3733 MINT_IN_CASE(MINT_BRTRUE_R8
)
3736 #define CONDBR_S(cond) \
3739 ip += (gint16)ip [1]; \
3742 #define BRELOP_S(datamem, op) \
3743 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3745 #define CONDBR(cond) \
3748 ip += (gint32)READ32(ip + 1); \
3752 #define BRELOP(datamem, op) \
3753 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3755 MINT_IN_CASE(MINT_BEQ_I4_S
)
3758 MINT_IN_CASE(MINT_BEQ_I8_S
)
3761 MINT_IN_CASE(MINT_BEQ_R4_S
)
3762 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3764 MINT_IN_CASE(MINT_BEQ_R8_S
)
3765 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3767 MINT_IN_CASE(MINT_BEQ_I4
)
3770 MINT_IN_CASE(MINT_BEQ_I8
)
3773 MINT_IN_CASE(MINT_BEQ_R4
)
3774 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3776 MINT_IN_CASE(MINT_BEQ_R8
)
3777 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3779 MINT_IN_CASE(MINT_BGE_I4_S
)
3782 MINT_IN_CASE(MINT_BGE_I8_S
)
3785 MINT_IN_CASE(MINT_BGE_R4_S
)
3786 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3788 MINT_IN_CASE(MINT_BGE_R8_S
)
3789 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3791 MINT_IN_CASE(MINT_BGE_I4
)
3794 MINT_IN_CASE(MINT_BGE_I8
)
3797 MINT_IN_CASE(MINT_BGE_R4
)
3798 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3800 MINT_IN_CASE(MINT_BGE_R8
)
3801 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3803 MINT_IN_CASE(MINT_BGT_I4_S
)
3806 MINT_IN_CASE(MINT_BGT_I8_S
)
3809 MINT_IN_CASE(MINT_BGT_R4_S
)
3810 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3812 MINT_IN_CASE(MINT_BGT_R8_S
)
3813 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3815 MINT_IN_CASE(MINT_BGT_I4
)
3818 MINT_IN_CASE(MINT_BGT_I8
)
3821 MINT_IN_CASE(MINT_BGT_R4
)
3822 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3824 MINT_IN_CASE(MINT_BGT_R8
)
3825 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3827 MINT_IN_CASE(MINT_BLT_I4_S
)
3830 MINT_IN_CASE(MINT_BLT_I8_S
)
3833 MINT_IN_CASE(MINT_BLT_R4_S
)
3834 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3836 MINT_IN_CASE(MINT_BLT_R8_S
)
3837 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3839 MINT_IN_CASE(MINT_BLT_I4
)
3842 MINT_IN_CASE(MINT_BLT_I8
)
3845 MINT_IN_CASE(MINT_BLT_R4
)
3846 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3848 MINT_IN_CASE(MINT_BLT_R8
)
3849 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3851 MINT_IN_CASE(MINT_BLE_I4_S
)
3854 MINT_IN_CASE(MINT_BLE_I8_S
)
3857 MINT_IN_CASE(MINT_BLE_R4_S
)
3858 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3860 MINT_IN_CASE(MINT_BLE_R8_S
)
3861 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3863 MINT_IN_CASE(MINT_BLE_I4
)
3866 MINT_IN_CASE(MINT_BLE_I8
)
3869 MINT_IN_CASE(MINT_BLE_R4
)
3870 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3872 MINT_IN_CASE(MINT_BLE_R8
)
3873 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3875 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3878 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3881 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
3882 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3884 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3885 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3887 MINT_IN_CASE(MINT_BNE_UN_I4
)
3890 MINT_IN_CASE(MINT_BNE_UN_I8
)
3893 MINT_IN_CASE(MINT_BNE_UN_R4
)
3894 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3896 MINT_IN_CASE(MINT_BNE_UN_R8
)
3897 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3900 #define BRELOP_S_CAST(datamem, op, type) \
3902 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3903 ip += (gint16)ip [1]; \
3907 #define BRELOP_CAST(datamem, op, type) \
3909 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3910 ip += (gint32)READ32(ip + 1); \
3914 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3915 BRELOP_S_CAST(i
, >=, guint32
);
3917 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3918 BRELOP_S_CAST(l
, >=, guint64
);
3920 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
3921 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3923 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3924 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3926 MINT_IN_CASE(MINT_BGE_UN_I4
)
3927 BRELOP_CAST(i
, >=, guint32
);
3929 MINT_IN_CASE(MINT_BGE_UN_I8
)
3930 BRELOP_CAST(l
, >=, guint64
);
3932 MINT_IN_CASE(MINT_BGE_UN_R4
)
3933 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3935 MINT_IN_CASE(MINT_BGE_UN_R8
)
3936 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3938 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3939 BRELOP_S_CAST(i
, >, guint32
);
3941 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3942 BRELOP_S_CAST(l
, >, guint64
);
3944 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
3945 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3947 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3948 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3950 MINT_IN_CASE(MINT_BGT_UN_I4
)
3951 BRELOP_CAST(i
, >, guint32
);
3953 MINT_IN_CASE(MINT_BGT_UN_I8
)
3954 BRELOP_CAST(l
, >, guint64
);
3956 MINT_IN_CASE(MINT_BGT_UN_R4
)
3957 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3959 MINT_IN_CASE(MINT_BGT_UN_R8
)
3960 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3962 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3963 BRELOP_S_CAST(i
, <=, guint32
);
3965 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3966 BRELOP_S_CAST(l
, <=, guint64
);
3968 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
3969 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3971 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3972 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3974 MINT_IN_CASE(MINT_BLE_UN_I4
)
3975 BRELOP_CAST(i
, <=, guint32
);
3977 MINT_IN_CASE(MINT_BLE_UN_I8
)
3978 BRELOP_CAST(l
, <=, guint64
);
3980 MINT_IN_CASE(MINT_BLE_UN_R4
)
3981 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3983 MINT_IN_CASE(MINT_BLE_UN_R8
)
3984 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3986 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3987 BRELOP_S_CAST(i
, <, guint32
);
3989 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3990 BRELOP_S_CAST(l
, <, guint64
);
3992 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
3993 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3995 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3996 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3998 MINT_IN_CASE(MINT_BLT_UN_I4
)
3999 BRELOP_CAST(i
, <, guint32
);
4001 MINT_IN_CASE(MINT_BLT_UN_I8
)
4002 BRELOP_CAST(l
, <, guint64
);
4004 MINT_IN_CASE(MINT_BLT_UN_R4
)
4005 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4007 MINT_IN_CASE(MINT_BLT_UN_R8
)
4008 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4010 MINT_IN_CASE(MINT_SWITCH
) {
4012 const unsigned short *st
;
4018 if ((guint32
)sp
->data
.i
< n
) {
4020 ip
+= 2 * (guint32
)sp
->data
.i
;
4021 offset
= READ32 (ip
);
4028 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
4029 NULL_CHECK (sp
[-1].data
.p
);
4031 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
4033 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
4034 NULL_CHECK (sp
[-1].data
.p
);
4036 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
4038 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
4039 NULL_CHECK (sp
[-1].data
.p
);
4041 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
4043 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
4044 NULL_CHECK (sp
[-1].data
.p
);
4046 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
4048 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
4049 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
4050 NULL_CHECK (sp
[-1].data
.p
);
4052 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
4054 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
4055 NULL_CHECK (sp
[-1].data
.p
);
4057 #ifdef NO_UNALIGNED_ACCESS
4058 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4059 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
4062 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
4064 MINT_IN_CASE(MINT_LDIND_I
) {
4065 guint16 offset
= ip
[1];
4066 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
4070 MINT_IN_CASE(MINT_LDIND_I8
) {
4071 guint16 offset
= ip
[1];
4072 #ifdef NO_UNALIGNED_ACCESS
4073 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
4074 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
4077 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
4081 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
4082 NULL_CHECK (sp
[-1].data
.p
);
4084 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
4086 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
4087 NULL_CHECK (sp
[-1].data
.p
);
4089 #ifdef NO_UNALIGNED_ACCESS
4090 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4091 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
4094 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
4096 MINT_IN_CASE(MINT_LDIND_REF
)
4098 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4100 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
4101 NULL_CHECK (sp
[-1].data
.p
);
4103 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4106 MINT_IN_CASE(MINT_STIND_REF
)
4109 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
4111 MINT_IN_CASE(MINT_STIND_I1
)
4114 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
4116 MINT_IN_CASE(MINT_STIND_I2
)
4119 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
4121 MINT_IN_CASE(MINT_STIND_I4
)
4124 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
4126 MINT_IN_CASE(MINT_STIND_I
)
4129 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
4131 MINT_IN_CASE(MINT_STIND_I8
)
4134 #ifdef NO_UNALIGNED_ACCESS
4135 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4136 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
4139 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
4141 MINT_IN_CASE(MINT_STIND_R4
)
4144 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
4146 MINT_IN_CASE(MINT_STIND_R8
)
4149 #ifdef NO_UNALIGNED_ACCESS
4150 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4151 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
4154 * (double *) sp
->data
.p
= sp
[1].data
.f
;
4156 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
4159 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
4161 #define BINOP(datamem, op) \
4163 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4165 MINT_IN_CASE(MINT_ADD_I4
)
4168 MINT_IN_CASE(MINT_ADD_I8
)
4171 MINT_IN_CASE(MINT_ADD_R4
)
4174 MINT_IN_CASE(MINT_ADD_R8
)
4177 MINT_IN_CASE(MINT_ADD1_I4
)
4181 MINT_IN_CASE(MINT_ADD1_I8
)
4185 MINT_IN_CASE(MINT_SUB_I4
)
4188 MINT_IN_CASE(MINT_SUB_I8
)
4191 MINT_IN_CASE(MINT_SUB_R4
)
4194 MINT_IN_CASE(MINT_SUB_R8
)
4197 MINT_IN_CASE(MINT_SUB1_I4
)
4201 MINT_IN_CASE(MINT_SUB1_I8
)
4205 MINT_IN_CASE(MINT_MUL_I4
)
4208 MINT_IN_CASE(MINT_MUL_I8
)
4211 MINT_IN_CASE(MINT_MUL_R4
)
4214 MINT_IN_CASE(MINT_MUL_R8
)
4217 MINT_IN_CASE(MINT_DIV_I4
)
4218 if (sp
[-1].data
.i
== 0)
4219 goto div_zero_label
;
4220 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4221 goto overflow_label
;
4224 MINT_IN_CASE(MINT_DIV_I8
)
4225 if (sp
[-1].data
.l
== 0)
4226 goto div_zero_label
;
4227 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4228 goto overflow_label
;
4231 MINT_IN_CASE(MINT_DIV_R4
)
4234 MINT_IN_CASE(MINT_DIV_R8
)
4238 #define BINOP_CAST(datamem, op, type) \
4240 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4242 MINT_IN_CASE(MINT_DIV_UN_I4
)
4243 if (sp
[-1].data
.i
== 0)
4244 goto div_zero_label
;
4245 BINOP_CAST(i
, /, guint32
);
4247 MINT_IN_CASE(MINT_DIV_UN_I8
)
4248 if (sp
[-1].data
.l
== 0)
4249 goto div_zero_label
;
4250 BINOP_CAST(l
, /, guint64
);
4252 MINT_IN_CASE(MINT_REM_I4
)
4253 if (sp
[-1].data
.i
== 0)
4254 goto div_zero_label
;
4255 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4256 goto overflow_label
;
4259 MINT_IN_CASE(MINT_REM_I8
)
4260 if (sp
[-1].data
.l
== 0)
4261 goto div_zero_label
;
4262 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4263 goto overflow_label
;
4266 MINT_IN_CASE(MINT_REM_R4
)
4267 /* FIXME: what do we actually do here? */
4269 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4272 MINT_IN_CASE(MINT_REM_R8
)
4273 /* FIXME: what do we actually do here? */
4275 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4278 MINT_IN_CASE(MINT_REM_UN_I4
)
4279 if (sp
[-1].data
.i
== 0)
4280 goto div_zero_label
;
4281 BINOP_CAST(i
, %, guint32
);
4283 MINT_IN_CASE(MINT_REM_UN_I8
)
4284 if (sp
[-1].data
.l
== 0)
4285 goto div_zero_label
;
4286 BINOP_CAST(l
, %, guint64
);
4288 MINT_IN_CASE(MINT_AND_I4
)
4291 MINT_IN_CASE(MINT_AND_I8
)
4294 MINT_IN_CASE(MINT_OR_I4
)
4297 MINT_IN_CASE(MINT_OR_I8
)
4300 MINT_IN_CASE(MINT_XOR_I4
)
4303 MINT_IN_CASE(MINT_XOR_I8
)
4307 #define SHIFTOP(datamem, op) \
4309 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4312 MINT_IN_CASE(MINT_SHL_I4
)
4315 MINT_IN_CASE(MINT_SHL_I8
)
4318 MINT_IN_CASE(MINT_SHR_I4
)
4321 MINT_IN_CASE(MINT_SHR_I8
)
4324 MINT_IN_CASE(MINT_SHR_UN_I4
)
4326 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4329 MINT_IN_CASE(MINT_SHR_UN_I8
)
4331 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4334 MINT_IN_CASE(MINT_NEG_I4
)
4335 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4338 MINT_IN_CASE(MINT_NEG_I8
)
4339 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4342 MINT_IN_CASE(MINT_NEG_R4
)
4343 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4346 MINT_IN_CASE(MINT_NEG_R8
)
4347 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4350 MINT_IN_CASE(MINT_NOT_I4
)
4351 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4354 MINT_IN_CASE(MINT_NOT_I8
)
4355 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4358 MINT_IN_CASE(MINT_CONV_I1_I4
)
4359 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4362 MINT_IN_CASE(MINT_CONV_I1_I8
)
4363 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4366 MINT_IN_CASE(MINT_CONV_I1_R4
)
4367 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4370 MINT_IN_CASE(MINT_CONV_I1_R8
)
4371 /* without gint32 cast, C compiler is allowed to use undefined
4372 * behaviour if data.f is bigger than >255. See conv.fpint section
4374 * > The conversion truncates; that is, the fractional part
4375 * > is discarded. The behavior is undefined if the truncated
4376 * > value cannot be represented in the destination type.
4378 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4381 MINT_IN_CASE(MINT_CONV_U1_I4
)
4382 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4385 MINT_IN_CASE(MINT_CONV_U1_I8
)
4386 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4389 MINT_IN_CASE(MINT_CONV_U1_R4
)
4390 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4393 MINT_IN_CASE(MINT_CONV_U1_R8
)
4394 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4397 MINT_IN_CASE(MINT_CONV_I2_I4
)
4398 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4401 MINT_IN_CASE(MINT_CONV_I2_I8
)
4402 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4405 MINT_IN_CASE(MINT_CONV_I2_R4
)
4406 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4409 MINT_IN_CASE(MINT_CONV_I2_R8
)
4410 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4413 MINT_IN_CASE(MINT_CONV_U2_I4
)
4414 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4417 MINT_IN_CASE(MINT_CONV_U2_I8
)
4418 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4421 MINT_IN_CASE(MINT_CONV_U2_R4
)
4422 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4425 MINT_IN_CASE(MINT_CONV_U2_R8
)
4426 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4429 MINT_IN_CASE(MINT_CONV_I4_R4
)
4430 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4433 MINT_IN_CASE(MINT_CONV_I4_R8
)
4434 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4437 MINT_IN_CASE(MINT_CONV_U4_I8
)
4438 MINT_IN_CASE(MINT_CONV_I4_I8
)
4439 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4442 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4443 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4446 MINT_IN_CASE(MINT_CONV_U4_R4
)
4447 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4448 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4450 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4454 MINT_IN_CASE(MINT_CONV_U4_R8
)
4455 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4456 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
4458 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4462 MINT_IN_CASE(MINT_CONV_I8_I4
)
4463 sp
[-1].data
.l
= sp
[-1].data
.i
;
4466 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4467 sp
[-2].data
.l
= sp
[-2].data
.i
;
4470 MINT_IN_CASE(MINT_CONV_I8_U4
)
4471 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4474 MINT_IN_CASE(MINT_CONV_I8_R4
)
4475 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4478 MINT_IN_CASE(MINT_CONV_I8_R8
)
4479 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4482 MINT_IN_CASE(MINT_CONV_R4_I4
)
4483 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4486 MINT_IN_CASE(MINT_CONV_R4_I8
)
4487 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4490 MINT_IN_CASE(MINT_CONV_R4_R8
)
4491 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4494 MINT_IN_CASE(MINT_CONV_R8_I4
)
4495 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4498 MINT_IN_CASE(MINT_CONV_R8_I8
)
4499 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4502 MINT_IN_CASE(MINT_CONV_R8_R4
)
4503 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4506 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4507 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4510 MINT_IN_CASE(MINT_CONV_U8_I4
)
4511 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
4514 MINT_IN_CASE(MINT_CONV_U8_R4
)
4515 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4516 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
4518 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4522 MINT_IN_CASE(MINT_CONV_U8_R8
)
4523 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4524 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
4526 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4530 MINT_IN_CASE(MINT_CPOBJ
) {
4531 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4532 g_assert (m_class_is_valuetype (c
));
4533 /* if this assertion fails, we need to add a write barrier */
4534 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4535 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4540 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4541 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4542 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4547 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4548 int size
= READ32(ip
+ 1);
4550 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4551 sp
[-1].data
.p
= vt_sp
;
4552 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4555 MINT_IN_CASE(MINT_LDSTR
)
4556 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
4560 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4561 MonoString
*s
= NULL
;
4562 guint32 strtoken
= (guint32
)(gsize
)frame
->imethod
->data_items
[ip
[1]];
4564 MonoMethod
*method
= frame
->imethod
->method
;
4565 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4566 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4567 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4568 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4570 g_assert_not_reached ();
4577 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4578 MonoClass
*newobj_class
;
4579 guint32 token
= ip
[1];
4580 guint16 param_count
= ip
[2];
4582 newobj_class
= (MonoClass
*) frame
->imethod
->data_items
[token
];
4585 sp
->data
.o
= ves_array_create (frame
->imethod
->domain
, newobj_class
, param_count
, sp
, error
);
4587 goto throw_error_label
;
4593 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
4595 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[3]];
4596 INIT_VTABLE (vtable
);
4597 MonoObject
*o
; // See the comment about GC safety.
4598 guint16 param_count
;
4599 guint16 imethod_index
= ip
[1];
4601 const gboolean is_inlined
= imethod_index
== 0xffff;
4603 param_count
= ip
[2];
4607 memmove (sp
+ 1 + is_inlined
, sp
, param_count
* sizeof (stackval
));
4610 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4611 if (G_UNLIKELY (!o
)) {
4612 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4613 goto throw_error_label
;
4619 sp
+= param_count
+ 2;
4621 InterpMethod
*ctor_method
= (InterpMethod
*) frame
->imethod
->data_items
[imethod_index
];
4624 child_frame
.imethod
= ctor_method
;
4625 child_frame
.stack_args
= sp
;
4627 interp_exec_method (&child_frame
, context
, error
);
4628 CHECK_RESUME_STATE (context
);
4636 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4637 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4639 // This is split up to:
4641 // - keep exception handling and resume mostly in the main function
4644 child_frame
.imethod
= (InterpMethod
*) frame
->imethod
->data_items
[ip
[1]];
4645 guint16
const param_count
= ip
[2];
4649 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
4651 child_frame
.stack_args
= sp
;
4652 gboolean
const vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4654 memset (vt_sp
, 0, ip
[3]);
4658 interp_exec_method (&child_frame
, context
, error
);
4660 CHECK_RESUME_STATE (context
);
4665 mono_interp_newobj_vt (&child_frame
, context
, error
);
4666 CHECK_RESUME_STATE (context
);
4672 MINT_IN_CASE(MINT_NEWOBJ
) {
4674 // This is split up to:
4676 // - keep exception handling and resume mostly in the main function
4680 guint32
const token
= ip
[1];
4681 ip
+= 2; // FIXME: Do this after throw?
4683 child_frame
.ip
= NULL
;
4685 child_frame
.imethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
4686 MonoMethodSignature
* const csig
= mono_method_signature_internal (child_frame
.imethod
->method
);
4688 g_assert (csig
->hasthis
);
4689 if (csig
->param_count
) {
4690 sp
-= csig
->param_count
;
4691 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
4694 child_frame
.stack_args
= sp
;
4696 MonoException
* const exc
= mono_interp_newobj (&child_frame
, context
, error
, vt_sp
);
4699 CHECK_RESUME_STATE (context
);
4703 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
4709 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
4710 MonoMethodSignature
*csig
;
4717 InterpMethod
*cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
4718 csig
= mono_method_signature_internal (cmethod
->method
);
4720 g_assert (csig
->hasthis
);
4721 sp
-= csig
->param_count
;
4723 gpointer arg0
= sp
[0].data
.p
;
4725 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
4726 *byreference_this
= arg0
;
4728 /* Followed by a VTRESULT opcode which will push the result on the stack */
4732 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4733 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4734 sp
[-1].data
.p
= *byreference_this
;
4738 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
4740 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
4745 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
4747 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
4752 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
4753 MonoObject
*obj
= sp
[-1].data
.o
;
4754 sp
[-1].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
4758 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
4759 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
4760 MonoObject
* const o
= sp
[-1].data
.o
;
4762 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4764 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
4766 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
4768 isinst
= mono_interp_isinst (o
, c
); // FIXME: do not swallow the error
4774 gboolean
const isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
4776 sp
[-1].data
.p
= NULL
;
4778 goto invalid_cast_label
;
4784 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
4785 MINT_IN_CASE(MINT_ISINST_COMMON
) {
4786 MonoObject
* const o
= sp
[-1].data
.o
;
4788 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4789 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
4792 gboolean
const isinst_instr
= *ip
== MINT_ISINST_COMMON
;
4794 sp
[-1].data
.p
= NULL
;
4796 goto invalid_cast_label
;
4802 MINT_IN_CASE(MINT_CASTCLASS
)
4803 MINT_IN_CASE(MINT_ISINST
) {
4804 MonoObject
* const o
= sp
[-1].data
.o
;
4806 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4807 if (!mono_interp_isinst (o
, c
)) { // FIXME: do not swallow the error
4808 gboolean
const isinst_instr
= *ip
== MINT_ISINST
;
4810 sp
[-1].data
.p
= NULL
;
4812 goto invalid_cast_label
;
4818 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4819 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4822 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4823 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4826 MINT_IN_CASE(MINT_UNBOX
) {
4827 MonoObject
* const o
= sp
[-1].data
.o
;
4829 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4831 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
4832 goto invalid_cast_label
;
4834 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
4838 MINT_IN_CASE(MINT_THROW
)
4841 sp
->data
.p
= mono_get_exception_null_reference ();
4843 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4845 MINT_IN_CASE(MINT_CHECKPOINT
)
4846 /* Do synchronous checking of abort requests */
4847 EXCEPTION_CHECKPOINT
;
4850 MINT_IN_CASE(MINT_SAFEPOINT
)
4851 /* Do synchronous checking of abort requests */
4852 EXCEPTION_CHECKPOINT
;
4853 /* Poll safepoint */
4854 mono_threads_safepoint ();
4857 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
) {
4858 sp
[-1].data
.p
= (char*)sp
[-1].data
.o
+ ip
[1];
4862 MINT_IN_CASE(MINT_LDFLDA
) {
4863 MonoObject
* const o
= sp
[-1].data
.o
;
4865 sp
[-1].data
.p
= (char *)o
+ ip
[1];
4869 MINT_IN_CASE(MINT_CKNULL_N
) {
4870 /* Same as CKNULL, but further down the stack */
4871 int const n
= ip
[1];
4872 MonoObject
* const o
= sp
[-n
].data
.o
;
4878 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4879 MonoObject* const o = sp [-1].data.o; \
4882 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
4884 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
4888 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4890 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4891 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4892 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4893 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4894 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4895 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4896 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
4897 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4898 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4899 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4900 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4901 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4903 MINT_IN_CASE(MINT_LDFLD_VT
) {
4904 MonoObject
* const o
= sp
[-1].data
.o
;
4907 int size
= READ32(ip
+ 2);
4908 sp
[-1].data
.p
= vt_sp
;
4909 memcpy (sp
[-1].data
.p
, (char *)o
+ ip
[1], size
);
4910 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4915 MINT_IN_CASE(MINT_LDRMFLD
) {
4916 MonoObject
* const o
= sp
[-1].data
.o
;
4918 mono_interp_load_remote_field (frame
->imethod
, o
, ip
, sp
);
4922 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
4923 MonoObject
* const o
= sp
[-1].data
.o
;
4925 vt_sp
= mono_interp_load_remote_field_vt (frame
->imethod
, o
, ip
, sp
, vt_sp
);
4930 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4931 MonoObject* const o = sp [-2].data.o; \
4935 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
4937 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
4941 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4943 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
4944 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
4945 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
4946 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
4947 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
4948 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
4949 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
4950 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
4951 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
4952 MINT_IN_CASE(MINT_STFLD_O
) {
4953 MonoObject
* const o
= sp
[-2].data
.o
;
4956 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[1], sp
[1].data
.o
);
4960 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4961 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4963 MINT_IN_CASE(MINT_STFLD_VT
) {
4964 MonoObject
* const o
= sp
[-2].data
.o
;
4968 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[2]];
4969 int const i32
= mono_class_value_size (klass
, NULL
);
4971 guint16 offset
= ip
[1];
4972 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
4974 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4978 MINT_IN_CASE(MINT_STRMFLD
) {
4979 MonoClassField
*field
;
4981 MonoObject
* const o
= sp
[-2].data
.o
;
4984 field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
4987 #ifndef DISABLE_REMOTING
4988 if (mono_object_is_transparent_proxy (o
)) {
4989 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4990 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4991 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
4994 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
4999 MINT_IN_CASE(MINT_STRMFLD_VT
)
5001 NULL_CHECK (sp
[-2].data
.o
);
5002 vt_sp
-= mono_interp_store_remote_field_vt (frame
, ip
, sp
, error
);
5007 MINT_IN_CASE(MINT_LDSFLDA
) {
5008 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5009 INIT_VTABLE (vtable
);
5010 sp
->data
.p
= frame
->imethod
->data_items
[ip
[2]];
5016 MINT_IN_CASE(MINT_LDSSFLDA
) {
5017 guint32 offset
= READ32(ip
+ 1);
5018 sp
->data
.p
= mono_get_special_static_data (offset
);
5024 /* We init class here to preserve cctor order */
5025 #define LDSFLD(datamem, fieldtype) { \
5026 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5027 INIT_VTABLE (vtable); \
5028 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5033 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
5034 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
5035 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
5036 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
5037 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
5038 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
5039 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
5040 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
5041 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5042 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5044 MINT_IN_CASE(MINT_LDSFLD_VT
) {
5045 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5046 INIT_VTABLE (vtable
);
5049 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5050 int const i32
= READ32 (ip
+ 3);
5051 memcpy (vt_sp
, addr
, i32
);
5052 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5058 #define LDTSFLD(datamem, fieldtype) { \
5059 MonoInternalThread *thread = mono_thread_internal_current (); \
5060 guint32 offset = READ32 (ip + 1); \
5061 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5062 sp[0].data.datamem = *(fieldtype*)addr; \
5066 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
5067 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
5068 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
5069 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
5070 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
5071 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
5072 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
5073 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
5074 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5075 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5077 MINT_IN_CASE(MINT_LDSSFLD
) {
5078 guint32 offset
= READ32(ip
+ 2);
5079 gpointer addr
= mono_get_special_static_data (offset
);
5080 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5081 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
5086 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
5087 guint32 offset
= READ32(ip
+ 1);
5088 gpointer addr
= mono_get_special_static_data (offset
);
5090 int size
= READ32 (ip
+ 3);
5091 memcpy (vt_sp
, addr
, size
);
5093 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5098 #define STSFLD(datamem, fieldtype) { \
5099 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5100 INIT_VTABLE (vtable); \
5102 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5106 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5107 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5108 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5109 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5110 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5111 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5112 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5113 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5114 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5115 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5117 MINT_IN_CASE(MINT_STSFLD_VT
) {
5118 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5119 INIT_VTABLE (vtable
);
5120 int const i32
= READ32 (ip
+ 3);
5121 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5123 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5124 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5130 #define STTSFLD(datamem, fieldtype) { \
5131 MonoInternalThread *thread = mono_thread_internal_current (); \
5132 guint32 offset = READ32 (ip + 1); \
5133 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5135 *(fieldtype*)addr = sp[0].data.datamem; \
5139 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5140 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5141 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5142 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5143 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5144 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5145 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5146 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5147 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5148 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5150 MINT_IN_CASE(MINT_STSSFLD
) {
5151 guint32 offset
= READ32(ip
+ 2);
5152 gpointer addr
= mono_get_special_static_data (offset
);
5153 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5155 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5159 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5160 guint32 offset
= READ32(ip
+ 1);
5161 gpointer addr
= mono_get_special_static_data (offset
);
5163 int size
= READ32 (ip
+ 3);
5164 memcpy (addr
, sp
->data
.vt
, size
);
5165 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5170 MINT_IN_CASE(MINT_STOBJ_VT
) {
5172 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5174 size
= mono_class_value_size (c
, NULL
);
5175 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5176 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5180 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5181 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5182 goto overflow_label
;
5183 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5186 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5187 if (sp
[-1].data
.i
< 0)
5188 goto overflow_label
;
5189 sp
[-1].data
.l
= sp
[-1].data
.i
;
5192 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5193 if (sp
[-1].data
.l
< 0)
5194 goto overflow_label
;
5197 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5198 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5199 goto overflow_label
;
5202 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5203 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5204 goto overflow_label
;
5205 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5208 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5209 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5210 goto overflow_label
;
5211 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5214 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5215 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
5216 goto overflow_label
;
5217 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5220 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
)
5221 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT64
)
5222 goto overflow_label
;
5223 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5226 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5227 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5228 goto overflow_label
;
5229 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5232 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5233 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5234 goto overflow_label
;
5235 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5238 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5239 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5240 goto overflow_label
;
5241 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5244 MINT_IN_CASE(MINT_BOX
) {
5245 mono_interp_box (frame
, ip
, sp
);
5249 MINT_IN_CASE(MINT_BOX_VT
) {
5250 vt_sp
-= mono_interp_box_vt (frame
, ip
, sp
);
5254 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5255 vt_sp
-= mono_interp_box_nullable (frame
, ip
, sp
, error
);
5259 MINT_IN_CASE(MINT_NEWARR
) {
5260 MonoVTable
*vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
5261 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5262 if (!is_ok (error
)) {
5263 goto throw_error_label
;
5266 /*if (profiling_classes) {
5267 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5269 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5274 MINT_IN_CASE(MINT_LDLEN
) {
5275 MonoObject
* const o
= sp
[-1].data
.o
;
5277 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5281 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5282 MonoObject
* const o
= sp
[-1].data
.o
;
5284 gsize offset_length
= (gsize
)(gint16
)ip
[1];
5285 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5289 MINT_IN_CASE(MINT_GETCHR
) {
5291 s
= (MonoString
*)sp
[-2].data
.p
;
5293 int const i32
= sp
[-1].data
.i
;
5294 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5295 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5297 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5301 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5302 guint8
* const span
= (guint8
*) sp
[-2].data
.p
;
5303 const int index
= sp
[-1].data
.i
;
5308 const gsize offset_length
= (gsize
)(gint16
)ip
[2];
5310 const gint32 length
= *(gint32
*) (span
+ offset_length
);
5311 if (index
< 0 || index
>= length
)
5312 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5314 const gsize element_size
= (gsize
)(gint16
)ip
[1];
5315 const gsize offset_pointer
= (gsize
)(gint16
)ip
[3];
5317 const gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5318 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5323 MINT_IN_CASE(MINT_STRLEN
) {
5325 MonoObject
* const o
= sp
[-1].data
.o
;
5327 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5330 MINT_IN_CASE(MINT_ARRAY_RANK
) {
5331 MonoObject
* const o
= sp
[-1].data
.o
;
5333 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
5337 MINT_IN_CASE(MINT_LDELEMA1
) {
5338 /* No bounds, one direction */
5339 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
5341 gint32
const index
= sp
[-1].data
.i
;
5342 if (index
>= ao
->max_length
)
5343 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5344 gint32
const size
= READ32 (ip
+ 1);
5345 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
5351 MINT_IN_CASE(MINT_LDELEMA
) {
5352 guint16 rank
= ip
[1];
5353 gint32
const esize
= READ32 (ip
+ 2);
5357 MonoArray
* const ao
= (MonoArray
*) sp
[-1].data
.o
;
5360 g_assert (ao
->bounds
);
5362 for (int i
= 0; i
< rank
; i
++) {
5363 guint32 idx
= sp
[i
].data
.i
;
5364 guint32 lower
= ao
->bounds
[i
].lower_bound
;
5365 guint32 len
= ao
->bounds
[i
].length
;
5366 if (idx
< lower
|| (idx
- lower
) >= len
)
5367 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5368 pos
= (pos
* len
) + idx
- lower
;
5371 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
5374 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5375 guint16 rank
= ip
[1];
5379 MonoObject
* const o
= sp
[-1].data
.o
;
5382 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[-3 + 2]];
5383 const gboolean needs_typecheck
= ip
[-3] == MINT_LDELEMA_TC
;
5384 MonoException
*ex
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, sp
, needs_typecheck
);
5389 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
5390 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
5391 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
5392 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
5393 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
5394 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
5395 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
5396 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
5397 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
5398 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
5399 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
5400 MINT_IN_CASE(MINT_LDELEM_VT
) {
5406 o
= (MonoArray
*)sp
[0].data
.p
;
5409 aindex
= sp
[1].data
.i
;
5410 if (aindex
>= mono_array_length_internal (o
))
5411 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5414 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5417 case MINT_LDELEM_I1
:
5418 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
5420 case MINT_LDELEM_U1
:
5421 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
5423 case MINT_LDELEM_I2
:
5424 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
5426 case MINT_LDELEM_U2
:
5427 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
5430 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
5432 case MINT_LDELEM_I4
:
5433 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
5435 case MINT_LDELEM_U4
:
5436 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
5438 case MINT_LDELEM_I8
:
5439 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
5441 case MINT_LDELEM_R4
:
5442 sp
[0].data
.f_r4
= mono_array_get_fast (o
, float, aindex
);
5444 case MINT_LDELEM_R8
:
5445 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
5447 case MINT_LDELEM_REF
:
5448 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
5450 case MINT_LDELEM_VT
: {
5451 int const i32
= READ32 (ip
+ 1);
5452 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5453 sp
[0].data
.vt
= vt_sp
;
5454 // Copying to vtstack. No wbarrier needed
5455 memcpy (sp
[0].data
.vt
, src_addr
, i32
);
5456 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5468 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
5469 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
5470 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
5471 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
5472 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
5473 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
5474 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
5475 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
5476 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
5477 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
5478 MINT_IN_CASE(MINT_STELEM_VT
) {
5483 MonoObject
* const o
= sp
[0].data
.o
;
5486 aindex
= sp
[1].data
.i
;
5487 if (aindex
>= mono_array_length_internal ((MonoArray
*)o
))
5488 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5492 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
5494 case MINT_STELEM_I1
:
5495 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
5497 case MINT_STELEM_U1
:
5498 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
5500 case MINT_STELEM_I2
:
5501 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
5503 case MINT_STELEM_U2
:
5504 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
5506 case MINT_STELEM_I4
:
5507 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
5509 case MINT_STELEM_I8
:
5510 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
5512 case MINT_STELEM_R4
:
5513 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f_r4
);
5515 case MINT_STELEM_R8
:
5516 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
5518 case MINT_STELEM_REF
: {
5519 if (sp
[2].data
.p
) {
5520 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
5521 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
5523 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5525 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5528 case MINT_STELEM_VT
: {
5529 MonoClass
*klass_vt
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5530 int const i32
= READ32 (ip
+ 2);
5531 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5533 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5534 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5545 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5546 if (sp
[-1].data
.i
< 0)
5547 goto overflow_label
;
5550 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5551 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5552 goto overflow_label
;
5553 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5556 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5557 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5558 goto overflow_label
;
5559 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5562 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5563 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
)
5564 goto overflow_label
;
5565 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5568 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5569 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
5570 goto overflow_label
;
5571 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5574 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5575 if (sp
[-1].data
.i
< 0)
5576 goto overflow_label
;
5579 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5580 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5581 goto overflow_label
;
5582 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5585 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5586 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
)
5587 goto overflow_label
;
5588 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5591 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5592 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
5593 goto overflow_label
;
5594 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5597 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5598 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5599 goto overflow_label
;
5602 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
5603 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
5604 goto overflow_label
;
5607 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
5608 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
5609 goto overflow_label
;
5610 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5613 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
5614 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
5615 goto overflow_label
;
5616 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5619 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
5620 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
5621 goto overflow_label
;
5622 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5625 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
5626 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
5627 goto overflow_label
;
5628 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5631 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
5632 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
5633 goto overflow_label
;
5636 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
5637 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
5638 goto overflow_label
;
5639 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
5642 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
5643 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
5644 goto overflow_label
;
5645 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
5648 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
5649 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
5650 goto overflow_label
;
5653 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
5654 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
5655 goto overflow_label
;
5658 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
5659 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
5660 goto overflow_label
;
5661 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5664 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
5665 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
5666 goto overflow_label
;
5667 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5670 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
5671 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
5672 goto overflow_label
;
5673 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5676 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
5677 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
5678 goto overflow_label
;
5679 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5682 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
5683 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
5684 goto overflow_label
;
5687 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
5688 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
5689 goto overflow_label
;
5690 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
5693 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
5694 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
5695 goto overflow_label
;
5696 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
5699 MINT_IN_CASE(MINT_CKFINITE
)
5700 if (!mono_isfinite (sp
[-1].data
.f
))
5701 THROW_EX (mono_get_exception_arithmetic (), ip
);
5704 MINT_IN_CASE(MINT_MKREFANY
) {
5705 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5707 /* The value address is on the stack */
5708 gpointer addr
= sp
[-1].data
.p
;
5709 /* Push the typedref value on the stack */
5710 sp
[-1].data
.p
= vt_sp
;
5711 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5713 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5715 tref
->type
= m_class_get_byval_arg (c
);
5721 MINT_IN_CASE(MINT_REFANYTYPE
) {
5722 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5723 MonoType
*type
= tref
->type
;
5725 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5726 sp
[-1].data
.p
= vt_sp
;
5728 *(gpointer
*)sp
[-1].data
.p
= type
;
5732 MINT_IN_CASE(MINT_REFANYVAL
) {
5733 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5734 gpointer addr
= tref
->value
;
5736 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5737 if (c
!= tref
->klass
)
5738 goto invalid_cast_label
;
5740 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5742 sp
[-1].data
.p
= addr
;
5746 MINT_IN_CASE(MINT_LDTOKEN
)
5749 * (gpointer
*)sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
5753 MINT_IN_CASE(MINT_ADD_OVF_I4
)
5754 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5755 goto overflow_label
;
5758 MINT_IN_CASE(MINT_ADD_OVF_I8
)
5759 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5760 goto overflow_label
;
5763 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
5764 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5765 goto overflow_label
;
5766 BINOP_CAST(i
, +, guint32
);
5768 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
5769 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5770 goto overflow_label
;
5771 BINOP_CAST(l
, +, guint64
);
5773 MINT_IN_CASE(MINT_MUL_OVF_I4
)
5774 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5775 goto overflow_label
;
5778 MINT_IN_CASE(MINT_MUL_OVF_I8
)
5779 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5780 goto overflow_label
;
5783 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
5784 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5785 goto overflow_label
;
5786 BINOP_CAST(i
, *, guint32
);
5788 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
5789 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5790 goto overflow_label
;
5791 BINOP_CAST(l
, *, guint64
);
5793 MINT_IN_CASE(MINT_SUB_OVF_I4
)
5794 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5795 goto overflow_label
;
5798 MINT_IN_CASE(MINT_SUB_OVF_I8
)
5799 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5800 goto overflow_label
;
5803 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
5804 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5805 goto overflow_label
;
5806 BINOP_CAST(i
, -, guint32
);
5808 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
5809 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5810 goto overflow_label
;
5811 BINOP_CAST(l
, -, guint64
);
5813 MINT_IN_CASE(MINT_START_ABORT_PROT
)
5814 mono_threads_begin_abort_protected_block ();
5817 MINT_IN_CASE(MINT_ENDFINALLY
) {
5818 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
5821 // After mono_threads_end_abort_protected_block to conserve stack.
5822 const int clause_index
= *ip
;
5824 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
5827 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
5828 g_assert (sp
>= frame
->stack
);
5833 ip
= (const guint16
*)finally_ips
->data
;
5834 finally_ips
= g_slist_remove (finally_ips
, ip
);
5835 /* Throw abort after the last finally block to avoid confusing EH */
5836 if (pending_abort
&& !finally_ips
)
5837 EXCEPTION_CHECKPOINT
;
5838 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5839 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5846 MINT_IN_CASE(MINT_LEAVE
)
5847 MINT_IN_CASE(MINT_LEAVE_S
)
5848 MINT_IN_CASE(MINT_LEAVE_CHECK
)
5849 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
5851 // Leave is split into pieces in order to consume less stack,
5852 // but not have to change how exception handling macros access labels and locals.
5854 g_assert (sp
>= frame
->stack
);
5855 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5856 vt_sp
= (unsigned char*)sp
+ frame
->imethod
->stack_size
;
5861 gboolean
const check
= opcode
== MINT_LEAVE_CHECK
|| opcode
== MINT_LEAVE_S_CHECK
;
5863 if (check
&& frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
5864 child_frame
.parent
= frame
;
5865 child_frame
.imethod
= NULL
;
5866 MonoException
*abort_exc
= mono_interp_leave (&child_frame
);
5868 THROW_EX (abort_exc
, frame
->ip
);
5871 opcode
= *ip
; // Refetch to avoid register/stack pressure.
5872 gboolean
const short_offset
= opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
;
5873 ip
+= short_offset
? (short)*(ip
+ 1) : (gint32
)READ32 (ip
+ 1);
5874 const guint16
*endfinally_ip
= ip
;
5875 GSList
*old_list
= finally_ips
;
5876 MonoMethod
*method
= frame
->imethod
->method
;
5879 g_print ("* Handle finally IL_%04x\n", endfinally_ip
- frame
->imethod
->code
);
5881 // FIXME Null check for frame->imethod follows deref.
5882 if (frame
->imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5883 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5886 guint32
const ip_offset
= frame
->ip
- frame
->imethod
->code
;
5888 finally_ips
= g_slist_prepend (finally_ips
, (void *)endfinally_ip
);
5890 for (int i
= frame
->imethod
->num_clauses
- 1; i
>= 0; i
--) {
5891 MonoExceptionClause
* const clause
= &frame
->imethod
->clauses
[i
];
5892 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- frame
->imethod
->code
))) {
5893 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5894 ip
= frame
->imethod
->code
+ clause
->handler_offset
;
5895 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5898 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, context
->has_resume_state
? "yes": "no");
5904 if (old_list
!= finally_ips
&& finally_ips
) {
5905 ip
= (const guint16
*)finally_ips
->data
;
5906 finally_ips
= g_slist_remove (finally_ips
, ip
);
5907 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5908 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5915 MINT_IN_CASE(MINT_ICALL_V_V
)
5916 MINT_IN_CASE(MINT_ICALL_V_P
)
5917 MINT_IN_CASE(MINT_ICALL_P_V
)
5918 MINT_IN_CASE(MINT_ICALL_P_P
)
5919 MINT_IN_CASE(MINT_ICALL_PP_V
)
5920 MINT_IN_CASE(MINT_ICALL_PP_P
)
5921 MINT_IN_CASE(MINT_ICALL_PPP_V
)
5922 MINT_IN_CASE(MINT_ICALL_PPP_P
)
5923 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
5924 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
5925 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
5926 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
5927 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
5928 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
5930 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, frame
->imethod
->data_items
[ip
[1]], FALSE
);
5931 EXCEPTION_CHECKPOINT
;
5932 CHECK_RESUME_STATE (context
);
5935 MINT_IN_CASE(MINT_MONO_LDPTR
)
5936 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
5940 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
5941 sp
->data
.o
= mono_interp_new (frame
->imethod
->domain
, (MonoClass
*)frame
->imethod
->data_items
[ip
[1]]); // FIXME: do not swallow the error
5945 MINT_IN_CASE(MINT_MONO_RETOBJ
)
5948 stackval_from_data (mono_method_signature_internal (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
5949 mono_method_signature_internal (frame
->imethod
->method
)->pinvoke
);
5950 if (sp
> frame
->stack
)
5951 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
5953 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
5954 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
5958 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
5960 mono_memory_barrier ();
5963 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
5964 sp
->data
.p
= mono_domain_get ();
5968 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
5969 if (G_UNLIKELY (ss_enabled
)) {
5970 typedef void (*T
) (void);
5974 void *tramp
= mini_get_single_step_trampoline ();
5975 mono_memory_barrier ();
5976 ss_tramp
= (T
)tramp
;
5980 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5981 * the address of that instruction is stored as the seq point address.
5986 * Use the same trampoline as the JIT. This ensures that
5987 * the debugger has the context for the last interpreter
5990 do_debugger_tramp (ss_tramp
, frame
);
5992 CHECK_RESUME_STATE (context
);
5996 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
5997 /* Just a placeholder for a breakpoint */
6000 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
6001 typedef void (*T
) (void);
6004 void *tramp
= mini_get_breakpoint_trampoline ();
6005 mono_memory_barrier ();
6006 bp_tramp
= (T
)tramp
;
6011 /* Use the same trampoline as the JIT */
6012 do_debugger_tramp (bp_tramp
, frame
);
6014 CHECK_RESUME_STATE (context
);
6020 #define RELOP(datamem, op) \
6022 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6025 #define RELOP_FP(datamem, op, noorder) \
6027 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6028 sp [-1].data.i = noorder; \
6030 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6033 MINT_IN_CASE(MINT_CEQ_I4
)
6036 MINT_IN_CASE(MINT_CEQ0_I4
)
6037 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
6040 MINT_IN_CASE(MINT_CEQ_I8
)
6043 MINT_IN_CASE(MINT_CEQ_R4
)
6044 RELOP_FP(f_r4
, ==, 0);
6046 MINT_IN_CASE(MINT_CEQ_R8
)
6049 MINT_IN_CASE(MINT_CNE_I4
)
6052 MINT_IN_CASE(MINT_CNE_I8
)
6055 MINT_IN_CASE(MINT_CNE_R4
)
6056 RELOP_FP(f_r4
, !=, 1);
6058 MINT_IN_CASE(MINT_CNE_R8
)
6061 MINT_IN_CASE(MINT_CGT_I4
)
6064 MINT_IN_CASE(MINT_CGT_I8
)
6067 MINT_IN_CASE(MINT_CGT_R4
)
6068 RELOP_FP(f_r4
, >, 0);
6070 MINT_IN_CASE(MINT_CGT_R8
)
6073 MINT_IN_CASE(MINT_CGE_I4
)
6076 MINT_IN_CASE(MINT_CGE_I8
)
6079 MINT_IN_CASE(MINT_CGE_R4
)
6080 RELOP_FP(f_r4
, >=, 0);
6082 MINT_IN_CASE(MINT_CGE_R8
)
6086 #define RELOP_CAST(datamem, op, type) \
6088 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6091 MINT_IN_CASE(MINT_CGE_UN_I4
)
6092 RELOP_CAST(l
, >=, guint32
);
6094 MINT_IN_CASE(MINT_CGE_UN_I8
)
6095 RELOP_CAST(l
, >=, guint64
);
6098 MINT_IN_CASE(MINT_CGT_UN_I4
)
6099 RELOP_CAST(i
, >, guint32
);
6101 MINT_IN_CASE(MINT_CGT_UN_I8
)
6102 RELOP_CAST(l
, >, guint64
);
6104 MINT_IN_CASE(MINT_CGT_UN_R4
)
6105 RELOP_FP(f_r4
, >, 1);
6107 MINT_IN_CASE(MINT_CGT_UN_R8
)
6110 MINT_IN_CASE(MINT_CLT_I4
)
6113 MINT_IN_CASE(MINT_CLT_I8
)
6116 MINT_IN_CASE(MINT_CLT_R4
)
6117 RELOP_FP(f_r4
, <, 0);
6119 MINT_IN_CASE(MINT_CLT_R8
)
6122 MINT_IN_CASE(MINT_CLT_UN_I4
)
6123 RELOP_CAST(i
, <, guint32
);
6125 MINT_IN_CASE(MINT_CLT_UN_I8
)
6126 RELOP_CAST(l
, <, guint64
);
6128 MINT_IN_CASE(MINT_CLT_UN_R4
)
6129 RELOP_FP(f_r4
, <, 1);
6131 MINT_IN_CASE(MINT_CLT_UN_R8
)
6134 MINT_IN_CASE(MINT_CLE_I4
)
6137 MINT_IN_CASE(MINT_CLE_I8
)
6140 MINT_IN_CASE(MINT_CLE_UN_I4
)
6141 RELOP_CAST(l
, <=, guint32
);
6143 MINT_IN_CASE(MINT_CLE_UN_I8
)
6144 RELOP_CAST(l
, <=, guint64
);
6146 MINT_IN_CASE(MINT_CLE_R4
)
6147 RELOP_FP(f_r4
, <=, 0);
6149 MINT_IN_CASE(MINT_CLE_R8
)
6157 MINT_IN_CASE(MINT_LDFTN
) {
6158 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6163 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6164 InterpMethod
*m
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
6166 NULL_CHECK (sp
->data
.p
);
6168 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6173 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6174 MONO_API_ERROR_INIT (error
);
6175 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6176 mono_error_assert_ok (error
);
6182 #define LDARG(datamem, argtype) \
6183 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6187 #define LDARGn(datamem, argtype, n) \
6188 sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \
6192 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
6193 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
6194 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
6195 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
6196 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
6197 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
6198 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
6199 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
6200 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6201 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6203 MINT_IN_CASE(MINT_LDARG_P0
) LDARGn(p
, gpointer
, 0); MINT_IN_BREAK
;
6205 MINT_IN_CASE(MINT_LDARG_VT
) {
6207 int const i32
= READ32 (ip
+ 2);
6208 memcpy(sp
->data
.p
, frame
->stack_args
[ip
[1]].data
.p
, i32
);
6209 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6215 #define STARG(datamem, argtype) \
6217 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6220 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
6221 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
6222 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
6223 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
6224 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
6225 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
6226 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6227 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6228 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6229 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6231 MINT_IN_CASE(MINT_STARG_VT
) {
6232 int const i32
= READ32 (ip
+ 2);
6234 memcpy(frame
->stack_args
[ip
[1]].data
.p
, sp
->data
.p
, i32
);
6235 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6239 MINT_IN_CASE(MINT_PROF_ENTER
) {
6242 if (MONO_PROFILER_ENABLED (method_enter
)) {
6243 MonoProfilerCallContext
*prof_ctx
= NULL
;
6245 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
6246 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6247 prof_ctx
->interp_frame
= frame
;
6248 prof_ctx
->method
= frame
->imethod
->method
;
6251 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
6259 MINT_IN_CASE(MINT_TRACE_ENTER
) {
6262 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6263 prof_ctx
->interp_frame
= frame
;
6264 prof_ctx
->method
= frame
->imethod
->method
;
6266 mono_trace_enter_method (frame
->imethod
->method
, prof_ctx
);
6270 MINT_IN_CASE(MINT_TRACE_EXIT
) {
6272 int const i32
= READ32 (ip
+ 1);
6277 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6279 *frame
->retval
= *sp
;
6281 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6282 prof_ctx
->interp_frame
= frame
;
6283 prof_ctx
->method
= frame
->imethod
->method
;
6285 mono_trace_leave_method (frame
->imethod
->method
, prof_ctx
);
6290 MINT_IN_CASE(MINT_LDARGA
)
6291 sp
->data
.p
= &frame
->stack_args
[ip
[1]];
6296 MINT_IN_CASE(MINT_LDARGA_VT
)
6297 sp
->data
.p
= frame
->stack_args
[ip
[1]].data
.p
;
6302 #define LDLOC(datamem, argtype) \
6303 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6307 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6308 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6309 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6310 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6311 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6312 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6313 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6314 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6315 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6316 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6318 MINT_IN_CASE(MINT_LDLOC_VT
) {
6320 int const i32
= READ32 (ip
+ 2);
6321 memcpy(sp
->data
.p
, locals
+ ip
[1], i32
);
6322 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6327 MINT_IN_CASE(MINT_LDLOCA_S
)
6328 sp
->data
.p
= locals
+ ip
[1];
6333 #define STLOC(datamem, argtype) \
6335 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6338 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6339 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6340 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6341 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6342 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6343 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6344 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6345 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6346 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6347 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6349 #define STLOC_NP(datamem, argtype) \
6350 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6353 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6354 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6356 MINT_IN_CASE(MINT_STLOC_VT
) {
6357 int const i32
= READ32 (ip
+ 2);
6359 memcpy(locals
+ ip
[1], sp
->data
.p
, i32
);
6360 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6365 #define MOVLOC(argtype) \
6366 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6369 MINT_IN_CASE(MINT_MOVLOC_1
) MOVLOC(guint8
); MINT_IN_BREAK
;
6370 MINT_IN_CASE(MINT_MOVLOC_2
) MOVLOC(guint16
); MINT_IN_BREAK
;
6371 MINT_IN_CASE(MINT_MOVLOC_4
) MOVLOC(guint32
); MINT_IN_BREAK
;
6372 MINT_IN_CASE(MINT_MOVLOC_8
) MOVLOC(guint64
); MINT_IN_BREAK
;
6374 MINT_IN_CASE(MINT_MOVLOC_VT
) {
6375 int const i32
= READ32(ip
+ 3);
6376 memcpy (locals
+ ip
[2], locals
+ ip
[1], i32
);
6381 MINT_IN_CASE(MINT_LOCALLOC
) {
6382 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6385 int len
= sp
[-1].data
.i
;
6386 sp
[-1].data
.p
= alloca (len
);
6388 if (frame
->imethod
->init_locals
)
6389 memset (sp
[-1].data
.p
, 0, len
);
6393 MINT_IN_CASE(MINT_ENDFILTER
)
6394 /* top of stack is result of filter */
6395 frame
->retval
= &sp
[-1];
6397 MINT_IN_CASE(MINT_INITOBJ
)
6399 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6402 MINT_IN_CASE(MINT_CPBLK
)
6404 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6405 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6407 /* FIXME: value and size may be int64... */
6408 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6411 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6413 /* FIXME: implement */
6415 token
= READ32 (ip
);
6420 MINT_IN_CASE(MINT_INITBLK
)
6422 NULL_CHECK (sp
[0].data
.p
);
6424 /* FIXME: value and size may be int64... */
6425 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6428 MINT_IN_CASE(MINT_NO_
)
6429 /* FIXME: implement */
6433 MINT_IN_CASE(MINT_RETHROW
) {
6434 int exvar_offset
= ip
[1];
6435 THROW_EX_GENERAL (*(MonoException
**)(frame_locals (frame
) + exvar_offset
), ip
, TRUE
);
6438 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6440 * need to clarify what this should actually do:
6442 * Takes an exception from the stack and rethrows it.
6443 * This is useful for wrappers that don't want to have to
6444 * use CEE_THROW and lose the exception stacktrace.
6449 sp
->data
.p
= mono_get_exception_null_reference ();
6451 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6454 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6458 del
= (MonoDelegate
*)sp
->data
.p
;
6459 if (!del
->interp_method
) {
6460 /* Not created from interpreted code */
6461 MONO_API_ERROR_INIT (error
);
6462 g_assert (del
->method
);
6463 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6464 mono_error_assert_ok (error
);
6466 g_assert (del
->interp_method
);
6467 sp
->data
.p
= del
->interp_method
;
6472 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6475 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6476 if (!del
->interp_invoke_impl
) {
6478 * First time we are called. Set up the invoke wrapper. We might be able to do this
6479 * in ctor but we would need to handle AllocDelegateLike_internal separately
6481 MONO_API_ERROR_INIT (error
);
6482 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6483 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6484 mono_error_assert_ok (error
);
6487 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6492 #define MATH_UNOP(mathfunc) \
6493 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6496 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
6497 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
6498 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
6499 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
6500 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
6501 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
6502 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
6503 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
6504 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
6505 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
6506 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
6507 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
6508 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
6509 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
6510 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
6512 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
6513 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6514 mono_interp_enum_hasflag (sp
, klass
);
6519 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
6520 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
6524 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
6525 NULL_CHECK (sp
[-1].data
.p
);
6526 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
6532 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname (*ip
), ip
- frame
->imethod
->code
);
6536 g_assert_not_reached ();
6539 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6541 THROW_EX (mono_get_exception_null_reference (), ip
);
6543 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
6545 THROW_EX (mono_get_exception_overflow (), ip
);
6547 THROW_EX (mono_error_convert_to_exception (error
), ip
);
6549 THROW_EX (mono_get_exception_invalid_cast (), ip
);
6551 g_assert (context
->has_resume_state
);
6553 if (frame
== context
->handler_frame
&& (!clause_args
|| context
->handler_ip
< clause_args
->end_at_ip
)) {
6554 /* Set the current execution state to the resume state in context */
6556 ip
= context
->handler_ip
;
6557 /* spec says stack should be empty at endfinally so it should be at the start too */
6559 vt_sp
= (guchar
*)sp
+ frame
->imethod
->stack_size
;
6560 g_assert (context
->exc_gchandle
);
6561 sp
->data
.p
= mono_gchandle_get_target_internal (context
->exc_gchandle
);
6564 finally_ips
= clear_resume_state (context
, finally_ips
);
6565 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6566 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6571 error_init_reuse (error
);
6573 if (clause_args
&& clause_args
->base_frame
)
6574 memcpy (clause_args
->base_frame
->stack
, frame
->stack
, frame
->imethod
->alloca_size
);
6576 if (!context
->has_resume_state
&& MONO_PROFILER_ENABLED (method_leave
) &&
6577 frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
6578 MonoProfilerCallContext
*prof_ctx
= NULL
;
6580 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
6581 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6582 prof_ctx
->interp_frame
= frame
;
6583 prof_ctx
->method
= frame
->imethod
->method
;
6585 MonoType
*rtype
= mono_method_signature_internal (frame
->imethod
->method
)->ret
;
6587 switch (rtype
->type
) {
6588 case MONO_TYPE_VOID
:
6590 case MONO_TYPE_VALUETYPE
:
6591 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6594 prof_ctx
->return_value
= frame
->retval
;
6599 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
6602 } else if (context
->has_resume_state
&& frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
6603 MONO_PROFILER_RAISE (method_exception_leave
, (frame
->imethod
->method
, mono_gchandle_get_target_internal (context
->exc_gchandle
)));
6609 interp_parse_options (const char *options
)
6616 args
= g_strsplit (options
, ",", -1);
6617 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
6620 if (strncmp (arg
, "jit=", 4) == 0)
6621 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
6622 if (strncmp (arg
, "interp-only=", strlen ("interp-only=")) == 0)
6623 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
6624 if (strncmp (arg
, "-inline", 7) == 0)
6625 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6626 if (strncmp (arg
, "-cprop", 6) == 0)
6627 mono_interp_opt
&= ~INTERP_OPT_CPROP
;
6632 * interp_set_resume_state:
6634 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6637 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
6639 ThreadContext
*context
;
6642 context
= (ThreadContext
*)jit_tls
->interp_context
;
6645 context
->has_resume_state
= TRUE
;
6646 context
->handler_frame
= (InterpFrame
*)interp_frame
;
6647 context
->handler_ei
= ei
;
6648 if (context
->exc_gchandle
)
6649 mono_gchandle_free_internal (context
->exc_gchandle
);
6650 context
->exc_gchandle
= mono_gchandle_new_internal ((MonoObject
*)ex
, FALSE
);
6653 *(MonoException
**)(frame_locals (context
->handler_frame
) + ei
->exvar_offset
) = ex
;
6654 context
->handler_ip
= (const guint16
*)handler_ip
;
6658 interp_get_resume_state (const MonoJitTlsData
*jit_tls
, gboolean
*has_resume_state
, MonoInterpFrameHandle
*interp_frame
, gpointer
*handler_ip
)
6661 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
6663 *has_resume_state
= context
->has_resume_state
;
6664 if (context
->has_resume_state
) {
6665 *interp_frame
= context
->handler_frame
;
6666 *handler_ip
= (gpointer
)context
->handler_ip
;
6671 * interp_run_finally:
6673 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6674 * frame->interp_frame.
6675 * Return TRUE if the finally clause threw an exception.
6678 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6680 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6681 ThreadContext
*context
= get_context ();
6682 const unsigned short *old_ip
= iframe
->ip
;
6683 FrameClauseArgs clause_args
;
6685 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6686 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
6687 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
6688 clause_args
.exit_clause
= clause_index
;
6691 interp_exec_method_full (iframe
, context
, &clause_args
, error
);
6692 if (context
->has_resume_state
) {
6695 iframe
->ip
= old_ip
;
6701 * interp_run_filter:
6703 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6704 * frame->interp_frame.
6707 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6709 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6710 ThreadContext
*context
= get_context ();
6711 InterpFrame child_frame
;
6713 FrameClauseArgs clause_args
;
6716 * Have to run the clause in a new frame which is a copy of IFRAME, since
6717 * during debugging, there are two copies of the frame on the stack.
6719 memset (&child_frame
, 0, sizeof (InterpFrame
));
6720 child_frame
.imethod
= iframe
->imethod
;
6721 child_frame
.retval
= &retval
;
6722 child_frame
.parent
= iframe
;
6723 child_frame
.stack_args
= iframe
->stack_args
;
6725 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6726 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
6727 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
6728 clause_args
.filter_exception
= ex
;
6729 clause_args
.base_frame
= iframe
;
6732 interp_exec_method_full (&child_frame
, context
, &clause_args
, error
);
6733 /* ENDFILTER stores the result into child_frame->retval */
6734 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
6738 InterpFrame
*current
;
6742 * interp_frame_iter_init:
6744 * Initialize an iterator for iterating through interpreted frames.
6747 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
6749 StackIter
*stack_iter
= (StackIter
*)iter
;
6751 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
6755 * interp_frame_iter_next:
6757 * Fill out FRAME with date for the next interpreter frame.
6760 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
6762 StackIter
*stack_iter
= (StackIter
*)iter
;
6763 InterpFrame
*iframe
= stack_iter
->current
;
6765 memset (frame
, 0, sizeof (StackFrameInfo
));
6766 /* pinvoke frames doesn't have imethod set */
6767 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
6768 iframe
= iframe
->parent
;
6772 MonoMethod
*method
= iframe
->imethod
->method
;
6773 frame
->domain
= iframe
->imethod
->domain
;
6774 frame
->interp_frame
= iframe
;
6775 frame
->method
= method
;
6776 frame
->actual_method
= method
;
6777 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
6778 frame
->native_offset
= -1;
6779 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
6781 frame
->type
= FRAME_TYPE_INTERP
;
6782 /* This is the offset in the interpreter IR */
6783 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
6784 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6785 frame
->managed
= TRUE
;
6787 frame
->ji
= iframe
->imethod
->jinfo
;
6788 frame
->frame_addr
= iframe
;
6790 stack_iter
->current
= iframe
->parent
;
6796 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
6798 InterpMethod
* imethod
;
6800 imethod
= lookup_imethod (domain
, method
);
6802 return imethod
->jinfo
;
6808 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6810 guint16
*code
= (guint16
*)ip
;
6811 g_assert (*code
== MINT_SDB_SEQ_POINT
);
6812 *code
= MINT_SDB_BREAKPOINT
;
6816 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6818 guint16
*code
= (guint16
*)ip
;
6819 g_assert (*code
== MINT_SDB_BREAKPOINT
);
6820 *code
= MINT_SDB_SEQ_POINT
;
6824 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
6826 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6828 g_assert (iframe
->imethod
);
6829 return iframe
->imethod
->jinfo
;
6833 interp_frame_get_ip (MonoInterpFrameHandle frame
)
6835 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6837 g_assert (iframe
->imethod
);
6838 return (gpointer
)iframe
->ip
;
6842 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
6844 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6845 MonoMethodSignature
*sig
;
6847 g_assert (iframe
->imethod
);
6849 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6850 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
6854 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
6856 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6858 g_assert (iframe
->imethod
);
6860 return frame_locals (iframe
) + iframe
->imethod
->local_offsets
[pos
];
6864 interp_frame_get_this (MonoInterpFrameHandle frame
)
6866 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6868 g_assert (iframe
->imethod
);
6869 g_assert (iframe
->imethod
->hasthis
);
6870 return &iframe
->stack_args
[0].data
.p
;
6873 static MonoInterpFrameHandle
6874 interp_frame_get_parent (MonoInterpFrameHandle frame
)
6876 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6878 return iframe
->parent
;
6882 interp_frame_get_res (MonoInterpFrameHandle frame
)
6884 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6885 MonoMethodSignature
*sig
;
6887 g_assert (iframe
->imethod
);
6888 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6889 if (sig
->ret
->type
== MONO_TYPE_VOID
)
6892 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
6896 interp_start_single_stepping (void)
6902 interp_stop_single_stepping (void)
6910 opcode_count_comparer (const void * pa
, const void * pb
)
6912 long counta
= opcode_counts
[*(int*)pa
];
6913 long countb
= opcode_counts
[*(int*)pb
];
6915 if (counta
< countb
)
6917 else if (counta
> countb
)
6924 interp_print_op_count (void)
6926 int ordered_ops
[MINT_LASTOP
];
6930 for (i
= 0; i
< MINT_LASTOP
; i
++) {
6931 ordered_ops
[i
] = i
;
6932 total_ops
+= opcode_counts
[i
];
6934 qsort (ordered_ops
, MINT_LASTOP
, sizeof (int), opcode_count_comparer
);
6936 for (i
= 0; i
< MINT_LASTOP
; i
++) {
6937 long count
= opcode_counts
[ordered_ops
[i
]];
6938 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops
[i
]), count
, (double)count
/ total_ops
* 100);
6944 interp_cleanup (void)
6947 interp_print_op_count ();
6952 register_interp_stats (void)
6954 mono_counters_init ();
6955 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
6956 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.cprop_time
);
6957 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.stloc_nps
);
6958 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.movlocs
);
6959 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.copy_propagations
);
6960 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.killed_instructions
);
6961 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
6962 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
6965 #undef MONO_EE_CALLBACK
6966 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6968 static const MonoEECallbacks mono_interp_callbacks
= {
6973 mono_ee_interp_init (const char *opts
)
6975 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
6976 g_assert (!interp_init_done
);
6977 interp_init_done
= TRUE
;
6979 mono_native_tls_alloc (&thread_context_id
, NULL
);
6982 interp_parse_options (opts
);
6983 /* Don't do any optimizations if running under debugger */
6984 if (mini_get_debug_options ()->mdb_optimizations
)
6985 mono_interp_opt
= 0;
6986 mono_interp_transform_init ();
6988 mini_install_interp_callbacks (&mono_interp_callbacks
);
6990 register_interp_stats ();