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 MONO_NEVER_INLINE MonoException
*
1007 ves_array_set (InterpFrame
*frame
, stackval
*sp
, MonoMethodSignature
*sig
)
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, TRUE
);
1017 return mono_get_exception_index_out_of_range ();
1019 int val_index
= 1 + m_class_get_rank (ac
);
1020 if (sp
[val_index
].data
.p
&& !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o
)))) {
1022 MonoObject
*isinst
= mono_object_isinst_checked (sp
[val_index
].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
1023 mono_error_cleanup (error
);
1025 return mono_get_exception_array_type_mismatch ();
1028 gint32 esize
= mono_array_element_size (ac
);
1029 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1031 MonoType
*mt
= sig
->params
[m_class_get_rank (ac
)];
1032 stackval_to_data (mt
, &sp
[val_index
], ea
, FALSE
);
1036 static MonoException
*
1037 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1039 MonoObject
*o
= sp
->data
.o
;
1040 MonoArray
*ao
= (MonoArray
*) o
;
1041 MonoClass
*ac
= o
->vtable
->klass
;
1043 g_assert (m_class_get_rank (ac
) >= 1);
1045 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, safe
);
1047 return mono_get_exception_index_out_of_range ();
1049 gint32 esize
= mono_array_element_size (ac
);
1050 gconstpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1052 MonoType
*mt
= sig
->ret
;
1053 stackval_from_data (mt
, retval
, ea
, FALSE
);
1057 static MONO_NEVER_INLINE MonoException
*
1058 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1060 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1062 g_assert (m_class_get_rank (ac
) >= 1);
1064 gint32 pos
= ves_array_calculate_index (ao
, sp
, TRUE
);
1066 return mono_get_exception_index_out_of_range ();
1068 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
))
1069 return mono_get_exception_array_type_mismatch ();
1070 gint32 esize
= mono_array_element_size (ac
);
1071 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1075 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1076 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1079 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1080 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1082 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1085 g_assert (mono_arm_eabi_supported ());
1086 int i8_align
= mono_arm_i8_align ();
1096 for (int i
= 0; i
< sig
->param_count
; i
++) {
1097 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1099 case MONO_TYPE_BOOLEAN
:
1100 case MONO_TYPE_CHAR
:
1110 case MONO_TYPE_SZARRAY
:
1111 case MONO_TYPE_CLASS
:
1112 case MONO_TYPE_OBJECT
:
1113 case MONO_TYPE_STRING
:
1114 case MONO_TYPE_VALUETYPE
:
1115 case MONO_TYPE_GENERICINST
:
1116 #if SIZEOF_VOID_P == 8
1122 #if SIZEOF_VOID_P == 4
1126 /* pairs begin at even registers */
1127 if (i8_align
== 8 && margs
->ilen
& 1)
1134 #if SIZEOF_VOID_P == 8
1139 #if SIZEOF_VOID_P == 4
1145 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1149 if (margs
->ilen
> 0)
1150 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1152 if (margs
->flen
> 0)
1153 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1155 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1156 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1158 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1159 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1166 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1170 for (int i
= 0; i
< sig
->param_count
; i
++) {
1171 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1173 case MONO_TYPE_BOOLEAN
:
1174 case MONO_TYPE_CHAR
:
1184 case MONO_TYPE_SZARRAY
:
1185 case MONO_TYPE_CLASS
:
1186 case MONO_TYPE_OBJECT
:
1187 case MONO_TYPE_STRING
:
1188 case MONO_TYPE_VALUETYPE
:
1189 case MONO_TYPE_GENERICINST
:
1190 #if SIZEOF_VOID_P == 8
1194 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1196 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1200 #if SIZEOF_VOID_P == 4
1202 case MONO_TYPE_U8
: {
1203 stackval
*sarg
= &frame
->stack_args
[i
];
1205 /* pairs begin at even registers */
1206 if (i8_align
== 8 && int_i
& 1)
1209 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1211 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1213 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
);
1221 if (ptype
== MONO_TYPE_R4
)
1222 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1224 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1226 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
);
1228 #if SIZEOF_VOID_P == 4
1235 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1239 switch (sig
->ret
->type
) {
1240 case MONO_TYPE_BOOLEAN
:
1241 case MONO_TYPE_CHAR
:
1251 case MONO_TYPE_SZARRAY
:
1252 case MONO_TYPE_CLASS
:
1253 case MONO_TYPE_OBJECT
:
1254 case MONO_TYPE_STRING
:
1257 case MONO_TYPE_VALUETYPE
:
1258 case MONO_TYPE_GENERICINST
:
1259 margs
->retval
= &(frame
->retval
->data
.p
);
1260 margs
->is_float_ret
= 0;
1264 margs
->retval
= &(frame
->retval
->data
.p
);
1265 margs
->is_float_ret
= 1;
1267 case MONO_TYPE_VOID
:
1268 margs
->retval
= NULL
;
1271 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1279 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1281 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1284 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1286 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1290 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gconstpointer data
)
1292 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1295 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1296 else if (sig
->hasthis
&& index
== 0)
1297 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1299 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1303 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1305 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1308 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1310 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1314 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1316 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1317 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1318 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1320 switch (type
->type
) {
1321 case MONO_TYPE_GENERICINST
:
1322 if (!MONO_TYPE_IS_REFERENCE (type
))
1323 val
->data
.vt
= storage
;
1325 case MONO_TYPE_VALUETYPE
:
1326 val
->data
.vt
= storage
;
1329 g_assert_not_reached ();
1334 get_interp_to_native_trampoline (void)
1336 static MonoPIFunc trampoline
= NULL
;
1339 if (mono_ee_features
.use_aot_trampolines
) {
1340 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1342 MonoTrampInfo
*info
;
1343 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1344 mono_tramp_info_register (info
, NULL
);
1346 mono_memory_barrier ();
1352 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1354 get_interp_to_native_trampoline () (addr
, ccontext
);
1357 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1359 #pragma optimize ("", off)
1361 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1362 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, ThreadContext
*context
, gboolean save_last_error
)
1367 g_assert (!frame
->imethod
);
1369 static MonoPIFunc entry_func
= NULL
;
1371 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1373 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
);
1374 mono_error_assert_ok (error
);
1376 entry_func
= get_interp_to_native_trampoline ();
1378 mono_memory_barrier ();
1381 #ifdef ENABLE_NETCORE
1382 if (save_last_error
) {
1383 mono_marshal_clear_last_error ();
1387 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1388 CallContext ccontext
;
1389 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1392 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1396 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_pinvoke
);
1397 entry_func ((gpointer
) addr
, args
);
1398 if (save_last_error
)
1399 mono_marshal_set_last_error ();
1400 interp_pop_lmf (&ext
);
1402 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1403 if (!context
->has_resume_state
)
1404 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1406 if (ccontext
.stack
!= NULL
)
1407 g_free (ccontext
.stack
);
1409 if (!context
->has_resume_state
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1410 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1412 g_free (margs
->iargs
);
1413 g_free (margs
->fargs
);
1416 goto exit_pinvoke
; // prevent unused label warning in some configurations
1421 #pragma optimize ("", on)
1425 * interp_init_delegate:
1427 * Initialize del->interp_method.
1430 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1434 if (del
->interp_method
) {
1435 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1436 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1437 } else if (del
->method
) {
1438 /* Delegate created dynamically */
1439 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1441 /* Created from JITted code */
1442 g_assert_not_reached ();
1445 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1448 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1449 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1450 mono_class_is_abstract (method
->klass
))
1451 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1453 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1454 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1455 const char *name
= method
->name
;
1456 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1458 * When invoking the delegate interp_method is executed directly. If it's an
1459 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1461 * FIXME We should do this later, when we also know the delegate on which the
1462 * target method is called.
1464 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1465 mono_error_assert_ok (error
);
1469 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1470 /* Return any errors from method compilation */
1471 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1472 return_if_nok (error
);
1477 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1480 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1482 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1484 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1485 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1486 /* virtual invoke delegates must not have null check */
1487 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1488 && MONO_HANDLE_IS_NULL (target
)) {
1489 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1494 g_assert (imethod
->method
);
1495 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1496 return_if_nok (error
);
1498 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1500 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1505 * runtime specifies that the implementation of the method is automatically
1506 * provided by the runtime and is primarily used for the methods of delegates.
1508 static MONO_NEVER_INLINE MonoException
*
1509 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1511 const char *name
= method
->name
;
1512 mono_class_init_internal (method
->klass
);
1514 if (method
->klass
== mono_defaults
.array_class
) {
1515 if (!strcmp (name
, "UnsafeMov")) {
1516 /* TODO: layout checks */
1517 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1520 if (!strcmp (name
, "UnsafeLoad"))
1521 return ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1522 } else if (mini_class_is_system_array (method
->klass
)) {
1523 MonoObject
*obj
= (MonoObject
*) sp
->data
.p
;
1525 return mono_get_exception_null_reference ();
1526 if (*name
== 'S' && (strcmp (name
, "Set") == 0))
1527 return ves_array_set (frame
, sp
, sig
);
1528 if (*name
== 'G' && (strcmp (name
, "Get") == 0))
1529 return ves_array_get (frame
, sp
, retval
, sig
, TRUE
);
1532 g_error ("Don't know how to exec runtime method %s.%s::%s",
1533 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1539 dump_stack (stackval
*stack
, stackval
*sp
)
1541 stackval
*s
= stack
;
1542 GString
*str
= g_string_new ("");
1545 return g_string_free (str
, FALSE
);
1548 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1551 return g_string_free (str
, FALSE
);
1555 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1557 switch (type
->type
) {
1564 case MONO_TYPE_CHAR
:
1565 case MONO_TYPE_BOOLEAN
:
1566 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1568 case MONO_TYPE_STRING
:
1569 case MONO_TYPE_SZARRAY
:
1570 case MONO_TYPE_CLASS
:
1571 case MONO_TYPE_OBJECT
:
1572 case MONO_TYPE_ARRAY
:
1576 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1578 case MONO_TYPE_VALUETYPE
:
1579 if (m_class_is_enumtype (type
->data
.klass
))
1580 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1582 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1585 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1588 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1593 GString
*res
= g_string_new ("");
1594 mono_type_get_desc (res
, type
, TRUE
);
1595 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1596 g_string_free (res
, TRUE
);
1603 dump_retval (InterpFrame
*inv
)
1605 GString
*str
= g_string_new ("");
1606 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1608 if (ret
->type
!= MONO_TYPE_VOID
)
1609 dump_stackval (str
, inv
->retval
, ret
);
1611 return g_string_free (str
, FALSE
);
1615 dump_args (InterpFrame
*inv
)
1617 GString
*str
= g_string_new ("");
1619 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1621 if (signature
->param_count
== 0 && !signature
->hasthis
)
1622 return g_string_free (str
, FALSE
);
1624 if (signature
->hasthis
) {
1625 MonoMethod
*method
= inv
->imethod
->method
;
1626 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1629 for (i
= 0; i
< signature
->param_count
; ++i
)
1630 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1632 return g_string_free (str
, FALSE
);
1636 #define CHECK_ADD_OVERFLOW(a,b) \
1637 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1638 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1640 #define CHECK_SUB_OVERFLOW(a,b) \
1641 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1642 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1644 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1645 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1647 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1648 (guint32)(a) < (guint32)(b) ? -1 : 0
1650 #define CHECK_ADD_OVERFLOW64(a,b) \
1651 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1652 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1654 #define CHECK_SUB_OVERFLOW64(a,b) \
1655 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1656 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1658 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1659 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1661 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1662 (guint64)(a) < (guint64)(b) ? -1 : 0
1664 #if SIZEOF_VOID_P == 4
1665 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1666 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1668 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1669 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1672 /* Resolves to TRUE if the operands would overflow */
1673 #define CHECK_MUL_OVERFLOW(a,b) \
1674 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1675 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1676 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1677 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1678 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1679 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1680 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1682 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1683 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1684 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1686 #define CHECK_MUL_OVERFLOW64(a,b) \
1687 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1688 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1689 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1690 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1691 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1692 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1693 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1695 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1696 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1697 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1699 #if SIZEOF_VOID_P == 4
1700 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1701 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1703 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1704 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1708 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1711 ThreadContext
*context
= get_context ();
1712 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1713 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1715 MonoMethod
*target_method
= method
;
1721 MonoDomain
*domain
= mono_domain_get ();
1723 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1724 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1725 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1727 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1729 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1733 args
[0].data
.p
= obj
;
1735 args
[0].data
.p
= NULL
;
1736 args
[1].data
.p
= params
;
1737 args
[2].data
.p
= exc
;
1738 args
[3].data
.p
= target_method
;
1740 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1741 mono_error_assert_ok (error
);
1742 init_frame (&frame
, NULL
, imethod
, args
, &result
);
1744 interp_exec_method (&frame
, context
, error
);
1746 if (context
->has_resume_state
) {
1747 // This can happen on wasm !?
1748 MonoException
*thrown_exc
= (MonoException
*) mono_gchandle_get_target_internal (context
->exc_gchandle
);
1750 *exc
= (MonoObject
*)thrown_exc
;
1752 mono_error_set_exception_instance (error
, thrown_exc
);
1755 return (MonoObject
*)result
.data
.p
;
1759 InterpMethod
*rmethod
;
1763 gpointer
*many_args
;
1766 /* Main function for entering the interpreter from compiled code */
1768 interp_entry (InterpEntryData
*data
)
1771 InterpMethod
*rmethod
;
1772 ThreadContext
*context
;
1776 MonoMethodSignature
*sig
;
1778 gpointer orig_domain
= NULL
, attach_cookie
;
1781 if ((gsize
)data
->rmethod
& 1) {
1783 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1784 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1786 rmethod
= data
->rmethod
;
1788 if (rmethod
->needs_thread_attach
)
1789 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1791 context
= get_context ();
1793 method
= rmethod
->method
;
1794 sig
= mono_method_signature_internal (method
);
1796 // FIXME: Optimize this
1798 //printf ("%s\n", mono_method_full_name (method, 1));
1800 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1802 args
[0].data
.p
= data
->this_arg
;
1805 if (data
->many_args
)
1806 params
= data
->many_args
;
1808 params
= data
->args
;
1809 for (i
= 0; i
< sig
->param_count
; ++i
) {
1810 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1811 if (sig
->params
[i
]->byref
) {
1812 args
[a_index
].data
.p
= params
[i
];
1815 type
= rmethod
->param_types
[i
];
1816 switch (type
->type
) {
1817 case MONO_TYPE_VALUETYPE
:
1818 args
[a_index
].data
.p
= params
[i
];
1820 case MONO_TYPE_GENERICINST
:
1821 if (MONO_TYPE_IS_REFERENCE (type
))
1822 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1824 args
[a_index
].data
.vt
= params
[i
];
1827 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1832 memset (&result
, 0, sizeof (result
));
1833 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1835 type
= rmethod
->rtype
;
1836 switch (type
->type
) {
1837 case MONO_TYPE_GENERICINST
:
1838 if (!MONO_TYPE_IS_REFERENCE (type
))
1839 frame
.retval
->data
.vt
= data
->res
;
1841 case MONO_TYPE_VALUETYPE
:
1842 frame
.retval
->data
.vt
= data
->res
;
1849 interp_exec_method (&frame
, context
, error
);
1851 g_assert (!context
->has_resume_state
);
1853 if (rmethod
->needs_thread_attach
)
1854 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
1856 if (mono_llvm_only
) {
1857 if (context
->has_resume_state
)
1858 mono_llvm_reraise_exception ((MonoException
*)mono_gchandle_get_target_internal (context
->exc_gchandle
));
1860 g_assert (!context
->has_resume_state
);
1863 type
= rmethod
->rtype
;
1864 switch (type
->type
) {
1865 case MONO_TYPE_VOID
:
1867 case MONO_TYPE_OBJECT
:
1868 /* No need for a write barrier */
1869 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1871 case MONO_TYPE_GENERICINST
:
1872 if (MONO_TYPE_IS_REFERENCE (type
)) {
1873 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1875 /* Already set before the call */
1878 case MONO_TYPE_VALUETYPE
:
1879 /* Already set before the call */
1882 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1888 do_icall (MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
1890 #ifdef ENABLE_NETCORE
1891 if (save_last_error
)
1892 mono_marshal_clear_last_error ();
1896 case MINT_ICALL_V_V
: {
1897 typedef void (*T
)(void);
1902 case MINT_ICALL_V_P
: {
1903 typedef gpointer (*T
)(void);
1906 sp
[-1].data
.p
= func ();
1909 case MINT_ICALL_P_V
: {
1910 typedef void (*T
)(gpointer
);
1912 func (sp
[-1].data
.p
);
1916 case MINT_ICALL_P_P
: {
1917 typedef gpointer (*T
)(gpointer
);
1919 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1922 case MINT_ICALL_PP_V
: {
1923 typedef void (*T
)(gpointer
,gpointer
);
1926 func (sp
[0].data
.p
, sp
[1].data
.p
);
1929 case MINT_ICALL_PP_P
: {
1930 typedef gpointer (*T
)(gpointer
,gpointer
);
1933 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1936 case MINT_ICALL_PPP_V
: {
1937 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
1940 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1943 case MINT_ICALL_PPP_P
: {
1944 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
1947 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
1950 case MINT_ICALL_PPPP_V
: {
1951 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1954 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1957 case MINT_ICALL_PPPP_P
: {
1958 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1961 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1964 case MINT_ICALL_PPPPP_V
: {
1965 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1968 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
1971 case MINT_ICALL_PPPPP_P
: {
1972 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1975 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
);
1978 case MINT_ICALL_PPPPPP_V
: {
1979 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1982 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
);
1985 case MINT_ICALL_PPPPPP_P
: {
1986 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1989 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
);
1993 g_assert_not_reached ();
1996 if (save_last_error
)
1997 mono_marshal_set_last_error ();
1999 /* convert the native representation to the stackval representation */
2001 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2006 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2008 #pragma optimize ("", off)
2010 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
2011 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2014 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
2016 sp
= do_icall (sig
, op
, sp
, ptr
, save_last_error
);
2018 interp_pop_lmf (&ext
);
2020 goto exit_icall
; // prevent unused label warning in some configurations
2025 #pragma optimize ("", on)
2030 gpointer jit_wrapper
;
2032 MonoFtnDesc
*ftndesc
;
2036 jit_call_cb (gpointer arg
)
2038 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2039 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2040 int pindex
= cb_data
->pindex
;
2041 gpointer
*args
= cb_data
->args
;
2042 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2046 typedef void (*T
)(gpointer
);
2047 T func
= (T
)jit_wrapper
;
2053 typedef void (*T
)(gpointer
, gpointer
);
2054 T func
= (T
)jit_wrapper
;
2056 func (args
[0], &ftndesc
);
2060 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2061 T func
= (T
)jit_wrapper
;
2063 func (args
[0], args
[1], &ftndesc
);
2067 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2068 T func
= (T
)jit_wrapper
;
2070 func (args
[0], args
[1], args
[2], &ftndesc
);
2074 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2075 T func
= (T
)jit_wrapper
;
2077 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2081 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2082 T func
= (T
)jit_wrapper
;
2084 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2088 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2089 T func
= (T
)jit_wrapper
;
2091 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2095 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2096 T func
= (T
)jit_wrapper
;
2098 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2102 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2103 T func
= (T
)jit_wrapper
;
2105 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2109 g_assert_not_reached ();
2114 static MONO_NEVER_INLINE stackval
*
2115 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2117 MonoMethodSignature
*sig
;
2118 MonoFtnDesc ftndesc
;
2119 guint8 res_buf
[256];
2123 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2126 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2127 * by ref and return a return value using an explicit return value argument.
2129 if (!rmethod
->jit_wrapper
) {
2130 MonoMethod
*method
= rmethod
->method
;
2132 sig
= mono_method_signature_internal (method
);
2135 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2136 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2138 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2139 mono_error_assert_ok (error
);
2141 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2142 return_val_if_nok (error
, NULL
);
2145 rmethod
->jit_addr
= addr
;
2146 rmethod
->jit_sig
= sig
;
2147 mono_memory_barrier ();
2148 rmethod
->jit_wrapper
= jit_wrapper
;
2151 sig
= rmethod
->jit_sig
;
2154 sp
-= sig
->param_count
;
2158 ftndesc
.addr
= rmethod
->jit_addr
;
2161 // FIXME: Optimize this
2165 int stack_index
= 0;
2166 if (rmethod
->hasthis
) {
2167 args
[pindex
++] = sp
[0].data
.p
;
2170 type
= rmethod
->rtype
;
2171 if (type
->type
!= MONO_TYPE_VOID
) {
2172 if (MONO_TYPE_ISSTRUCT (type
))
2173 args
[pindex
++] = vt_sp
;
2175 args
[pindex
++] = res_buf
;
2177 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2178 MonoType
*t
= rmethod
->param_types
[i
];
2179 stackval
*sval
= &sp
[stack_index
+ i
];
2180 if (sig
->params
[i
]->byref
) {
2181 args
[pindex
++] = sval
->data
.p
;
2182 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2183 args
[pindex
++] = sval
->data
.p
;
2184 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2185 args
[pindex
++] = &sval
->data
.p
;
2194 case MONO_TYPE_VALUETYPE
:
2195 args
[pindex
++] = &sval
->data
.i
;
2198 case MONO_TYPE_FNPTR
:
2201 case MONO_TYPE_OBJECT
:
2202 args
[pindex
++] = &sval
->data
.p
;
2206 args
[pindex
++] = &sval
->data
.l
;
2209 args
[pindex
++] = &sval
->data
.f_r4
;
2212 args
[pindex
++] = &sval
->data
.f
;
2215 printf ("%s\n", mono_type_full_name (t
));
2216 g_assert_not_reached ();
2221 interp_push_lmf (&ext
, frame
);
2223 JitCallCbData cb_data
;
2224 memset (&cb_data
, 0, sizeof (cb_data
));
2225 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2226 cb_data
.pindex
= pindex
;
2227 cb_data
.args
= args
;
2228 cb_data
.ftndesc
= &ftndesc
;
2230 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2231 /* Catch the exception thrown by the native code using a try-catch */
2232 gboolean thrown
= FALSE
;
2233 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2234 interp_pop_lmf (&ext
);
2236 MonoObject
*obj
= mono_llvm_load_exception ();
2238 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2242 jit_call_cb (&cb_data
);
2243 interp_pop_lmf (&ext
);
2246 MonoType
*rtype
= rmethod
->rtype
;
2247 switch (rtype
->type
) {
2248 case MONO_TYPE_VOID
:
2249 case MONO_TYPE_OBJECT
:
2250 case MONO_TYPE_STRING
:
2251 case MONO_TYPE_CLASS
:
2252 case MONO_TYPE_ARRAY
:
2253 case MONO_TYPE_SZARRAY
:
2257 sp
->data
.p
= *(gpointer
*)res_buf
;
2260 sp
->data
.i
= *(gint8
*)res_buf
;
2263 sp
->data
.i
= *(guint8
*)res_buf
;
2266 sp
->data
.i
= *(gint16
*)res_buf
;
2269 sp
->data
.i
= *(guint16
*)res_buf
;
2272 sp
->data
.i
= *(gint32
*)res_buf
;
2275 sp
->data
.i
= *(guint32
*)res_buf
;
2278 sp
->data
.l
= *(gint64
*)res_buf
;
2281 sp
->data
.l
= *(guint64
*)res_buf
;
2284 sp
->data
.f_r4
= *(float*)res_buf
;
2287 sp
->data
.f
= *(double*)res_buf
;
2289 case MONO_TYPE_TYPEDBYREF
:
2290 case MONO_TYPE_VALUETYPE
:
2291 /* The result was written to vt_sp */
2294 case MONO_TYPE_GENERICINST
:
2295 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2296 sp
->data
.p
= *(gpointer
*)res_buf
;
2298 /* The result was written to vt_sp */
2303 g_print ("%s\n", mono_type_full_name (rtype
));
2304 g_assert_not_reached ();
2311 static MONO_NEVER_INLINE
void
2312 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2315 interp_push_lmf (&ext
, frame
);
2317 interp_pop_lmf (&ext
);
2320 static MONO_NEVER_INLINE MonoException
*
2321 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2324 /* Don't push lmf if we have no interp data */
2325 gboolean push_lmf
= frame
->parent
!= NULL
;
2328 /* Use the parent frame as the current frame is not complete yet */
2330 interp_push_lmf (&ext
, frame
->parent
);
2332 mono_interp_transform_method (frame
->imethod
, context
, error
);
2335 interp_pop_lmf (&ext
);
2337 return mono_error_convert_to_exception (error
);
2340 static MONO_NEVER_INLINE guchar
*
2341 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, guchar
*vt_sp_start
)
2343 stackval
*first_arg
= sp
- csig
->param_count
;
2344 guchar
*vt_sp
= vt_sp_start
;
2347 * We need to have the varargs linearly on the stack so the ArgIterator
2348 * can iterate over them. We pass the signature first and then copy them
2349 * one by one on the vtstack. At the end we pass the original vt_stack
2350 * so the callee (MINT_ARGLIST) can find the varargs space.
2352 *(gpointer
*)vt_sp
= csig
;
2353 vt_sp
+= sizeof (gpointer
);
2355 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2356 int align
, arg_size
;
2357 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2358 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, align
);
2360 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt_sp
, FALSE
);
2364 vt_sp
+= sizeof (gpointer
);
2365 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, MINT_VT_ALIGNMENT
);
2367 ((gpointer
*)vt_sp
) [-1] = vt_sp_start
;
2373 * These functions are the entry points into the interpreter from compiled code.
2374 * They are called by the interp_in wrappers. They have the following signature:
2375 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2376 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2377 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2378 * more wrappers then these functions.
2379 * this/static * ret/void * 16 arguments -> 64 functions.
2382 #define MAX_INTERP_ENTRY_ARGS 8
2384 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2385 InterpEntryData data; \
2386 (data).rmethod = (_method); \
2387 (data).res = (_res); \
2388 (data).this_arg = (_this_arg); \
2389 (data).many_args = NULL;
2391 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2392 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2393 interp_entry (&data); \
2395 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2396 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2397 (data).args [0] = arg1; \
2398 interp_entry (&data); \
2400 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2401 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2402 (data).args [0] = arg1; \
2403 (data).args [1] = arg2; \
2404 interp_entry (&data); \
2406 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2407 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2408 (data).args [0] = arg1; \
2409 (data).args [1] = arg2; \
2410 (data).args [2] = arg3; \
2411 interp_entry (&data); \
2413 #define INTERP_ENTRY4(_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 interp_entry (&data); \
2421 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2422 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2423 (data).args [0] = arg1; \
2424 (data).args [1] = arg2; \
2425 (data).args [2] = arg3; \
2426 (data).args [3] = arg4; \
2427 (data).args [4] = arg5; \
2428 interp_entry (&data); \
2430 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2431 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2432 (data).args [0] = arg1; \
2433 (data).args [1] = arg2; \
2434 (data).args [2] = arg3; \
2435 (data).args [3] = arg4; \
2436 (data).args [4] = arg5; \
2437 (data).args [5] = arg6; \
2438 interp_entry (&data); \
2440 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2441 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2442 (data).args [0] = arg1; \
2443 (data).args [1] = arg2; \
2444 (data).args [2] = arg3; \
2445 (data).args [3] = arg4; \
2446 (data).args [4] = arg5; \
2447 (data).args [5] = arg6; \
2448 (data).args [6] = arg7; \
2449 interp_entry (&data); \
2451 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2452 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2453 (data).args [0] = arg1; \
2454 (data).args [1] = arg2; \
2455 (data).args [2] = arg3; \
2456 (data).args [3] = arg4; \
2457 (data).args [4] = arg5; \
2458 (data).args [5] = arg6; \
2459 (data).args [6] = arg7; \
2460 (data).args [7] = arg8; \
2461 interp_entry (&data); \
2464 #define ARGLIST0 InterpMethod *rmethod
2465 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2466 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2467 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2468 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2469 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2470 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2471 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2472 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2474 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2475 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2476 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2477 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2478 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2479 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2480 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2481 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2482 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2483 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2484 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2485 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2486 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2487 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2488 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2489 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2490 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2491 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2492 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2493 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2494 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2495 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2496 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2497 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2498 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2499 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2500 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2501 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2502 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2503 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2504 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2505 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2506 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2507 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2508 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2509 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2511 #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
2513 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2514 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2515 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2516 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2518 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2520 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2522 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2523 data
.many_args
= args
;
2524 interp_entry (&data
);
2527 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2529 // inline so we can alloc on stack
2530 #define alloc_storage_for_stackval(s, t, p) do { \
2531 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2532 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2533 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2535 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2537 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2542 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2545 ThreadContext
*context
;
2549 MonoMethodSignature
*sig
;
2550 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2551 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2552 gpointer orig_domain
= NULL
, attach_cookie
;
2555 if (rmethod
->needs_thread_attach
)
2556 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2558 context
= get_context ();
2560 method
= rmethod
->method
;
2561 sig
= mono_method_signature_internal (method
);
2563 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2565 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2567 /* Allocate storage for value types */
2568 for (i
= 0; i
< sig
->param_count
; i
++) {
2569 MonoType
*type
= sig
->params
[i
];
2570 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2573 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2574 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2576 /* Copy the args saved in the trampoline to the frame stack */
2577 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2580 interp_exec_method (&frame
, context
, error
);
2582 g_assert (!context
->has_resume_state
);
2584 if (rmethod
->needs_thread_attach
)
2585 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2587 /* Write back the return value */
2588 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2594 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2596 g_assert_not_reached ();
2599 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2601 static InterpMethod
*
2602 lookup_method_pointer (gpointer addr
)
2604 MonoDomain
*domain
= mono_domain_get ();
2605 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2606 InterpMethod
*res
= NULL
;
2608 mono_domain_lock (domain
);
2609 if (info
->interp_method_pointer_hash
)
2610 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2611 mono_domain_unlock (domain
);
2616 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2618 interp_no_native_to_managed (void)
2620 g_error ("interpreter: native-to-managed transition not available on this platform");
2625 no_llvmonly_interp_method_pointer (void)
2627 g_assert_not_reached ();
2631 * interp_create_method_pointer_llvmonly:
2633 * Return an ftndesc for entering the interpreter and executing METHOD.
2636 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2638 MonoDomain
*domain
= mono_domain_get ();
2639 gpointer addr
, entry_func
, entry_wrapper
;
2640 MonoMethodSignature
*sig
;
2641 MonoMethod
*wrapper
;
2642 MonoJitDomainInfo
*info
;
2643 InterpMethod
*imethod
;
2645 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2646 return_val_if_nok (error
, NULL
);
2649 if (imethod
->llvmonly_unbox_entry
)
2650 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2652 if (imethod
->jit_entry
)
2653 return (MonoFtnDesc
*)imethod
->jit_entry
;
2656 sig
= mono_method_signature_internal (method
);
2659 * The entry functions need access to the method to call, so we have
2660 * to use a ftndesc. The caller uses a normal signature, while the
2661 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2662 * a gsharedvt_in_sig wrapper.
2664 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2666 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2667 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2668 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2669 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2671 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2672 g_assert_not_reached ();
2673 //entry_func = (gpointer)interp_entry_general;
2674 } else if (sig
->hasthis
) {
2675 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2676 entry_func
= entry_funcs_instance
[sig
->param_count
];
2678 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2680 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2681 entry_func
= entry_funcs_static
[sig
->param_count
];
2683 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2685 g_assert (entry_func
);
2687 /* Encode unbox in the lower bit of imethod */
2688 gpointer entry_arg
= imethod
;
2690 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2691 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2693 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2695 info
= domain_jit_info (domain
);
2696 mono_domain_lock (domain
);
2697 if (!info
->interp_method_pointer_hash
)
2698 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2699 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2700 mono_domain_unlock (domain
);
2702 mono_memory_barrier ();
2704 imethod
->llvmonly_unbox_entry
= addr
;
2706 imethod
->jit_entry
= addr
;
2708 return (MonoFtnDesc
*)addr
;
2712 * interp_create_method_pointer:
2714 * Return a function pointer which can be used to call METHOD using the
2715 * interpreter. Return NULL for methods which are not supported.
2718 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2720 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2722 return (gpointer
)no_llvmonly_interp_method_pointer
;
2723 return (gpointer
)interp_no_native_to_managed
;
2725 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2726 MonoDomain
*domain
= mono_domain_get ();
2727 MonoJitDomainInfo
*info
;
2728 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2731 return (gpointer
)no_llvmonly_interp_method_pointer
;
2733 if (imethod
->jit_entry
)
2734 return imethod
->jit_entry
;
2736 if (compile
&& !imethod
->transformed
) {
2737 /* Return any errors from method compilation */
2738 mono_interp_transform_method (imethod
, get_context (), error
);
2739 return_val_if_nok (error
, NULL
);
2742 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2745 /* The caller should call interp_create_method_pointer_llvmonly */
2746 g_assert_not_reached ();
2748 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2751 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2753 * Interp in wrappers get the argument in the rgctx register. If
2754 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2755 * on that arch the rgctx register is not scratch, so we use a
2756 * separate temp register. We should update the wrappers for this
2757 * if we really care about those architectures (arm).
2759 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2761 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2763 if (entry_wrapper
) {
2764 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2765 entry_func
= (gpointer
)interp_entry_general
;
2766 } else if (sig
->hasthis
) {
2767 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2768 entry_func
= entry_funcs_instance
[sig
->param_count
];
2770 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2772 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2773 entry_func
= entry_funcs_static
[sig
->param_count
];
2775 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2778 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2779 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2780 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2781 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2783 mono_error_cleanup (error
);
2784 error_init_reuse (error
);
2785 if (!mono_native_to_interp_trampoline
) {
2786 if (mono_aot_only
) {
2787 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2789 MonoTrampInfo
*info
;
2790 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2791 mono_tramp_info_register (info
, NULL
);
2794 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2795 /* We need the lmf wrapper only when being called from mixed mode */
2797 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2799 static gpointer cached_func
= NULL
;
2801 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
);
2802 mono_memory_barrier ();
2804 entry_func
= cached_func
;
2809 g_assert (entry_func
);
2810 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2811 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2812 ftndesc
->addr
= entry_func
;
2813 ftndesc
->arg
= imethod
;
2814 mono_error_assert_ok (error
);
2817 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2818 * rgctx register using a trampoline.
2821 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2823 info
= domain_jit_info (domain
);
2824 mono_domain_lock (domain
);
2825 if (!info
->interp_method_pointer_hash
)
2826 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2827 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2828 mono_domain_unlock (domain
);
2830 mono_memory_barrier ();
2831 imethod
->jit_entry
= addr
;
2838 static long opcode_counts
[MINT_LASTOP
];
2840 #define COUNT_OP(op) opcode_counts[op]++
2842 #define COUNT_OP(op)
2846 #define DUMP_INSTR() \
2847 if (tracing > 1) { \
2849 if (sp > frame->stack) { \
2850 ins = dump_stack (frame->stack, sp); \
2852 ins = g_strdup (""); \
2856 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2857 char *disasm = mono_interp_dis_mintop (frame->imethod->code, ip); \
2858 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2864 #define DUMP_INSTR()
2867 #define INIT_VTABLE(vtable) do { \
2868 if (G_UNLIKELY (!(vtable)->initialized)) { \
2869 mono_runtime_class_init_full ((vtable), error); \
2870 if (!is_ok (error)) \
2871 goto throw_error_label; \
2875 static MONO_NEVER_INLINE MonoObject
*
2876 mono_interp_new (MonoDomain
* domain
, MonoClass
* klass
)
2879 MonoObject
* const object
= mono_object_new_checked (domain
, klass
, error
);
2880 mono_error_cleanup (error
); // FIXME: do not swallow the error
2885 #ifndef DISABLE_REMOTING
2886 MONO_NEVER_INLINE
// To reduce stack.
2889 mono_interp_load_remote_field (
2890 InterpMethod
* imethod
,
2895 g_assert (o
); // Caller checks and throws exception properly.
2898 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
2900 #ifndef DISABLE_REMOTING
2902 if (mono_object_is_transparent_proxy (o
)) {
2903 MonoClass
* const klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
2905 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
2906 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2909 addr
= (char*)o
+ field
->offset
;
2910 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
2914 #ifndef DISABLE_REMOTING
2915 MONO_NEVER_INLINE
// To reduce stack.
2917 guchar
* // Return new vt_sp instead of take-address.
2918 mono_interp_load_remote_field_vt (
2919 InterpMethod
* imethod
,
2925 g_assert (o
); // Caller checks and throws exception properly.
2928 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
2929 MonoClass
* klass
= mono_class_from_mono_type_internal (field
->type
);
2930 int const i32
= mono_class_value_size (klass
, NULL
);
2932 #ifndef DISABLE_REMOTING
2934 if (mono_object_is_transparent_proxy (o
)) {
2935 klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
2937 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
2938 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2941 addr
= (char*)o
+ field
->offset
;
2942 sp
[-1].data
.p
= vt_sp
;
2943 memcpy (vt_sp
, addr
, i32
);
2944 return vt_sp
+ ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
2947 static MONO_NEVER_INLINE gboolean
2948 mono_interp_isinst (MonoObject
* object
, MonoClass
* klass
)
2951 const gboolean isinst
= mono_object_isinst_checked (object
, klass
, error
) != NULL
;
2952 mono_error_cleanup (error
); // FIXME: do not swallow the error
2956 // This function is outlined to help save stack in its caller, on the premise
2957 // that it is relatively rarely called. This also lets it use alloca.
2958 static MONO_NEVER_INLINE
void
2959 mono_interp_calli_nat_dynamic_pinvoke (
2960 // Parameters are sorted by name.
2961 InterpFrame
* child_frame
,
2963 ThreadContext
* context
,
2964 MonoMethodSignature
* csignature
,
2967 // Recompute to limit parameters, which can also contribute to caller stack.
2968 InterpMethod
* const imethod
= child_frame
->parent
->imethod
;
2970 g_assert (imethod
->method
->dynamic
&& csignature
->pinvoke
);
2972 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
2973 MonoMarshalSpec
** mspecs
= g_newa (MonoMarshalSpec
*, csignature
->param_count
+ 1);
2974 memset (mspecs
, 0, sizeof (MonoMarshalSpec
*) * (csignature
->param_count
+ 1));
2976 MonoMethodPInvoke iinfo
;
2977 memset (&iinfo
, 0, sizeof (iinfo
));
2979 MonoMethod
* m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &iinfo
, mspecs
, code
);
2981 for (int i
= csignature
->param_count
; i
>= 0; i
--)
2983 mono_metadata_free_marshal_spec (mspecs
[i
]);
2987 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
2988 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2991 interp_exec_method (child_frame
, context
, error
);
2994 // Leave is split into pieces in order to consume less stack,
2995 // but not have to change how exception handling macros access labels and locals.
2996 static MONO_NEVER_INLINE MonoException
*
2997 mono_interp_leave (InterpFrame
* child_frame
)
3001 * We need for mono_thread_get_undeniable_exception to be able to unwind
3002 * to check the abort threshold. For this to work we use child_frame as a
3003 * dummy frame that is stored in the lmf and serves as the transition frame
3005 do_icall_wrapper (child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
3007 return (MonoException
*)tmp_sp
.data
.p
;
3010 static MONO_NEVER_INLINE
void
3011 mono_interp_newobj_vt (
3012 // Parameters are sorted by name and parameter list is minimized
3013 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3014 // use no stack in caller).
3015 InterpFrame
* child_frame
,
3016 ThreadContext
* context
,
3019 stackval
* const sp
= child_frame
->stack_args
;
3021 stackval valuetype_this
;
3023 memset (&valuetype_this
, 0, sizeof (stackval
));
3024 sp
->data
.p
= &valuetype_this
;
3026 // FIXME It is unfortunate to outline a recursive case as it
3027 // increases its stack usage. We do this however as it conserves
3028 // stack for all the other recursive cases.
3029 interp_exec_method (child_frame
, context
, error
);
3031 CHECK_RESUME_STATE (context
);
3033 *sp
= valuetype_this
;
3038 static MONO_NEVER_INLINE MonoException
*
3039 mono_interp_newobj (
3040 // Parameters are sorted by name and parameter list is minimized
3041 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3042 // use no stack in caller).
3043 InterpFrame
* child_frame
,
3044 ThreadContext
* context
,
3048 InterpFrame
* const frame
= child_frame
->parent
;
3049 InterpMethod
* const imethod
= frame
->imethod
;
3050 stackval
* const sp
= child_frame
->stack_args
;
3052 MonoObject
* o
= NULL
; // See the comment about GC safety.
3053 stackval valuetype_this
;
3056 MonoClass
* const newobj_class
= child_frame
->imethod
->method
->klass
;
3057 /*if (profiling_classes) {
3058 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3060 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3064 * First arg is the object.
3066 if (m_class_is_valuetype (newobj_class
)) {
3067 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
3068 memset (&valuetype_this
, 0, sizeof (stackval
));
3069 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3071 valuetype_this
.data
.p
= vt_sp
;
3073 sp
->data
.p
= &valuetype_this
;
3076 if (newobj_class
!= mono_defaults
.string_class
) {
3077 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
3078 if (!is_ok (error
) || !mono_runtime_class_init_full (vtable
, error
)) {
3079 MonoException
* const exc
= mono_error_convert_to_exception (error
);
3084 OBJREF (o
) = mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
3085 mono_error_cleanup (error
); // FIXME: do not swallow the error
3086 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION
;
3088 #ifndef DISABLE_REMOTING
3089 if (mono_object_is_transparent_proxy (o
)) {
3090 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
->imethod
->method
, error
);
3091 mono_error_assert_ok (error
);
3092 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
3093 mono_error_assert_ok (error
);
3098 child_frame
->retval
= &retval
;
3102 interp_exec_method (child_frame
, context
, error
);
3104 CHECK_RESUME_STATE (context
);
3107 * a constructor returns void, but we need to return the object we created
3109 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
3110 *sp
= valuetype_this
;
3111 } else if (newobj_class
== mono_defaults
.string_class
) {
3120 static MONO_NEVER_INLINE
void
3121 mono_interp_enum_hasflag (stackval
* sp
, MonoClass
* klass
)
3123 guint64 a_val
= 0, b_val
= 0;
3125 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &b_val
, FALSE
);
3126 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &a_val
, FALSE
);
3127 sp
->data
.i
= (a_val
& b_val
) == b_val
;
3130 static MONO_NEVER_INLINE
int
3131 mono_interp_box_nullable (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3133 InterpMethod
* const imethod
= frame
->imethod
;
3134 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[ip
[1]];
3136 int const size
= mono_class_value_size (c
, NULL
);
3138 guint16 offset
= ip
[2];
3139 gboolean
const pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
3140 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
3142 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
3143 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3145 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3148 static MONO_NEVER_INLINE
int
3149 mono_interp_box_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3151 InterpMethod
* const imethod
= frame
->imethod
;
3153 MonoObject
* o
; // See the comment about GC safety.
3154 MonoVTable
* const vtable
= (MonoVTable
*)imethod
->data_items
[ip
[1]];
3155 MonoClass
* const c
= vtable
->klass
;
3157 int const size
= mono_class_value_size (c
, NULL
);
3159 guint16 offset
= ip
[2];
3160 gboolean
const pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
3161 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
3163 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3164 mono_value_copy_internal (mono_object_get_data (o
), sp
[-1 - offset
].data
.p
, c
);
3166 sp
[-1 - offset
].data
.p
= o
;
3167 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3170 static MONO_NEVER_INLINE
void
3171 mono_interp_box (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3173 MonoObject
*o
; // See the comment about GC safety.
3174 MonoVTable
* const vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
3176 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3178 guint16
const offset
= ip
[2];
3180 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (o
), FALSE
);
3182 sp
[-1 - offset
].data
.p
= o
;
3185 static MONO_NEVER_INLINE
int
3186 mono_interp_store_remote_field_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3188 InterpMethod
* const imethod
= frame
->imethod
;
3189 MonoClassField
*field
;
3191 MonoObject
* const o
= sp
[-2].data
.o
;
3193 field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3194 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
3195 int const i32
= mono_class_value_size (klass
, NULL
);
3197 #ifndef DISABLE_REMOTING
3198 if (mono_object_is_transparent_proxy (o
)) {
3199 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3200 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
3201 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3204 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3206 return ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3210 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3211 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3212 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3213 * to return error information.
3215 * Currently this method uses 0x88 of stack space on 64bit gcc. Make sure to keep it under control.
3218 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
)
3220 InterpFrame child_frame
;
3221 GSList
*finally_ips
= NULL
;
3222 const guint16
*ip
= NULL
;
3225 gint tracing
= global_tracing
;
3226 unsigned char *vtalloc
;
3228 unsigned char *vt_sp
;
3229 unsigned char *locals
= NULL
;
3230 #if USE_COMPUTED_GOTO
3231 static void * const in_labels
[] = {
3232 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3233 #include "mintops.def"
3238 debug_enter (frame
, &tracing
);
3241 if (!frame
->imethod
->transformed
) {
3243 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
3244 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
3249 MonoException
*ex
= do_transform_method (frame
, context
);
3251 THROW_EX (ex
, NULL
);
3252 EXCEPTION_CHECKPOINT
;
3256 frame
->stack
= (stackval
*)g_alloca (frame
->imethod
->alloca_size
);
3257 ip
= frame
->imethod
->code
;
3259 ip
= clause_args
->start_with_ip
;
3260 if (clause_args
->base_frame
) {
3261 frame
->stack
= (stackval
*)g_alloca (frame
->imethod
->alloca_size
);
3262 memcpy (frame
->stack
, clause_args
->base_frame
->stack
, frame
->imethod
->alloca_size
);
3266 vt_sp
= (unsigned char *) sp
+ frame
->imethod
->stack_size
;
3270 locals
= (unsigned char *) vt_sp
+ frame
->imethod
->vt_stack_size
;
3271 child_frame
.parent
= frame
;
3273 if (clause_args
&& clause_args
->filter_exception
) {
3274 sp
->data
.p
= clause_args
->filter_exception
;
3278 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3281 * using while (ip < end) may result in a 15% performance drop,
3282 * but it may be useful for debug
3286 /* g_assert (sp >= frame->stack); */
3287 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3289 MINT_IN_SWITCH (*ip
) {
3290 MINT_IN_CASE(MINT_INITLOCALS
)
3291 memset (locals
, 0, frame
->imethod
->locals_size
);
3294 MINT_IN_CASE(MINT_NOP
)
3295 MINT_IN_CASE(MINT_NIY
)
3296 g_assert_not_reached ();
3298 MINT_IN_CASE(MINT_BREAK
)
3300 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3302 MINT_IN_CASE(MINT_BREAKPOINT
)
3306 MINT_IN_CASE(MINT_LDNULL
)
3311 MINT_IN_CASE(MINT_ARGLIST
)
3313 *(gpointer
*)sp
->data
.p
= ((gpointer
*)frame
->retval
->data
.p
) [-1];
3314 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3318 MINT_IN_CASE(MINT_VTRESULT
) {
3319 int ret_size
= ip
[1];
3320 unsigned char *ret_vt_sp
= vt_sp
;
3321 vt_sp
-= READ32(ip
+ 2);
3323 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3324 sp
[-1].data
.p
= vt_sp
;
3325 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3330 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3331 MINT_IN_CASE(MINT_LDC_I4_M1
)
3334 MINT_IN_CASE(MINT_LDC_I4_0
)
3337 MINT_IN_CASE(MINT_LDC_I4_1
)
3340 MINT_IN_CASE(MINT_LDC_I4_2
)
3343 MINT_IN_CASE(MINT_LDC_I4_3
)
3346 MINT_IN_CASE(MINT_LDC_I4_4
)
3349 MINT_IN_CASE(MINT_LDC_I4_5
)
3352 MINT_IN_CASE(MINT_LDC_I4_6
)
3355 MINT_IN_CASE(MINT_LDC_I4_7
)
3358 MINT_IN_CASE(MINT_LDC_I4_8
)
3361 MINT_IN_CASE(MINT_LDC_I4_S
)
3362 sp
->data
.i
= (short)ip
[1];
3366 MINT_IN_CASE(MINT_LDC_I4
)
3368 sp
->data
.i
= READ32 (ip
);
3372 MINT_IN_CASE(MINT_LDC_I8
)
3374 sp
->data
.l
= READ64 (ip
);
3378 MINT_IN_CASE(MINT_LDC_I8_S
)
3379 sp
->data
.l
= (short)ip
[1];
3383 MINT_IN_CASE(MINT_LDC_R4
) {
3387 sp
->data
.f_r4
= * (float *)&val
;
3392 MINT_IN_CASE(MINT_LDC_R8
)
3393 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3397 MINT_IN_CASE(MINT_DUP
)
3402 MINT_IN_CASE(MINT_DUP_VT
) {
3403 int const i32
= READ32 (ip
+ 1);
3405 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3406 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3411 MINT_IN_CASE(MINT_POP
) {
3412 guint16 u16
= (ip
[1]) + 1;
3414 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
3419 MINT_IN_CASE(MINT_JMP
) {
3420 g_assert (sp
== frame
->stack
);
3421 InterpMethod
*new_method
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3423 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3424 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
3426 if (!new_method
->transformed
) {
3427 MONO_API_ERROR_INIT (error
);
3430 mono_interp_transform_method (new_method
, context
, error
);
3431 MonoException
*ex
= mono_error_convert_to_exception (error
);
3436 const gboolean realloc_frame
= new_method
->alloca_size
> frame
->imethod
->alloca_size
;
3437 frame
->imethod
= new_method
;
3439 * We allocate the stack frame from scratch and store the arguments in the
3440 * locals again since it's possible for the caller stack frame to be smaller
3441 * than the callee stack frame (at the interp level)
3443 if (realloc_frame
) {
3444 frame
->stack
= (stackval
*)g_alloca (frame
->imethod
->alloca_size
);
3445 memset (frame
->stack
, 0, frame
->imethod
->alloca_size
);
3448 vt_sp
= (unsigned char *) sp
+ frame
->imethod
->stack_size
;
3452 locals
= vt_sp
+ frame
->imethod
->vt_stack_size
;
3453 ip
= frame
->imethod
->code
;
3456 MINT_IN_CASE(MINT_CALLI
) {
3457 MonoMethodSignature
*csignature
;
3461 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3464 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
3467 child_frame
.retval
= sp
;
3468 /* decrement by the actual number of args */
3469 sp
-= csignature
->param_count
;
3470 if (csignature
->hasthis
)
3472 child_frame
.stack_args
= sp
;
3474 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3475 child_frame
.imethod
= mono_interp_get_imethod (frame
->imethod
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
3476 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3479 if (csignature
->hasthis
) {
3480 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3482 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3483 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3484 sp
[0].data
.p
= unboxed
;
3488 interp_exec_method (&child_frame
, context
, error
);
3490 CHECK_RESUME_STATE (context
);
3492 /* need to handle typedbyref ... */
3493 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3494 *sp
= *child_frame
.retval
;
3499 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3500 gpointer target_ip
= sp
[-1].data
.p
;
3501 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3502 int opcode
= ip
[2];
3503 gboolean save_last_error
= ip
[3];
3508 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3509 EXCEPTION_CHECKPOINT
;
3510 CHECK_RESUME_STATE (context
);
3514 MINT_IN_CASE(MINT_CALLI_NAT
) {
3518 MonoMethodSignature
* csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3522 guchar
* const code
= (guchar
*)sp
->data
.p
;
3523 child_frame
.imethod
= NULL
;
3526 child_frame
.retval
= sp
;
3527 /* decrement by the actual number of args */
3528 sp
-= csignature
->param_count
;
3529 if (csignature
->hasthis
)
3531 child_frame
.stack_args
= sp
;
3533 if (frame
->imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3534 mono_interp_calli_nat_dynamic_pinvoke (&child_frame
, code
, context
, csignature
, error
);
3536 const gboolean save_last_error
= ip
[-3 + 2];
3537 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, context
, save_last_error
);
3540 CHECK_RESUME_STATE (context
);
3542 /* need to handle typedbyref ... */
3543 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3544 *sp
= *child_frame
.retval
;
3549 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3550 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3551 MonoObject
*this_arg
;
3552 InterpMethod
*target_imethod
;
3555 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3559 target_imethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3560 slot
= (gint16
)ip
[2];
3563 child_frame
.retval
= sp
;
3565 /* decrement by the actual number of args */
3566 sp
-= target_imethod
->param_count
+ target_imethod
->hasthis
;
3567 child_frame
.stack_args
= sp
;
3569 this_arg
= (MonoObject
*)sp
->data
.p
;
3571 child_frame
.imethod
= get_virtual_method_fast (target_imethod
, this_arg
->vtable
, slot
);
3572 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3574 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3575 sp
[0].data
.p
= unboxed
;
3578 interp_exec_method (&child_frame
, context
, error
);
3580 CHECK_RESUME_STATE (context
);
3582 const gboolean is_void
= ip
[-3] == MINT_VCALLVIRT_FAST
;
3584 /* need to handle typedbyref ... */
3585 *sp
= *child_frame
.retval
;
3590 MINT_IN_CASE(MINT_CALL_VARARG
) {
3591 int num_varargs
= 0;
3592 MonoMethodSignature
*csig
;
3596 child_frame
.imethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3597 /* The real signature for vararg calls */
3598 csig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3599 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3600 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
3601 vt_sp
= copy_varargs_vtstack (csig
, sp
, vt_sp
);
3605 child_frame
.retval
= sp
;
3607 /* decrement by the actual number of args */
3608 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
3609 child_frame
.stack_args
= sp
;
3611 interp_exec_method (&child_frame
, context
, error
);
3613 CHECK_RESUME_STATE (context
);
3615 if (csig
->ret
->type
!= MONO_TYPE_VOID
) {
3616 *sp
= *child_frame
.retval
;
3621 MINT_IN_CASE(MINT_CALL
)
3622 MINT_IN_CASE(MINT_VCALL
)
3623 MINT_IN_CASE(MINT_CALLVIRT
)
3624 MINT_IN_CASE(MINT_VCALLVIRT
) {
3628 child_frame
.imethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3631 child_frame
.retval
= sp
;
3633 /* decrement by the actual number of args */
3634 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
;
3635 child_frame
.stack_args
= sp
;
3637 const gboolean is_virtual
= ip
[-2] == MINT_CALLVIRT
|| ip
[-2] == MINT_VCALLVIRT
;
3639 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3641 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
->vtable
);
3642 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3644 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3645 sp
[0].data
.p
= unboxed
;
3649 interp_exec_method (&child_frame
, context
, error
);
3651 CHECK_RESUME_STATE (context
);
3653 const gboolean is_void
= ip
[-2] == MINT_VCALL
|| ip
[-2] == MINT_VCALLVIRT
;
3655 /* need to handle typedbyref ... */
3656 *sp
= *child_frame
.retval
;
3661 MINT_IN_CASE(MINT_JIT_CALL
) {
3662 InterpMethod
*rmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3663 MONO_API_ERROR_INIT (error
);
3665 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3666 if (!is_ok (error
)) {
3667 MonoException
*ex
= mono_error_convert_to_exception (error
);
3672 CHECK_RESUME_STATE (context
);
3674 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3679 MINT_IN_CASE(MINT_CALLRUN
) {
3680 MonoMethod
*target_method
= (MonoMethod
*) frame
->imethod
->data_items
[ip
[1]];
3681 MonoMethodSignature
*sig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3687 sp
-= sig
->param_count
;
3691 MonoException
*ex
= ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3695 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3702 MINT_IN_CASE(MINT_RET
)
3704 *frame
->retval
= *sp
;
3705 if (sp
> frame
->stack
)
3706 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3708 MINT_IN_CASE(MINT_RET_VOID
)
3709 if (sp
> frame
->stack
)
3710 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
3712 MINT_IN_CASE(MINT_RET_VT
) {
3713 int const i32
= READ32 (ip
+ 1);
3715 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3716 if (sp
> frame
->stack
)
3717 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3720 MINT_IN_CASE(MINT_BR_S
)
3721 ip
+= (short) *(ip
+ 1);
3723 MINT_IN_CASE(MINT_BR
)
3724 ip
+= (gint32
) READ32(ip
+ 1);
3726 #define ZEROP_S(datamem, op) \
3728 if (sp->data.datamem op 0) \
3729 ip += (gint16)ip [1]; \
3733 #define ZEROP(datamem, op) \
3735 if (sp->data.datamem op 0) \
3736 ip += (gint32)READ32(ip + 1); \
3740 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3743 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3746 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3749 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3752 MINT_IN_CASE(MINT_BRFALSE_I4
)
3755 MINT_IN_CASE(MINT_BRFALSE_I8
)
3758 MINT_IN_CASE(MINT_BRFALSE_R4
)
3761 MINT_IN_CASE(MINT_BRFALSE_R8
)
3764 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3767 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3770 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
3773 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3776 MINT_IN_CASE(MINT_BRTRUE_I4
)
3779 MINT_IN_CASE(MINT_BRTRUE_I8
)
3782 MINT_IN_CASE(MINT_BRTRUE_R4
)
3785 MINT_IN_CASE(MINT_BRTRUE_R8
)
3788 #define CONDBR_S(cond) \
3791 ip += (gint16)ip [1]; \
3794 #define BRELOP_S(datamem, op) \
3795 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3797 #define CONDBR(cond) \
3800 ip += (gint32)READ32(ip + 1); \
3804 #define BRELOP(datamem, op) \
3805 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3807 MINT_IN_CASE(MINT_BEQ_I4_S
)
3810 MINT_IN_CASE(MINT_BEQ_I8_S
)
3813 MINT_IN_CASE(MINT_BEQ_R4_S
)
3814 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3816 MINT_IN_CASE(MINT_BEQ_R8_S
)
3817 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3819 MINT_IN_CASE(MINT_BEQ_I4
)
3822 MINT_IN_CASE(MINT_BEQ_I8
)
3825 MINT_IN_CASE(MINT_BEQ_R4
)
3826 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3828 MINT_IN_CASE(MINT_BEQ_R8
)
3829 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3831 MINT_IN_CASE(MINT_BGE_I4_S
)
3834 MINT_IN_CASE(MINT_BGE_I8_S
)
3837 MINT_IN_CASE(MINT_BGE_R4_S
)
3838 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3840 MINT_IN_CASE(MINT_BGE_R8_S
)
3841 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3843 MINT_IN_CASE(MINT_BGE_I4
)
3846 MINT_IN_CASE(MINT_BGE_I8
)
3849 MINT_IN_CASE(MINT_BGE_R4
)
3850 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3852 MINT_IN_CASE(MINT_BGE_R8
)
3853 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3855 MINT_IN_CASE(MINT_BGT_I4_S
)
3858 MINT_IN_CASE(MINT_BGT_I8_S
)
3861 MINT_IN_CASE(MINT_BGT_R4_S
)
3862 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3864 MINT_IN_CASE(MINT_BGT_R8_S
)
3865 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3867 MINT_IN_CASE(MINT_BGT_I4
)
3870 MINT_IN_CASE(MINT_BGT_I8
)
3873 MINT_IN_CASE(MINT_BGT_R4
)
3874 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3876 MINT_IN_CASE(MINT_BGT_R8
)
3877 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3879 MINT_IN_CASE(MINT_BLT_I4_S
)
3882 MINT_IN_CASE(MINT_BLT_I8_S
)
3885 MINT_IN_CASE(MINT_BLT_R4_S
)
3886 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3888 MINT_IN_CASE(MINT_BLT_R8_S
)
3889 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3891 MINT_IN_CASE(MINT_BLT_I4
)
3894 MINT_IN_CASE(MINT_BLT_I8
)
3897 MINT_IN_CASE(MINT_BLT_R4
)
3898 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3900 MINT_IN_CASE(MINT_BLT_R8
)
3901 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3903 MINT_IN_CASE(MINT_BLE_I4_S
)
3906 MINT_IN_CASE(MINT_BLE_I8_S
)
3909 MINT_IN_CASE(MINT_BLE_R4_S
)
3910 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3912 MINT_IN_CASE(MINT_BLE_R8_S
)
3913 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3915 MINT_IN_CASE(MINT_BLE_I4
)
3918 MINT_IN_CASE(MINT_BLE_I8
)
3921 MINT_IN_CASE(MINT_BLE_R4
)
3922 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3924 MINT_IN_CASE(MINT_BLE_R8
)
3925 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3927 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3930 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3933 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
3934 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3936 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3937 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3939 MINT_IN_CASE(MINT_BNE_UN_I4
)
3942 MINT_IN_CASE(MINT_BNE_UN_I8
)
3945 MINT_IN_CASE(MINT_BNE_UN_R4
)
3946 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3948 MINT_IN_CASE(MINT_BNE_UN_R8
)
3949 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3952 #define BRELOP_S_CAST(datamem, op, type) \
3954 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3955 ip += (gint16)ip [1]; \
3959 #define BRELOP_CAST(datamem, op, type) \
3961 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3962 ip += (gint32)READ32(ip + 1); \
3966 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3967 BRELOP_S_CAST(i
, >=, guint32
);
3969 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3970 BRELOP_S_CAST(l
, >=, guint64
);
3972 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
3973 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3975 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3976 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3978 MINT_IN_CASE(MINT_BGE_UN_I4
)
3979 BRELOP_CAST(i
, >=, guint32
);
3981 MINT_IN_CASE(MINT_BGE_UN_I8
)
3982 BRELOP_CAST(l
, >=, guint64
);
3984 MINT_IN_CASE(MINT_BGE_UN_R4
)
3985 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3987 MINT_IN_CASE(MINT_BGE_UN_R8
)
3988 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3990 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3991 BRELOP_S_CAST(i
, >, guint32
);
3993 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3994 BRELOP_S_CAST(l
, >, guint64
);
3996 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
3997 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3999 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
4000 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4002 MINT_IN_CASE(MINT_BGT_UN_I4
)
4003 BRELOP_CAST(i
, >, guint32
);
4005 MINT_IN_CASE(MINT_BGT_UN_I8
)
4006 BRELOP_CAST(l
, >, guint64
);
4008 MINT_IN_CASE(MINT_BGT_UN_R4
)
4009 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4011 MINT_IN_CASE(MINT_BGT_UN_R8
)
4012 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4014 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
4015 BRELOP_S_CAST(i
, <=, guint32
);
4017 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
4018 BRELOP_S_CAST(l
, <=, guint64
);
4020 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
4021 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4023 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
4024 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4026 MINT_IN_CASE(MINT_BLE_UN_I4
)
4027 BRELOP_CAST(i
, <=, guint32
);
4029 MINT_IN_CASE(MINT_BLE_UN_I8
)
4030 BRELOP_CAST(l
, <=, guint64
);
4032 MINT_IN_CASE(MINT_BLE_UN_R4
)
4033 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4035 MINT_IN_CASE(MINT_BLE_UN_R8
)
4036 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4038 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
4039 BRELOP_S_CAST(i
, <, guint32
);
4041 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
4042 BRELOP_S_CAST(l
, <, guint64
);
4044 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
4045 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4047 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
4048 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4050 MINT_IN_CASE(MINT_BLT_UN_I4
)
4051 BRELOP_CAST(i
, <, guint32
);
4053 MINT_IN_CASE(MINT_BLT_UN_I8
)
4054 BRELOP_CAST(l
, <, guint64
);
4056 MINT_IN_CASE(MINT_BLT_UN_R4
)
4057 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4059 MINT_IN_CASE(MINT_BLT_UN_R8
)
4060 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4062 MINT_IN_CASE(MINT_SWITCH
) {
4064 const unsigned short *st
;
4070 if ((guint32
)sp
->data
.i
< n
) {
4072 ip
+= 2 * (guint32
)sp
->data
.i
;
4073 offset
= READ32 (ip
);
4080 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
4081 NULL_CHECK (sp
[-1].data
.p
);
4083 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
4085 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
4086 NULL_CHECK (sp
[-1].data
.p
);
4088 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
4090 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
4091 NULL_CHECK (sp
[-1].data
.p
);
4093 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
4095 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
4096 NULL_CHECK (sp
[-1].data
.p
);
4098 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
4100 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
4101 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
4102 NULL_CHECK (sp
[-1].data
.p
);
4104 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
4106 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
4107 NULL_CHECK (sp
[-1].data
.p
);
4109 #ifdef NO_UNALIGNED_ACCESS
4110 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4111 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
4114 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
4116 MINT_IN_CASE(MINT_LDIND_I
) {
4117 guint16 offset
= ip
[1];
4118 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
4122 MINT_IN_CASE(MINT_LDIND_I8
) {
4123 guint16 offset
= ip
[1];
4124 #ifdef NO_UNALIGNED_ACCESS
4125 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
4126 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
4129 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
4133 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
4134 NULL_CHECK (sp
[-1].data
.p
);
4136 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
4138 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
4139 NULL_CHECK (sp
[-1].data
.p
);
4141 #ifdef NO_UNALIGNED_ACCESS
4142 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4143 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
4146 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
4148 MINT_IN_CASE(MINT_LDIND_REF
)
4150 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4152 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
4153 NULL_CHECK (sp
[-1].data
.p
);
4155 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4158 MINT_IN_CASE(MINT_STIND_REF
)
4161 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
4163 MINT_IN_CASE(MINT_STIND_I1
)
4166 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
4168 MINT_IN_CASE(MINT_STIND_I2
)
4171 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
4173 MINT_IN_CASE(MINT_STIND_I4
)
4176 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
4178 MINT_IN_CASE(MINT_STIND_I
)
4181 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
4183 MINT_IN_CASE(MINT_STIND_I8
)
4186 #ifdef NO_UNALIGNED_ACCESS
4187 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4188 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
4191 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
4193 MINT_IN_CASE(MINT_STIND_R4
)
4196 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
4198 MINT_IN_CASE(MINT_STIND_R8
)
4201 #ifdef NO_UNALIGNED_ACCESS
4202 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4203 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
4206 * (double *) sp
->data
.p
= sp
[1].data
.f
;
4208 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
4211 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
4213 #define BINOP(datamem, op) \
4215 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4217 MINT_IN_CASE(MINT_ADD_I4
)
4220 MINT_IN_CASE(MINT_ADD_I8
)
4223 MINT_IN_CASE(MINT_ADD_R4
)
4226 MINT_IN_CASE(MINT_ADD_R8
)
4229 MINT_IN_CASE(MINT_ADD1_I4
)
4233 MINT_IN_CASE(MINT_ADD1_I8
)
4237 MINT_IN_CASE(MINT_SUB_I4
)
4240 MINT_IN_CASE(MINT_SUB_I8
)
4243 MINT_IN_CASE(MINT_SUB_R4
)
4246 MINT_IN_CASE(MINT_SUB_R8
)
4249 MINT_IN_CASE(MINT_SUB1_I4
)
4253 MINT_IN_CASE(MINT_SUB1_I8
)
4257 MINT_IN_CASE(MINT_MUL_I4
)
4260 MINT_IN_CASE(MINT_MUL_I8
)
4263 MINT_IN_CASE(MINT_MUL_R4
)
4266 MINT_IN_CASE(MINT_MUL_R8
)
4269 MINT_IN_CASE(MINT_DIV_I4
)
4270 if (sp
[-1].data
.i
== 0)
4271 goto div_zero_label
;
4272 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4273 goto overflow_label
;
4276 MINT_IN_CASE(MINT_DIV_I8
)
4277 if (sp
[-1].data
.l
== 0)
4278 goto div_zero_label
;
4279 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4280 goto overflow_label
;
4283 MINT_IN_CASE(MINT_DIV_R4
)
4286 MINT_IN_CASE(MINT_DIV_R8
)
4290 #define BINOP_CAST(datamem, op, type) \
4292 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4294 MINT_IN_CASE(MINT_DIV_UN_I4
)
4295 if (sp
[-1].data
.i
== 0)
4296 goto div_zero_label
;
4297 BINOP_CAST(i
, /, guint32
);
4299 MINT_IN_CASE(MINT_DIV_UN_I8
)
4300 if (sp
[-1].data
.l
== 0)
4301 goto div_zero_label
;
4302 BINOP_CAST(l
, /, guint64
);
4304 MINT_IN_CASE(MINT_REM_I4
)
4305 if (sp
[-1].data
.i
== 0)
4306 goto div_zero_label
;
4307 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4308 goto overflow_label
;
4311 MINT_IN_CASE(MINT_REM_I8
)
4312 if (sp
[-1].data
.l
== 0)
4313 goto div_zero_label
;
4314 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4315 goto overflow_label
;
4318 MINT_IN_CASE(MINT_REM_R4
)
4319 /* FIXME: what do we actually do here? */
4321 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4324 MINT_IN_CASE(MINT_REM_R8
)
4325 /* FIXME: what do we actually do here? */
4327 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4330 MINT_IN_CASE(MINT_REM_UN_I4
)
4331 if (sp
[-1].data
.i
== 0)
4332 goto div_zero_label
;
4333 BINOP_CAST(i
, %, guint32
);
4335 MINT_IN_CASE(MINT_REM_UN_I8
)
4336 if (sp
[-1].data
.l
== 0)
4337 goto div_zero_label
;
4338 BINOP_CAST(l
, %, guint64
);
4340 MINT_IN_CASE(MINT_AND_I4
)
4343 MINT_IN_CASE(MINT_AND_I8
)
4346 MINT_IN_CASE(MINT_OR_I4
)
4349 MINT_IN_CASE(MINT_OR_I8
)
4352 MINT_IN_CASE(MINT_XOR_I4
)
4355 MINT_IN_CASE(MINT_XOR_I8
)
4359 #define SHIFTOP(datamem, op) \
4361 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4364 MINT_IN_CASE(MINT_SHL_I4
)
4367 MINT_IN_CASE(MINT_SHL_I8
)
4370 MINT_IN_CASE(MINT_SHR_I4
)
4373 MINT_IN_CASE(MINT_SHR_I8
)
4376 MINT_IN_CASE(MINT_SHR_UN_I4
)
4378 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4381 MINT_IN_CASE(MINT_SHR_UN_I8
)
4383 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4386 MINT_IN_CASE(MINT_NEG_I4
)
4387 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4390 MINT_IN_CASE(MINT_NEG_I8
)
4391 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4394 MINT_IN_CASE(MINT_NEG_R4
)
4395 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4398 MINT_IN_CASE(MINT_NEG_R8
)
4399 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4402 MINT_IN_CASE(MINT_NOT_I4
)
4403 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4406 MINT_IN_CASE(MINT_NOT_I8
)
4407 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4410 MINT_IN_CASE(MINT_CONV_I1_I4
)
4411 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4414 MINT_IN_CASE(MINT_CONV_I1_I8
)
4415 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4418 MINT_IN_CASE(MINT_CONV_I1_R4
)
4419 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4422 MINT_IN_CASE(MINT_CONV_I1_R8
)
4423 /* without gint32 cast, C compiler is allowed to use undefined
4424 * behaviour if data.f is bigger than >255. See conv.fpint section
4426 * > The conversion truncates; that is, the fractional part
4427 * > is discarded. The behavior is undefined if the truncated
4428 * > value cannot be represented in the destination type.
4430 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4433 MINT_IN_CASE(MINT_CONV_U1_I4
)
4434 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4437 MINT_IN_CASE(MINT_CONV_U1_I8
)
4438 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4441 MINT_IN_CASE(MINT_CONV_U1_R4
)
4442 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4445 MINT_IN_CASE(MINT_CONV_U1_R8
)
4446 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4449 MINT_IN_CASE(MINT_CONV_I2_I4
)
4450 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4453 MINT_IN_CASE(MINT_CONV_I2_I8
)
4454 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4457 MINT_IN_CASE(MINT_CONV_I2_R4
)
4458 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4461 MINT_IN_CASE(MINT_CONV_I2_R8
)
4462 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4465 MINT_IN_CASE(MINT_CONV_U2_I4
)
4466 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4469 MINT_IN_CASE(MINT_CONV_U2_I8
)
4470 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4473 MINT_IN_CASE(MINT_CONV_U2_R4
)
4474 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4477 MINT_IN_CASE(MINT_CONV_U2_R8
)
4478 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4481 MINT_IN_CASE(MINT_CONV_I4_R4
)
4482 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4485 MINT_IN_CASE(MINT_CONV_I4_R8
)
4486 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4489 MINT_IN_CASE(MINT_CONV_U4_I8
)
4490 MINT_IN_CASE(MINT_CONV_I4_I8
)
4491 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4494 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4495 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4498 MINT_IN_CASE(MINT_CONV_U4_R4
)
4499 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4500 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4502 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4506 MINT_IN_CASE(MINT_CONV_U4_R8
)
4507 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4508 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
4510 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4514 MINT_IN_CASE(MINT_CONV_I8_I4
)
4515 sp
[-1].data
.l
= sp
[-1].data
.i
;
4518 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4519 sp
[-2].data
.l
= sp
[-2].data
.i
;
4522 MINT_IN_CASE(MINT_CONV_I8_U4
)
4523 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4526 MINT_IN_CASE(MINT_CONV_I8_R4
)
4527 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4530 MINT_IN_CASE(MINT_CONV_I8_R8
)
4531 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4534 MINT_IN_CASE(MINT_CONV_R4_I4
)
4535 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4538 MINT_IN_CASE(MINT_CONV_R4_I8
)
4539 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4542 MINT_IN_CASE(MINT_CONV_R4_R8
)
4543 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4546 MINT_IN_CASE(MINT_CONV_R8_I4
)
4547 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4550 MINT_IN_CASE(MINT_CONV_R8_I8
)
4551 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4554 MINT_IN_CASE(MINT_CONV_R8_R4
)
4555 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4558 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4559 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4562 MINT_IN_CASE(MINT_CONV_U8_I4
)
4563 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
4566 MINT_IN_CASE(MINT_CONV_U8_R4
)
4567 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4568 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
4570 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4574 MINT_IN_CASE(MINT_CONV_U8_R8
)
4575 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4576 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
4578 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4582 MINT_IN_CASE(MINT_CPOBJ
) {
4583 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4584 g_assert (m_class_is_valuetype (c
));
4585 /* if this assertion fails, we need to add a write barrier */
4586 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4587 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4592 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4593 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4594 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4599 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4600 int size
= READ32(ip
+ 1);
4602 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4603 sp
[-1].data
.p
= vt_sp
;
4604 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4607 MINT_IN_CASE(MINT_LDSTR
)
4608 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
4612 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4613 MonoString
*s
= NULL
;
4614 guint32 strtoken
= (guint32
)(gsize
)frame
->imethod
->data_items
[ip
[1]];
4616 MonoMethod
*method
= frame
->imethod
->method
;
4617 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4618 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4619 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4620 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4622 g_assert_not_reached ();
4629 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4630 MonoClass
*newobj_class
;
4631 guint32 token
= ip
[1];
4632 guint16 param_count
= ip
[2];
4634 newobj_class
= (MonoClass
*) frame
->imethod
->data_items
[token
];
4637 sp
->data
.o
= ves_array_create (frame
->imethod
->domain
, newobj_class
, param_count
, sp
, error
);
4639 goto throw_error_label
;
4645 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
4647 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[3]];
4648 INIT_VTABLE (vtable
);
4649 MonoObject
*o
; // See the comment about GC safety.
4650 guint16 param_count
;
4651 guint16 imethod_index
= ip
[1];
4653 const gboolean is_inlined
= imethod_index
== 0xffff;
4655 param_count
= ip
[2];
4659 memmove (sp
+ 1 + is_inlined
, sp
, param_count
* sizeof (stackval
));
4662 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4663 if (G_UNLIKELY (!o
)) {
4664 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4665 goto throw_error_label
;
4671 sp
+= param_count
+ 2;
4673 InterpMethod
*ctor_method
= (InterpMethod
*) frame
->imethod
->data_items
[imethod_index
];
4676 child_frame
.imethod
= ctor_method
;
4677 child_frame
.stack_args
= sp
;
4679 interp_exec_method (&child_frame
, context
, error
);
4680 CHECK_RESUME_STATE (context
);
4688 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4689 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4691 // This is split up to:
4693 // - keep exception handling and resume mostly in the main function
4696 child_frame
.imethod
= (InterpMethod
*) frame
->imethod
->data_items
[ip
[1]];
4697 guint16
const param_count
= ip
[2];
4701 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
4703 child_frame
.stack_args
= sp
;
4704 gboolean
const vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4706 memset (vt_sp
, 0, ip
[3]);
4710 interp_exec_method (&child_frame
, context
, error
);
4712 CHECK_RESUME_STATE (context
);
4717 mono_interp_newobj_vt (&child_frame
, context
, error
);
4718 CHECK_RESUME_STATE (context
);
4724 MINT_IN_CASE(MINT_NEWOBJ
) {
4726 // This is split up to:
4728 // - keep exception handling and resume mostly in the main function
4732 guint32
const token
= ip
[1];
4733 ip
+= 2; // FIXME: Do this after throw?
4735 child_frame
.ip
= NULL
;
4737 child_frame
.imethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
4738 MonoMethodSignature
* const csig
= mono_method_signature_internal (child_frame
.imethod
->method
);
4740 g_assert (csig
->hasthis
);
4741 if (csig
->param_count
) {
4742 sp
-= csig
->param_count
;
4743 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
4746 child_frame
.stack_args
= sp
;
4748 MonoException
* const exc
= mono_interp_newobj (&child_frame
, context
, error
, vt_sp
);
4751 CHECK_RESUME_STATE (context
);
4755 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
4761 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
4762 MonoMethodSignature
*csig
;
4769 InterpMethod
*cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
4770 csig
= mono_method_signature_internal (cmethod
->method
);
4772 g_assert (csig
->hasthis
);
4773 sp
-= csig
->param_count
;
4775 gpointer arg0
= sp
[0].data
.p
;
4777 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
4778 *byreference_this
= arg0
;
4780 /* Followed by a VTRESULT opcode which will push the result on the stack */
4784 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4785 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4786 sp
[-1].data
.p
= *byreference_this
;
4790 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
4792 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
4797 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
4799 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
4804 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
4805 MonoObject
*obj
= sp
[-1].data
.o
;
4806 sp
[-1].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
4810 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
4811 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
4812 MonoObject
* const o
= sp
[-1].data
.o
;
4814 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4816 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
4818 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
4820 isinst
= mono_interp_isinst (o
, c
); // FIXME: do not swallow the error
4826 gboolean
const isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
4828 sp
[-1].data
.p
= NULL
;
4830 goto invalid_cast_label
;
4836 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
4837 MINT_IN_CASE(MINT_ISINST_COMMON
) {
4838 MonoObject
* const o
= sp
[-1].data
.o
;
4840 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4841 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
4844 gboolean
const isinst_instr
= *ip
== MINT_ISINST_COMMON
;
4846 sp
[-1].data
.p
= NULL
;
4848 goto invalid_cast_label
;
4854 MINT_IN_CASE(MINT_CASTCLASS
)
4855 MINT_IN_CASE(MINT_ISINST
) {
4856 MonoObject
* const o
= sp
[-1].data
.o
;
4858 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4859 if (!mono_interp_isinst (o
, c
)) { // FIXME: do not swallow the error
4860 gboolean
const isinst_instr
= *ip
== MINT_ISINST
;
4862 sp
[-1].data
.p
= NULL
;
4864 goto invalid_cast_label
;
4870 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4871 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4874 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4875 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4878 MINT_IN_CASE(MINT_UNBOX
) {
4879 MonoObject
* const o
= sp
[-1].data
.o
;
4881 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4883 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
4884 goto invalid_cast_label
;
4886 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
4890 MINT_IN_CASE(MINT_THROW
)
4893 sp
->data
.p
= mono_get_exception_null_reference ();
4895 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4897 MINT_IN_CASE(MINT_CHECKPOINT
)
4898 /* Do synchronous checking of abort requests */
4899 EXCEPTION_CHECKPOINT
;
4902 MINT_IN_CASE(MINT_SAFEPOINT
)
4903 /* Do synchronous checking of abort requests */
4904 EXCEPTION_CHECKPOINT
;
4905 /* Poll safepoint */
4906 mono_threads_safepoint ();
4909 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
) {
4910 sp
[-1].data
.p
= (char*)sp
[-1].data
.o
+ ip
[1];
4914 MINT_IN_CASE(MINT_LDFLDA
) {
4915 MonoObject
* const o
= sp
[-1].data
.o
;
4917 sp
[-1].data
.p
= (char *)o
+ ip
[1];
4921 MINT_IN_CASE(MINT_CKNULL_N
) {
4922 /* Same as CKNULL, but further down the stack */
4923 int const n
= ip
[1];
4924 MonoObject
* const o
= sp
[-n
].data
.o
;
4930 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4931 MonoObject* const o = sp [-1].data.o; \
4934 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
4936 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
4940 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4942 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4943 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4944 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4945 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4946 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4947 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4948 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
4949 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4950 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4951 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4952 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4953 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4955 MINT_IN_CASE(MINT_LDFLD_VT
) {
4956 MonoObject
* const o
= sp
[-1].data
.o
;
4959 int size
= READ32(ip
+ 2);
4960 sp
[-1].data
.p
= vt_sp
;
4961 memcpy (sp
[-1].data
.p
, (char *)o
+ ip
[1], size
);
4962 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4967 MINT_IN_CASE(MINT_LDRMFLD
) {
4968 MonoObject
* const o
= sp
[-1].data
.o
;
4970 mono_interp_load_remote_field (frame
->imethod
, o
, ip
, sp
);
4974 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
4975 MonoObject
* const o
= sp
[-1].data
.o
;
4977 vt_sp
= mono_interp_load_remote_field_vt (frame
->imethod
, o
, ip
, sp
, vt_sp
);
4982 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4983 MonoObject* const o = sp [-2].data.o; \
4987 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
4989 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
4993 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4995 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
4996 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
4997 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
4998 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
4999 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
5000 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
5001 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
5002 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
5003 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
5004 MINT_IN_CASE(MINT_STFLD_O
) {
5005 MonoObject
* const o
= sp
[-2].data
.o
;
5008 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[1], sp
[1].data
.o
);
5012 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5013 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5015 MINT_IN_CASE(MINT_STFLD_VT
) {
5016 MonoObject
* const o
= sp
[-2].data
.o
;
5020 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[2]];
5021 int const i32
= mono_class_value_size (klass
, NULL
);
5023 guint16 offset
= ip
[1];
5024 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
5026 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5030 MINT_IN_CASE(MINT_STRMFLD
) {
5031 MonoClassField
*field
;
5033 MonoObject
* const o
= sp
[-2].data
.o
;
5036 field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5039 #ifndef DISABLE_REMOTING
5040 if (mono_object_is_transparent_proxy (o
)) {
5041 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
5042 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
5043 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
5046 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
5051 MINT_IN_CASE(MINT_STRMFLD_VT
)
5053 NULL_CHECK (sp
[-2].data
.o
);
5054 vt_sp
-= mono_interp_store_remote_field_vt (frame
, ip
, sp
, error
);
5059 MINT_IN_CASE(MINT_LDSFLDA
) {
5060 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5061 INIT_VTABLE (vtable
);
5062 sp
->data
.p
= frame
->imethod
->data_items
[ip
[2]];
5068 MINT_IN_CASE(MINT_LDSSFLDA
) {
5069 guint32 offset
= READ32(ip
+ 1);
5070 sp
->data
.p
= mono_get_special_static_data (offset
);
5076 /* We init class here to preserve cctor order */
5077 #define LDSFLD(datamem, fieldtype) { \
5078 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5079 INIT_VTABLE (vtable); \
5080 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5085 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
5086 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
5087 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
5088 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
5089 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
5090 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
5091 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
5092 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
5093 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5094 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5096 MINT_IN_CASE(MINT_LDSFLD_VT
) {
5097 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5098 INIT_VTABLE (vtable
);
5101 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5102 int const i32
= READ32 (ip
+ 3);
5103 memcpy (vt_sp
, addr
, i32
);
5104 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5110 #define LDTSFLD(datamem, fieldtype) { \
5111 MonoInternalThread *thread = mono_thread_internal_current (); \
5112 guint32 offset = READ32 (ip + 1); \
5113 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5114 sp[0].data.datamem = *(fieldtype*)addr; \
5118 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
5119 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
5120 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
5121 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
5122 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
5123 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
5124 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
5125 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
5126 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5127 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5129 MINT_IN_CASE(MINT_LDSSFLD
) {
5130 guint32 offset
= READ32(ip
+ 2);
5131 gpointer addr
= mono_get_special_static_data (offset
);
5132 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5133 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
5138 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
5139 guint32 offset
= READ32(ip
+ 1);
5140 gpointer addr
= mono_get_special_static_data (offset
);
5142 int size
= READ32 (ip
+ 3);
5143 memcpy (vt_sp
, addr
, size
);
5145 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5150 #define STSFLD(datamem, fieldtype) { \
5151 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5152 INIT_VTABLE (vtable); \
5154 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5158 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5159 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5160 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5161 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5162 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5163 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5164 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5165 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5166 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5167 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5169 MINT_IN_CASE(MINT_STSFLD_VT
) {
5170 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5171 INIT_VTABLE (vtable
);
5172 int const i32
= READ32 (ip
+ 3);
5173 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5175 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5176 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5182 #define STTSFLD(datamem, fieldtype) { \
5183 MonoInternalThread *thread = mono_thread_internal_current (); \
5184 guint32 offset = READ32 (ip + 1); \
5185 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5187 *(fieldtype*)addr = sp[0].data.datamem; \
5191 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5192 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5193 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5194 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5195 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5196 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5197 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5198 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5199 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5200 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5202 MINT_IN_CASE(MINT_STSSFLD
) {
5203 guint32 offset
= READ32(ip
+ 2);
5204 gpointer addr
= mono_get_special_static_data (offset
);
5205 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5207 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5211 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5212 guint32 offset
= READ32(ip
+ 1);
5213 gpointer addr
= mono_get_special_static_data (offset
);
5215 int size
= READ32 (ip
+ 3);
5216 memcpy (addr
, sp
->data
.vt
, size
);
5217 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5222 MINT_IN_CASE(MINT_STOBJ_VT
) {
5224 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5226 size
= mono_class_value_size (c
, NULL
);
5227 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5228 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5232 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5233 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5234 goto overflow_label
;
5235 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5238 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5239 if (sp
[-1].data
.i
< 0)
5240 goto overflow_label
;
5241 sp
[-1].data
.l
= sp
[-1].data
.i
;
5244 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5245 if (sp
[-1].data
.l
< 0)
5246 goto overflow_label
;
5249 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5250 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5251 goto overflow_label
;
5254 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5255 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5256 goto overflow_label
;
5257 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5260 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5261 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5262 goto overflow_label
;
5263 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5266 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5267 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
5268 goto overflow_label
;
5269 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5272 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
)
5273 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT64
)
5274 goto overflow_label
;
5275 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5278 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5279 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5280 goto overflow_label
;
5281 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5284 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5285 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5286 goto overflow_label
;
5287 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5290 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5291 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5292 goto overflow_label
;
5293 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5296 MINT_IN_CASE(MINT_BOX
) {
5297 mono_interp_box (frame
, ip
, sp
);
5301 MINT_IN_CASE(MINT_BOX_VT
) {
5302 vt_sp
-= mono_interp_box_vt (frame
, ip
, sp
);
5306 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5307 vt_sp
-= mono_interp_box_nullable (frame
, ip
, sp
, error
);
5311 MINT_IN_CASE(MINT_NEWARR
) {
5312 MonoVTable
*vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
5313 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5314 if (!is_ok (error
)) {
5315 goto throw_error_label
;
5318 /*if (profiling_classes) {
5319 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5321 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5326 MINT_IN_CASE(MINT_LDLEN
) {
5327 MonoObject
* const o
= sp
[-1].data
.o
;
5329 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5333 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5334 MonoObject
* const o
= sp
[-1].data
.o
;
5336 gsize offset_length
= (gsize
)(gint16
)ip
[1];
5337 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5341 MINT_IN_CASE(MINT_GETCHR
) {
5343 s
= (MonoString
*)sp
[-2].data
.p
;
5345 int const i32
= sp
[-1].data
.i
;
5346 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5347 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5349 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5353 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5354 guint8
* const span
= (guint8
*) sp
[-2].data
.p
;
5355 const int index
= sp
[-1].data
.i
;
5360 const gsize offset_length
= (gsize
)(gint16
)ip
[2];
5362 const gint32 length
= *(gint32
*) (span
+ offset_length
);
5363 if (index
< 0 || index
>= length
)
5364 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5366 const gsize element_size
= (gsize
)(gint16
)ip
[1];
5367 const gsize offset_pointer
= (gsize
)(gint16
)ip
[3];
5369 const gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5370 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5375 MINT_IN_CASE(MINT_STRLEN
) {
5377 MonoObject
* const o
= sp
[-1].data
.o
;
5379 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5382 MINT_IN_CASE(MINT_ARRAY_RANK
) {
5383 MonoObject
* const o
= sp
[-1].data
.o
;
5385 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
5389 MINT_IN_CASE(MINT_LDELEMA_FAST
) {
5390 /* No bounds, one direction */
5391 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
5393 gint32
const index
= sp
[-1].data
.i
;
5394 if (index
>= ao
->max_length
)
5395 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5396 gint32
const size
= READ32 (ip
+ 1);
5397 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
5403 MINT_IN_CASE(MINT_LDELEMA
)
5404 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5406 guint16 numargs
= ip
[2];
5410 MonoObject
* const o
= sp
[0].data
.o
;
5413 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[-3 + 1]];
5414 const gboolean needs_typecheck
= ip
[-3] == MINT_LDELEMA_TC
;
5415 MonoException
*ex
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
5422 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
5423 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
5424 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
5425 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
5426 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
5427 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
5428 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
5429 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
5430 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
5431 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
5432 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
5433 MINT_IN_CASE(MINT_LDELEM_VT
) {
5439 o
= (MonoArray
*)sp
[0].data
.p
;
5442 aindex
= sp
[1].data
.i
;
5443 if (aindex
>= mono_array_length_internal (o
))
5444 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5447 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5450 case MINT_LDELEM_I1
:
5451 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
5453 case MINT_LDELEM_U1
:
5454 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
5456 case MINT_LDELEM_I2
:
5457 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
5459 case MINT_LDELEM_U2
:
5460 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
5463 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
5465 case MINT_LDELEM_I4
:
5466 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
5468 case MINT_LDELEM_U4
:
5469 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
5471 case MINT_LDELEM_I8
:
5472 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
5474 case MINT_LDELEM_R4
:
5475 sp
[0].data
.f_r4
= mono_array_get_fast (o
, float, aindex
);
5477 case MINT_LDELEM_R8
:
5478 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
5480 case MINT_LDELEM_REF
:
5481 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
5483 case MINT_LDELEM_VT
: {
5484 int const i32
= READ32 (ip
+ 1);
5485 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5486 sp
[0].data
.vt
= vt_sp
;
5487 // Copying to vtstack. No wbarrier needed
5488 memcpy (sp
[0].data
.vt
, src_addr
, i32
);
5489 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5501 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
5502 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
5503 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
5504 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
5505 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
5506 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
5507 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
5508 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
5509 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
5510 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
5511 MINT_IN_CASE(MINT_STELEM_VT
) {
5516 MonoObject
* const o
= sp
[0].data
.o
;
5519 aindex
= sp
[1].data
.i
;
5520 if (aindex
>= mono_array_length_internal ((MonoArray
*)o
))
5521 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5525 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
5527 case MINT_STELEM_I1
:
5528 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
5530 case MINT_STELEM_U1
:
5531 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
5533 case MINT_STELEM_I2
:
5534 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
5536 case MINT_STELEM_U2
:
5537 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
5539 case MINT_STELEM_I4
:
5540 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
5542 case MINT_STELEM_I8
:
5543 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
5545 case MINT_STELEM_R4
:
5546 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f_r4
);
5548 case MINT_STELEM_R8
:
5549 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
5551 case MINT_STELEM_REF
: {
5552 if (sp
[2].data
.p
) {
5553 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
5554 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
5556 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5558 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5561 case MINT_STELEM_VT
: {
5562 MonoClass
*klass_vt
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5563 int const i32
= READ32 (ip
+ 2);
5564 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5566 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5567 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5578 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5579 if (sp
[-1].data
.i
< 0)
5580 goto overflow_label
;
5583 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5584 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5585 goto overflow_label
;
5586 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5589 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5590 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5591 goto overflow_label
;
5592 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5595 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5596 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
)
5597 goto overflow_label
;
5598 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5601 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5602 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
5603 goto overflow_label
;
5604 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5607 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5608 if (sp
[-1].data
.i
< 0)
5609 goto overflow_label
;
5612 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5613 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5614 goto overflow_label
;
5615 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5618 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5619 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
)
5620 goto overflow_label
;
5621 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5624 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5625 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
5626 goto overflow_label
;
5627 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5630 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5631 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5632 goto overflow_label
;
5635 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
5636 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
5637 goto overflow_label
;
5640 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
5641 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
5642 goto overflow_label
;
5643 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5646 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
5647 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
5648 goto overflow_label
;
5649 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5652 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
5653 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
5654 goto overflow_label
;
5655 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5658 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
5659 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
5660 goto overflow_label
;
5661 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5664 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
5665 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
5666 goto overflow_label
;
5669 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
5670 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
5671 goto overflow_label
;
5672 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
5675 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
5676 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
5677 goto overflow_label
;
5678 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
5681 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
5682 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
5683 goto overflow_label
;
5686 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
5687 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
5688 goto overflow_label
;
5691 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
5692 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
5693 goto overflow_label
;
5694 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5697 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
5698 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
5699 goto overflow_label
;
5700 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5703 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
5704 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
5705 goto overflow_label
;
5706 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5709 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
5710 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
5711 goto overflow_label
;
5712 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5715 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
5716 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
5717 goto overflow_label
;
5720 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
5721 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
5722 goto overflow_label
;
5723 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
5726 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
5727 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
5728 goto overflow_label
;
5729 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
5732 MINT_IN_CASE(MINT_CKFINITE
)
5733 if (!mono_isfinite (sp
[-1].data
.f
))
5734 THROW_EX (mono_get_exception_arithmetic (), ip
);
5737 MINT_IN_CASE(MINT_MKREFANY
) {
5738 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5740 /* The value address is on the stack */
5741 gpointer addr
= sp
[-1].data
.p
;
5742 /* Push the typedref value on the stack */
5743 sp
[-1].data
.p
= vt_sp
;
5744 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5746 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5748 tref
->type
= m_class_get_byval_arg (c
);
5754 MINT_IN_CASE(MINT_REFANYTYPE
) {
5755 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5756 MonoType
*type
= tref
->type
;
5758 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5759 sp
[-1].data
.p
= vt_sp
;
5761 *(gpointer
*)sp
[-1].data
.p
= type
;
5765 MINT_IN_CASE(MINT_REFANYVAL
) {
5766 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5767 gpointer addr
= tref
->value
;
5769 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5770 if (c
!= tref
->klass
)
5771 goto invalid_cast_label
;
5773 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5775 sp
[-1].data
.p
= addr
;
5779 MINT_IN_CASE(MINT_LDTOKEN
)
5782 * (gpointer
*)sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
5786 MINT_IN_CASE(MINT_ADD_OVF_I4
)
5787 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5788 goto overflow_label
;
5791 MINT_IN_CASE(MINT_ADD_OVF_I8
)
5792 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5793 goto overflow_label
;
5796 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
5797 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5798 goto overflow_label
;
5799 BINOP_CAST(i
, +, guint32
);
5801 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
5802 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5803 goto overflow_label
;
5804 BINOP_CAST(l
, +, guint64
);
5806 MINT_IN_CASE(MINT_MUL_OVF_I4
)
5807 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5808 goto overflow_label
;
5811 MINT_IN_CASE(MINT_MUL_OVF_I8
)
5812 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5813 goto overflow_label
;
5816 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
5817 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5818 goto overflow_label
;
5819 BINOP_CAST(i
, *, guint32
);
5821 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
5822 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5823 goto overflow_label
;
5824 BINOP_CAST(l
, *, guint64
);
5826 MINT_IN_CASE(MINT_SUB_OVF_I4
)
5827 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5828 goto overflow_label
;
5831 MINT_IN_CASE(MINT_SUB_OVF_I8
)
5832 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5833 goto overflow_label
;
5836 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
5837 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5838 goto overflow_label
;
5839 BINOP_CAST(i
, -, guint32
);
5841 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
5842 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5843 goto overflow_label
;
5844 BINOP_CAST(l
, -, guint64
);
5846 MINT_IN_CASE(MINT_START_ABORT_PROT
)
5847 mono_threads_begin_abort_protected_block ();
5850 MINT_IN_CASE(MINT_ENDFINALLY
) {
5851 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
5854 // After mono_threads_end_abort_protected_block to conserve stack.
5855 const int clause_index
= *ip
;
5857 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
5860 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
5861 g_assert (sp
>= frame
->stack
);
5866 ip
= (const guint16
*)finally_ips
->data
;
5867 finally_ips
= g_slist_remove (finally_ips
, ip
);
5868 /* Throw abort after the last finally block to avoid confusing EH */
5869 if (pending_abort
&& !finally_ips
)
5870 EXCEPTION_CHECKPOINT
;
5871 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5872 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5879 MINT_IN_CASE(MINT_LEAVE
)
5880 MINT_IN_CASE(MINT_LEAVE_S
)
5881 MINT_IN_CASE(MINT_LEAVE_CHECK
)
5882 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
5884 // Leave is split into pieces in order to consume less stack,
5885 // but not have to change how exception handling macros access labels and locals.
5887 g_assert (sp
>= frame
->stack
);
5888 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5889 vt_sp
= (unsigned char*)sp
+ frame
->imethod
->stack_size
;
5894 gboolean
const check
= opcode
== MINT_LEAVE_CHECK
|| opcode
== MINT_LEAVE_S_CHECK
;
5896 if (check
&& frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
5897 child_frame
.parent
= frame
;
5898 child_frame
.imethod
= NULL
;
5899 MonoException
*abort_exc
= mono_interp_leave (&child_frame
);
5901 THROW_EX (abort_exc
, frame
->ip
);
5904 opcode
= *ip
; // Refetch to avoid register/stack pressure.
5905 gboolean
const short_offset
= opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
;
5906 ip
+= short_offset
? (short)*(ip
+ 1) : (gint32
)READ32 (ip
+ 1);
5907 const guint16
*endfinally_ip
= ip
;
5908 GSList
*old_list
= finally_ips
;
5909 MonoMethod
*method
= frame
->imethod
->method
;
5912 g_print ("* Handle finally IL_%04x\n", endfinally_ip
- frame
->imethod
->code
);
5914 // FIXME Null check for frame->imethod follows deref.
5915 if (frame
->imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5916 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5919 guint32
const ip_offset
= frame
->ip
- frame
->imethod
->code
;
5921 finally_ips
= g_slist_prepend (finally_ips
, (void *)endfinally_ip
);
5923 for (int i
= frame
->imethod
->num_clauses
- 1; i
>= 0; i
--) {
5924 MonoExceptionClause
* const clause
= &frame
->imethod
->clauses
[i
];
5925 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- frame
->imethod
->code
))) {
5926 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5927 ip
= frame
->imethod
->code
+ clause
->handler_offset
;
5928 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5931 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, context
->has_resume_state
? "yes": "no");
5937 if (old_list
!= finally_ips
&& finally_ips
) {
5938 ip
= (const guint16
*)finally_ips
->data
;
5939 finally_ips
= g_slist_remove (finally_ips
, ip
);
5940 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5941 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5948 MINT_IN_CASE(MINT_ICALL_V_V
)
5949 MINT_IN_CASE(MINT_ICALL_V_P
)
5950 MINT_IN_CASE(MINT_ICALL_P_V
)
5951 MINT_IN_CASE(MINT_ICALL_P_P
)
5952 MINT_IN_CASE(MINT_ICALL_PP_V
)
5953 MINT_IN_CASE(MINT_ICALL_PP_P
)
5954 MINT_IN_CASE(MINT_ICALL_PPP_V
)
5955 MINT_IN_CASE(MINT_ICALL_PPP_P
)
5956 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
5957 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
5958 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
5959 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
5960 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
5961 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
5963 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, frame
->imethod
->data_items
[ip
[1]], FALSE
);
5964 EXCEPTION_CHECKPOINT
;
5965 CHECK_RESUME_STATE (context
);
5968 MINT_IN_CASE(MINT_MONO_LDPTR
)
5969 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
5973 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
5974 sp
->data
.o
= mono_interp_new (frame
->imethod
->domain
, (MonoClass
*)frame
->imethod
->data_items
[ip
[1]]); // FIXME: do not swallow the error
5978 MINT_IN_CASE(MINT_MONO_RETOBJ
)
5981 stackval_from_data (mono_method_signature_internal (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
5982 mono_method_signature_internal (frame
->imethod
->method
)->pinvoke
);
5983 if (sp
> frame
->stack
)
5984 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
5986 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
5987 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
5991 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
5993 mono_memory_barrier ();
5996 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
5997 sp
->data
.p
= mono_domain_get ();
6001 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
6002 if (G_UNLIKELY (ss_enabled
)) {
6003 typedef void (*T
) (void);
6007 void *tramp
= mini_get_single_step_trampoline ();
6008 mono_memory_barrier ();
6009 ss_tramp
= (T
)tramp
;
6013 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6014 * the address of that instruction is stored as the seq point address.
6019 * Use the same trampoline as the JIT. This ensures that
6020 * the debugger has the context for the last interpreter
6023 do_debugger_tramp (ss_tramp
, frame
);
6025 CHECK_RESUME_STATE (context
);
6029 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
6030 /* Just a placeholder for a breakpoint */
6033 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
6034 typedef void (*T
) (void);
6037 void *tramp
= mini_get_breakpoint_trampoline ();
6038 mono_memory_barrier ();
6039 bp_tramp
= (T
)tramp
;
6044 /* Use the same trampoline as the JIT */
6045 do_debugger_tramp (bp_tramp
, frame
);
6047 CHECK_RESUME_STATE (context
);
6053 #define RELOP(datamem, op) \
6055 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6058 #define RELOP_FP(datamem, op, noorder) \
6060 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6061 sp [-1].data.i = noorder; \
6063 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6066 MINT_IN_CASE(MINT_CEQ_I4
)
6069 MINT_IN_CASE(MINT_CEQ0_I4
)
6070 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
6073 MINT_IN_CASE(MINT_CEQ_I8
)
6076 MINT_IN_CASE(MINT_CEQ_R4
)
6077 RELOP_FP(f_r4
, ==, 0);
6079 MINT_IN_CASE(MINT_CEQ_R8
)
6082 MINT_IN_CASE(MINT_CNE_I4
)
6085 MINT_IN_CASE(MINT_CNE_I8
)
6088 MINT_IN_CASE(MINT_CNE_R4
)
6089 RELOP_FP(f_r4
, !=, 1);
6091 MINT_IN_CASE(MINT_CNE_R8
)
6094 MINT_IN_CASE(MINT_CGT_I4
)
6097 MINT_IN_CASE(MINT_CGT_I8
)
6100 MINT_IN_CASE(MINT_CGT_R4
)
6101 RELOP_FP(f_r4
, >, 0);
6103 MINT_IN_CASE(MINT_CGT_R8
)
6106 MINT_IN_CASE(MINT_CGE_I4
)
6109 MINT_IN_CASE(MINT_CGE_I8
)
6112 MINT_IN_CASE(MINT_CGE_R4
)
6113 RELOP_FP(f_r4
, >=, 0);
6115 MINT_IN_CASE(MINT_CGE_R8
)
6119 #define RELOP_CAST(datamem, op, type) \
6121 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6124 MINT_IN_CASE(MINT_CGE_UN_I4
)
6125 RELOP_CAST(l
, >=, guint32
);
6127 MINT_IN_CASE(MINT_CGE_UN_I8
)
6128 RELOP_CAST(l
, >=, guint64
);
6131 MINT_IN_CASE(MINT_CGT_UN_I4
)
6132 RELOP_CAST(i
, >, guint32
);
6134 MINT_IN_CASE(MINT_CGT_UN_I8
)
6135 RELOP_CAST(l
, >, guint64
);
6137 MINT_IN_CASE(MINT_CGT_UN_R4
)
6138 RELOP_FP(f_r4
, >, 1);
6140 MINT_IN_CASE(MINT_CGT_UN_R8
)
6143 MINT_IN_CASE(MINT_CLT_I4
)
6146 MINT_IN_CASE(MINT_CLT_I8
)
6149 MINT_IN_CASE(MINT_CLT_R4
)
6150 RELOP_FP(f_r4
, <, 0);
6152 MINT_IN_CASE(MINT_CLT_R8
)
6155 MINT_IN_CASE(MINT_CLT_UN_I4
)
6156 RELOP_CAST(i
, <, guint32
);
6158 MINT_IN_CASE(MINT_CLT_UN_I8
)
6159 RELOP_CAST(l
, <, guint64
);
6161 MINT_IN_CASE(MINT_CLT_UN_R4
)
6162 RELOP_FP(f_r4
, <, 1);
6164 MINT_IN_CASE(MINT_CLT_UN_R8
)
6167 MINT_IN_CASE(MINT_CLE_I4
)
6170 MINT_IN_CASE(MINT_CLE_I8
)
6173 MINT_IN_CASE(MINT_CLE_UN_I4
)
6174 RELOP_CAST(l
, <=, guint32
);
6176 MINT_IN_CASE(MINT_CLE_UN_I8
)
6177 RELOP_CAST(l
, <=, guint64
);
6179 MINT_IN_CASE(MINT_CLE_R4
)
6180 RELOP_FP(f_r4
, <=, 0);
6182 MINT_IN_CASE(MINT_CLE_R8
)
6190 MINT_IN_CASE(MINT_LDFTN
) {
6191 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6196 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6197 InterpMethod
*m
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
6199 NULL_CHECK (sp
->data
.p
);
6201 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6206 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6207 MONO_API_ERROR_INIT (error
);
6208 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6209 mono_error_assert_ok (error
);
6215 #define LDARG(datamem, argtype) \
6216 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6220 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
6221 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
6222 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
6223 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
6224 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
6225 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
6226 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
6227 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
6228 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6229 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6231 MINT_IN_CASE(MINT_LDARG_VT
) {
6233 int const i32
= READ32 (ip
+ 2);
6234 memcpy(sp
->data
.p
, frame
->stack_args
[ip
[1]].data
.p
, i32
);
6235 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6241 #define STARG(datamem, argtype) \
6243 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6246 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
6247 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
6248 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
6249 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
6250 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
6251 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
6252 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6253 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6254 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6255 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6257 MINT_IN_CASE(MINT_STARG_VT
) {
6258 int const i32
= READ32 (ip
+ 2);
6260 memcpy(frame
->stack_args
[ip
[1]].data
.p
, sp
->data
.p
, i32
);
6261 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6265 MINT_IN_CASE(MINT_PROF_ENTER
) {
6268 if (MONO_PROFILER_ENABLED (method_enter
)) {
6269 MonoProfilerCallContext
*prof_ctx
= NULL
;
6271 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
6272 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6273 prof_ctx
->interp_frame
= frame
;
6274 prof_ctx
->method
= frame
->imethod
->method
;
6277 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
6285 MINT_IN_CASE(MINT_TRACE_ENTER
) {
6288 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6289 prof_ctx
->interp_frame
= frame
;
6290 prof_ctx
->method
= frame
->imethod
->method
;
6292 mono_trace_enter_method (frame
->imethod
->method
, prof_ctx
);
6296 MINT_IN_CASE(MINT_TRACE_EXIT
) {
6298 int const i32
= READ32 (ip
+ 1);
6303 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6305 *frame
->retval
= *sp
;
6307 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6308 prof_ctx
->interp_frame
= frame
;
6309 prof_ctx
->method
= frame
->imethod
->method
;
6311 mono_trace_leave_method (frame
->imethod
->method
, prof_ctx
);
6316 MINT_IN_CASE(MINT_LDARGA
)
6317 sp
->data
.p
= &frame
->stack_args
[ip
[1]];
6322 MINT_IN_CASE(MINT_LDARGA_VT
)
6323 sp
->data
.p
= frame
->stack_args
[ip
[1]].data
.p
;
6328 #define LDLOC(datamem, argtype) \
6329 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6333 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6334 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6335 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6336 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6337 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6338 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6339 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6340 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6341 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6342 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6344 MINT_IN_CASE(MINT_LDLOC_VT
) {
6346 int const i32
= READ32 (ip
+ 2);
6347 memcpy(sp
->data
.p
, locals
+ ip
[1], i32
);
6348 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6353 MINT_IN_CASE(MINT_LDLOCA_S
)
6354 sp
->data
.p
= locals
+ ip
[1];
6359 #define STLOC(datamem, argtype) \
6361 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6364 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6365 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6366 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6367 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6368 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6369 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6370 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6371 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6372 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6373 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6375 #define STLOC_NP(datamem, argtype) \
6376 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6379 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6380 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6382 MINT_IN_CASE(MINT_STLOC_VT
) {
6383 int const i32
= READ32 (ip
+ 2);
6385 memcpy(locals
+ ip
[1], sp
->data
.p
, i32
);
6386 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6391 #define MOVLOC(argtype) \
6392 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6395 MINT_IN_CASE(MINT_MOVLOC_1
) MOVLOC(guint8
); MINT_IN_BREAK
;
6396 MINT_IN_CASE(MINT_MOVLOC_2
) MOVLOC(guint16
); MINT_IN_BREAK
;
6397 MINT_IN_CASE(MINT_MOVLOC_4
) MOVLOC(guint32
); MINT_IN_BREAK
;
6398 MINT_IN_CASE(MINT_MOVLOC_8
) MOVLOC(guint64
); MINT_IN_BREAK
;
6400 MINT_IN_CASE(MINT_MOVLOC_VT
) {
6401 int const i32
= READ32(ip
+ 3);
6402 memcpy (locals
+ ip
[2], locals
+ ip
[1], i32
);
6407 MINT_IN_CASE(MINT_LOCALLOC
) {
6408 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6411 int len
= sp
[-1].data
.i
;
6412 sp
[-1].data
.p
= alloca (len
);
6414 if (frame
->imethod
->init_locals
)
6415 memset (sp
[-1].data
.p
, 0, len
);
6419 MINT_IN_CASE(MINT_ENDFILTER
)
6420 /* top of stack is result of filter */
6421 frame
->retval
= &sp
[-1];
6423 MINT_IN_CASE(MINT_INITOBJ
)
6425 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6428 MINT_IN_CASE(MINT_CPBLK
)
6430 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6431 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6433 /* FIXME: value and size may be int64... */
6434 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6437 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6439 /* FIXME: implement */
6441 token
= READ32 (ip
);
6446 MINT_IN_CASE(MINT_INITBLK
)
6448 NULL_CHECK (sp
[0].data
.p
);
6450 /* FIXME: value and size may be int64... */
6451 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6454 MINT_IN_CASE(MINT_NO_
)
6455 /* FIXME: implement */
6459 MINT_IN_CASE(MINT_RETHROW
) {
6460 int exvar_offset
= ip
[1];
6461 THROW_EX_GENERAL (*(MonoException
**)(frame_locals (frame
) + exvar_offset
), ip
, TRUE
);
6464 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6466 * need to clarify what this should actually do:
6468 * Takes an exception from the stack and rethrows it.
6469 * This is useful for wrappers that don't want to have to
6470 * use CEE_THROW and lose the exception stacktrace.
6475 sp
->data
.p
= mono_get_exception_null_reference ();
6477 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6480 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6484 del
= (MonoDelegate
*)sp
->data
.p
;
6485 if (!del
->interp_method
) {
6486 /* Not created from interpreted code */
6487 MONO_API_ERROR_INIT (error
);
6488 g_assert (del
->method
);
6489 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6490 mono_error_assert_ok (error
);
6492 g_assert (del
->interp_method
);
6493 sp
->data
.p
= del
->interp_method
;
6498 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6501 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6502 if (!del
->interp_invoke_impl
) {
6504 * First time we are called. Set up the invoke wrapper. We might be able to do this
6505 * in ctor but we would need to handle AllocDelegateLike_internal separately
6507 MONO_API_ERROR_INIT (error
);
6508 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6509 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6510 mono_error_assert_ok (error
);
6513 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6518 #define MATH_UNOP(mathfunc) \
6519 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6522 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
6523 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
6524 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
6525 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
6526 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
6527 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
6528 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
6529 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
6530 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
6531 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
6532 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
6533 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
6534 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
6535 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
6536 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
6538 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
6539 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6540 mono_interp_enum_hasflag (sp
, klass
);
6545 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
6546 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
6550 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
6551 NULL_CHECK (sp
[-1].data
.p
);
6552 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
6558 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname (*ip
), ip
- frame
->imethod
->code
);
6562 g_assert_not_reached ();
6565 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6567 THROW_EX (mono_get_exception_null_reference (), ip
);
6569 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
6571 THROW_EX (mono_get_exception_overflow (), ip
);
6573 THROW_EX (mono_error_convert_to_exception (error
), ip
);
6575 THROW_EX (mono_get_exception_invalid_cast (), ip
);
6577 g_assert (context
->has_resume_state
);
6579 if (frame
== context
->handler_frame
&& (!clause_args
|| context
->handler_ip
< clause_args
->end_at_ip
)) {
6580 /* Set the current execution state to the resume state in context */
6582 ip
= context
->handler_ip
;
6583 /* spec says stack should be empty at endfinally so it should be at the start too */
6585 vt_sp
= (guchar
*)sp
+ frame
->imethod
->stack_size
;
6586 g_assert (context
->exc_gchandle
);
6587 sp
->data
.p
= mono_gchandle_get_target_internal (context
->exc_gchandle
);
6590 finally_ips
= clear_resume_state (context
, finally_ips
);
6591 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6592 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6597 error_init_reuse (error
);
6599 if (clause_args
&& clause_args
->base_frame
)
6600 memcpy (clause_args
->base_frame
->stack
, frame
->stack
, frame
->imethod
->alloca_size
);
6602 if (!context
->has_resume_state
&& MONO_PROFILER_ENABLED (method_leave
) &&
6603 frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
6604 MonoProfilerCallContext
*prof_ctx
= NULL
;
6606 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
6607 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6608 prof_ctx
->interp_frame
= frame
;
6609 prof_ctx
->method
= frame
->imethod
->method
;
6611 MonoType
*rtype
= mono_method_signature_internal (frame
->imethod
->method
)->ret
;
6613 switch (rtype
->type
) {
6614 case MONO_TYPE_VOID
:
6616 case MONO_TYPE_VALUETYPE
:
6617 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6620 prof_ctx
->return_value
= frame
->retval
;
6625 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
6628 } else if (context
->has_resume_state
&& frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
6629 MONO_PROFILER_RAISE (method_exception_leave
, (frame
->imethod
->method
, mono_gchandle_get_target_internal (context
->exc_gchandle
)));
6635 interp_parse_options (const char *options
)
6642 args
= g_strsplit (options
, ",", -1);
6643 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
6646 if (strncmp (arg
, "jit=", 4) == 0)
6647 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
6648 if (strncmp (arg
, "interp-only=", strlen ("interp-only=")) == 0)
6649 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
6650 if (strncmp (arg
, "-inline", 7) == 0)
6651 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6652 if (strncmp (arg
, "-cprop", 6) == 0)
6653 mono_interp_opt
&= ~INTERP_OPT_CPROP
;
6658 * interp_set_resume_state:
6660 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6663 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
6665 ThreadContext
*context
;
6668 context
= (ThreadContext
*)jit_tls
->interp_context
;
6671 context
->has_resume_state
= TRUE
;
6672 context
->handler_frame
= (InterpFrame
*)interp_frame
;
6673 context
->handler_ei
= ei
;
6674 if (context
->exc_gchandle
)
6675 mono_gchandle_free_internal (context
->exc_gchandle
);
6676 context
->exc_gchandle
= mono_gchandle_new_internal ((MonoObject
*)ex
, FALSE
);
6679 *(MonoException
**)(frame_locals (context
->handler_frame
) + ei
->exvar_offset
) = ex
;
6680 context
->handler_ip
= (const guint16
*)handler_ip
;
6684 interp_get_resume_state (const MonoJitTlsData
*jit_tls
, gboolean
*has_resume_state
, MonoInterpFrameHandle
*interp_frame
, gpointer
*handler_ip
)
6687 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
6689 *has_resume_state
= context
->has_resume_state
;
6690 if (context
->has_resume_state
) {
6691 *interp_frame
= context
->handler_frame
;
6692 *handler_ip
= (gpointer
)context
->handler_ip
;
6697 * interp_run_finally:
6699 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6700 * frame->interp_frame.
6701 * Return TRUE if the finally clause threw an exception.
6704 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6706 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6707 ThreadContext
*context
= get_context ();
6708 const unsigned short *old_ip
= iframe
->ip
;
6709 FrameClauseArgs clause_args
;
6711 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6712 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
6713 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
6714 clause_args
.exit_clause
= clause_index
;
6717 interp_exec_method_full (iframe
, context
, &clause_args
, error
);
6718 if (context
->has_resume_state
) {
6721 iframe
->ip
= old_ip
;
6727 * interp_run_filter:
6729 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6730 * frame->interp_frame.
6733 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6735 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6736 ThreadContext
*context
= get_context ();
6737 InterpFrame child_frame
;
6739 FrameClauseArgs clause_args
;
6742 * Have to run the clause in a new frame which is a copy of IFRAME, since
6743 * during debugging, there are two copies of the frame on the stack.
6745 memset (&child_frame
, 0, sizeof (InterpFrame
));
6746 child_frame
.imethod
= iframe
->imethod
;
6747 child_frame
.retval
= &retval
;
6748 child_frame
.parent
= iframe
;
6749 child_frame
.stack_args
= iframe
->stack_args
;
6751 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6752 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
6753 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
6754 clause_args
.filter_exception
= ex
;
6755 clause_args
.base_frame
= iframe
;
6758 interp_exec_method_full (&child_frame
, context
, &clause_args
, error
);
6759 /* ENDFILTER stores the result into child_frame->retval */
6760 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
6764 InterpFrame
*current
;
6768 * interp_frame_iter_init:
6770 * Initialize an iterator for iterating through interpreted frames.
6773 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
6775 StackIter
*stack_iter
= (StackIter
*)iter
;
6777 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
6781 * interp_frame_iter_next:
6783 * Fill out FRAME with date for the next interpreter frame.
6786 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
6788 StackIter
*stack_iter
= (StackIter
*)iter
;
6789 InterpFrame
*iframe
= stack_iter
->current
;
6791 memset (frame
, 0, sizeof (StackFrameInfo
));
6792 /* pinvoke frames doesn't have imethod set */
6793 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
6794 iframe
= iframe
->parent
;
6798 MonoMethod
*method
= iframe
->imethod
->method
;
6799 frame
->domain
= iframe
->imethod
->domain
;
6800 frame
->interp_frame
= iframe
;
6801 frame
->method
= method
;
6802 frame
->actual_method
= method
;
6803 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
6804 frame
->native_offset
= -1;
6805 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
6807 frame
->type
= FRAME_TYPE_INTERP
;
6808 /* This is the offset in the interpreter IR */
6809 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
6810 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6811 frame
->managed
= TRUE
;
6813 frame
->ji
= iframe
->imethod
->jinfo
;
6814 frame
->frame_addr
= iframe
;
6816 stack_iter
->current
= iframe
->parent
;
6822 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
6824 InterpMethod
* imethod
;
6826 imethod
= lookup_imethod (domain
, method
);
6828 return imethod
->jinfo
;
6834 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6836 guint16
*code
= (guint16
*)ip
;
6837 g_assert (*code
== MINT_SDB_SEQ_POINT
);
6838 *code
= MINT_SDB_BREAKPOINT
;
6842 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6844 guint16
*code
= (guint16
*)ip
;
6845 g_assert (*code
== MINT_SDB_BREAKPOINT
);
6846 *code
= MINT_SDB_SEQ_POINT
;
6850 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
6852 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6854 g_assert (iframe
->imethod
);
6855 return iframe
->imethod
->jinfo
;
6859 interp_frame_get_ip (MonoInterpFrameHandle frame
)
6861 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6863 g_assert (iframe
->imethod
);
6864 return (gpointer
)iframe
->ip
;
6868 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
6870 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6871 MonoMethodSignature
*sig
;
6873 g_assert (iframe
->imethod
);
6875 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6876 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
6880 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
6882 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6884 g_assert (iframe
->imethod
);
6886 return frame_locals (iframe
) + iframe
->imethod
->local_offsets
[pos
];
6890 interp_frame_get_this (MonoInterpFrameHandle frame
)
6892 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6894 g_assert (iframe
->imethod
);
6895 g_assert (iframe
->imethod
->hasthis
);
6896 return &iframe
->stack_args
[0].data
.p
;
6899 static MonoInterpFrameHandle
6900 interp_frame_get_parent (MonoInterpFrameHandle frame
)
6902 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6904 return iframe
->parent
;
6908 interp_frame_get_res (MonoInterpFrameHandle frame
)
6910 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6911 MonoMethodSignature
*sig
;
6913 g_assert (iframe
->imethod
);
6914 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6915 if (sig
->ret
->type
== MONO_TYPE_VOID
)
6918 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
6922 interp_start_single_stepping (void)
6928 interp_stop_single_stepping (void)
6936 opcode_count_comparer (const void * pa
, const void * pb
)
6938 long counta
= opcode_counts
[*(int*)pa
];
6939 long countb
= opcode_counts
[*(int*)pb
];
6941 if (counta
< countb
)
6943 else if (counta
> countb
)
6950 interp_print_op_count (void)
6952 int ordered_ops
[MINT_LASTOP
];
6956 for (i
= 0; i
< MINT_LASTOP
; i
++) {
6957 ordered_ops
[i
] = i
;
6958 total_ops
+= opcode_counts
[i
];
6960 qsort (ordered_ops
, MINT_LASTOP
, sizeof (int), opcode_count_comparer
);
6962 for (i
= 0; i
< MINT_LASTOP
; i
++) {
6963 long count
= opcode_counts
[ordered_ops
[i
]];
6964 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops
[i
]), count
, (double)count
/ total_ops
* 100);
6970 interp_cleanup (void)
6973 interp_print_op_count ();
6978 register_interp_stats (void)
6980 mono_counters_init ();
6981 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
6982 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.cprop_time
);
6983 mono_counters_register ("Instructions optimized away", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.killed_instructions
);
6984 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
6985 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
6988 #undef MONO_EE_CALLBACK
6989 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6991 static const MonoEECallbacks mono_interp_callbacks
= {
6996 mono_ee_interp_init (const char *opts
)
6998 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
6999 g_assert (!interp_init_done
);
7000 interp_init_done
= TRUE
;
7002 mono_native_tls_alloc (&thread_context_id
, NULL
);
7005 interp_parse_options (opts
);
7006 if (mini_get_debug_options ()->mdb_optimizations
)
7007 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
7008 mono_interp_transform_init ();
7010 mini_install_interp_callbacks (&mono_interp_callbacks
);
7012 register_interp_stats ();