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 guint16
*start_with_ip
;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
94 /* When exiting this clause we also exit the frame */
96 /* Exception that we are filtering */
97 MonoException
*filter_exception
;
98 InterpFrame
*base_frame
;
102 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
104 frame
->parent
= parent_frame
;
105 frame
->stack_args
= method_args
;
106 frame
->retval
= method_retval
;
107 frame
->imethod
= rmethod
;
112 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
115 * List of classes whose methods will be executed by transitioning to JITted code.
118 GSList
*mono_interp_jit_classes
;
119 /* Optimizations enabled with interpreter */
120 int mono_interp_opt
= INTERP_OPT_INLINE
;
121 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
122 static gboolean ss_enabled
;
124 static gboolean interp_init_done
= FALSE
;
126 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
);
127 static InterpMethod
* lookup_method_pointer (gpointer addr
);
129 typedef void (*ICallMethod
) (InterpFrame
*frame
);
131 static MonoNativeTlsKey thread_context_id
;
133 #define DEBUG_INTERP 0
137 int mono_interp_traceopt
= 2;
138 /* If true, then we output the opcodes as we interpret them */
139 static int global_tracing
= 2;
141 static int debug_indent_level
= 0;
143 static int break_on_method
= 0;
144 static int nested_trace
= 0;
145 static GList
*db_methods
= NULL
;
146 static char* dump_args (InterpFrame
*inv
);
153 for (h
= 0; h
< debug_indent_level
; h
++)
158 db_match_method (gpointer data
, gpointer user_data
)
160 MonoMethod
*m
= (MonoMethod
*)user_data
;
161 MonoMethodDesc
*desc
= data
;
163 if (mono_method_desc_full_match (desc
, m
))
168 debug_enter (InterpFrame
*frame
, int *tracing
)
171 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
173 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
177 MonoMethod
*method
= frame
->imethod
->method
;
178 char *mn
, *args
= dump_args (frame
);
179 debug_indent_level
++;
181 mn
= mono_method_full_name (method
, FALSE
);
182 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
184 g_print ("%s)\n", args
);
190 #define DEBUG_LEAVE() \
193 args = dump_retval (frame); \
195 mn = mono_method_full_name (frame->imethod->method, FALSE); \
196 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
198 g_print (" => %s\n", args); \
200 debug_indent_level--; \
201 if (tracing == 3) global_tracing = 0; \
206 int mono_interp_traceopt
= 0;
207 #define DEBUG_LEAVE()
211 #if defined(__GNUC__) && !defined(TARGET_WASM)
212 #define USE_COMPUTED_GOTO 1
214 #if USE_COMPUTED_GOTO
215 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
216 #define MINT_IN_CASE(x) LAB_ ## x:
217 #define MINT_IN_DISPATCH(op) goto *in_labels[op];
219 #define MINT_IN_BREAK if (tracing > 1) { MINT_IN_DISPATCH(*ip); } else { COUNT_OP(*ip); goto *in_labels[*ip]; }
221 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
223 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
225 #define MINT_IN_SWITCH(op) switch (op)
226 #define MINT_IN_CASE(x) case x:
227 #define MINT_IN_DISPATCH(op) goto main_loop;
228 #define MINT_IN_BREAK break
229 #define MINT_IN_DEFAULT default:
232 static MONO_NEVER_INLINE GSList
* // Inlining this causes caller to use more stack.
233 set_resume_state (ThreadContext
*context
, InterpFrame
*frame
, 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
);
241 context
->has_resume_state
= 0;
242 context
->handler_frame
= NULL
;
243 context
->handler_ei
= NULL
;
247 /* Set the current execution state to the resume state in context */
248 #define SET_RESUME_STATE(context) do { \
249 ip = (const guint16*)(context)->handler_ip; \
250 /* spec says stack should be empty at endfinally so it should be at the start too */ \
252 vt_sp = (unsigned char *) sp + imethod->stack_size; \
254 sp->data.p = frame->ex; \
257 (finally_ips) = set_resume_state ((context), (frame), (finally_ips)); \
258 /* goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack. \
259 * This is a slow/rare path and conserving stack is preferred over its performance otherwise. \
265 * If this bit is set, it means the call has thrown the exception, and we
266 * reached this point because the EH code in mono_handle_exception ()
267 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
268 * has set the fields in context to indicate where we have to resume execution.
270 #define CHECK_RESUME_STATE(context) do { \
271 if ((context)->has_resume_state) { \
272 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
273 SET_RESUME_STATE (context); \
279 // In a void function, leave ret empty.
280 #define CHECK_RESUME_STATE_IN_HELPER_FUNCTION(context, ret) do { \
281 if ((context)->has_resume_state) \
286 set_context (ThreadContext
*context
)
288 mono_native_tls_set_value (thread_context_id
, context
);
293 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
294 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
296 /* jit_tls assumes ownership of 'context' */
297 jit_tls
->interp_context
= context
;
300 static ThreadContext
*
303 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
304 if (context
== NULL
) {
305 context
= g_new0 (ThreadContext
, 1);
306 set_context (context
);
311 static MONO_NEVER_INLINE
void
312 ves_real_abort (int line
, MonoMethod
*mh
,
313 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
316 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
317 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
318 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
319 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
320 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
321 mono_metadata_free_mh (header
);
324 #define ves_abort() \
326 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
327 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
331 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
333 InterpMethod
*imethod
;
334 MonoJitDomainInfo
*info
;
336 info
= domain_jit_info (domain
);
337 mono_domain_jit_code_hash_lock (domain
);
338 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
339 mono_domain_jit_code_hash_unlock (domain
);
344 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
346 #ifndef DISABLE_REMOTING
347 InterpMethod
*imethod
;
350 imethod
= lookup_method_pointer (addr
);
353 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
354 return_val_if_nok (error
, NULL
);
357 g_assert (mono_use_interpreter
);
359 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
360 return_val_if_nok (error
, NULL
);
361 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
363 g_assert_not_reached ();
369 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
371 InterpMethod
*imethod
;
372 MonoJitDomainInfo
*info
;
373 MonoMethodSignature
*sig
;
378 info
= domain_jit_info (domain
);
379 mono_domain_jit_code_hash_lock (domain
);
380 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
381 mono_domain_jit_code_hash_unlock (domain
);
385 sig
= mono_method_signature_internal (method
);
387 imethod
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
388 imethod
->method
= method
;
389 imethod
->domain
= domain
;
390 imethod
->param_count
= sig
->param_count
;
391 imethod
->hasthis
= sig
->hasthis
;
392 imethod
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
393 imethod
->rtype
= mini_get_underlying_type (sig
->ret
);
394 imethod
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
395 for (i
= 0; i
< sig
->param_count
; ++i
)
396 imethod
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
398 mono_domain_jit_code_hash_lock (domain
);
399 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
400 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, imethod
);
401 mono_domain_jit_code_hash_unlock (domain
);
403 imethod
->prof_flags
= mono_profiler_get_call_instrumentation_flags (imethod
->method
);
408 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
409 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
410 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
412 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
413 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
414 * (registers are not accurate), thus resuming to the label does not work. */
415 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
416 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
417 #elif defined (_MSC_VER)
418 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
419 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
420 (ext).interp_exit_label_set = FALSE; \
421 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
422 if ((ext).interp_exit_label_set == FALSE) \
423 mono_arch_do_ip_adjustment (&(ext).ctx); \
424 if ((ext).interp_exit_label_set == TRUE) \
426 (ext).interp_exit_label_set = TRUE;
427 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
428 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
429 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
430 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
431 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
432 mono_arch_do_ip_adjustment (&(ext).ctx);
434 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
437 /* INTERP_PUSH_LMF_WITH_CTX:
439 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
440 * This is needed to resume into the interp when the exception is thrown from
441 * native code (see ./mono/tests/install_eh_callback.exe).
443 * This must be a macro in order to retrieve the right register values for
446 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
447 memset (&(ext), 0, sizeof (MonoLMFExt)); \
448 (ext).interp_exit_data = (frame); \
449 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
450 mono_push_lmf (&(ext));
455 * Push an LMF frame on the LMF stack
456 * to mark the transition to native code.
457 * This is needed for the native code to
458 * be able to do stack walks.
461 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
463 memset (ext
, 0, sizeof (MonoLMFExt
));
464 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
465 ext
->interp_exit_data
= frame
;
471 interp_pop_lmf (MonoLMFExt
*ext
)
473 mono_pop_lmf (&ext
->lmf
);
476 static MONO_NEVER_INLINE InterpMethod
*
477 get_virtual_method (InterpMethod
*imethod
, MonoVTable
*vtable
)
479 MonoMethod
*m
= imethod
->method
;
480 MonoDomain
*domain
= imethod
->domain
;
481 InterpMethod
*ret
= NULL
;
483 #ifndef DISABLE_REMOTING
484 if (mono_class_is_transparent_proxy (vtable
->klass
)) {
486 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
487 mono_error_assert_ok (error
);
488 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
489 mono_error_assert_ok (error
);
494 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
495 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
497 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
498 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
505 mono_class_setup_vtable (vtable
->klass
);
507 int slot
= mono_method_get_vtable_slot (m
);
508 if (mono_class_is_interface (m
->klass
)) {
509 g_assert (vtable
->klass
!= m
->klass
);
510 /* TODO: interface offset lookup is slow, go through IMT instead */
511 gboolean non_exact_match
;
512 slot
+= mono_class_interface_offset_with_variance (vtable
->klass
, m
->klass
, &non_exact_match
);
515 MonoMethod
*virtual_method
= m_class_get_vtable (vtable
->klass
) [slot
];
516 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
517 MonoGenericContext context
= { NULL
, NULL
};
519 if (mono_class_is_ginst (virtual_method
->klass
))
520 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
521 else if (mono_class_is_gtd (virtual_method
->klass
))
522 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
523 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
526 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
527 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
530 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
531 virtual_method
= mono_marshal_get_native_wrapper (virtual_method
, FALSE
, FALSE
);
534 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
535 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
539 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
540 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
541 return virtual_imethod
;
545 InterpMethod
*imethod
;
546 InterpMethod
*target_imethod
;
549 /* domain lock must be held */
551 append_imethod (MonoDomain
*domain
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
554 InterpVTableEntry
*entry
;
556 entry
= (InterpVTableEntry
*) mono_mempool_alloc (domain
->mp
, sizeof (InterpVTableEntry
));
557 entry
->imethod
= imethod
;
558 entry
->target_imethod
= target_imethod
;
559 ret
= g_slist_append_mempool (domain
->mp
, list
, entry
);
565 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
567 while (list
!= NULL
) {
568 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
569 if (entry
->imethod
== imethod
)
570 return entry
->target_imethod
;
577 get_method_table (MonoVTable
*vtable
, int offset
)
580 return vtable
->interp_vtable
;
582 return (gpointer
*)vtable
;
586 alloc_method_table (MonoVTable
*vtable
, int offset
)
591 table
= mono_domain_alloc0 (vtable
->domain
, m_class_get_vtable_size (vtable
->klass
) * sizeof (gpointer
));
592 vtable
->interp_vtable
= table
;
594 table
= (gpointer
*)vtable
;
600 static MONO_NEVER_INLINE InterpMethod
* // Inlining causes additional stack use in caller.
601 get_virtual_method_fast (InterpMethod
*imethod
, MonoVTable
*vtable
, int offset
)
605 #ifndef DISABLE_REMOTING
607 if (mono_class_is_transparent_proxy (vtable
->klass
))
608 return get_virtual_method (imethod
, vtable
);
611 table
= get_method_table (vtable
, offset
);
614 /* Lazily allocate method table */
615 mono_domain_lock (vtable
->domain
);
616 table
= get_method_table (vtable
, offset
);
618 table
= alloc_method_table (vtable
, offset
);
619 mono_domain_unlock (vtable
->domain
);
622 if (!table
[offset
]) {
623 InterpMethod
*target_imethod
= get_virtual_method (imethod
, vtable
);
624 /* Lazily initialize the method table slot */
625 mono_domain_lock (vtable
->domain
);
626 if (!table
[offset
]) {
627 if (imethod
->method
->is_inflated
|| offset
< 0)
628 table
[offset
] = append_imethod (vtable
->domain
, NULL
, imethod
, target_imethod
);
630 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
632 mono_domain_unlock (vtable
->domain
);
635 if ((gsize
)table
[offset
] & 0x1) {
636 /* Non generic virtual call. Only one method in slot */
637 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
639 /* Virtual generic or interface call. Multiple methods in slot */
640 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
642 if (!target_imethod
) {
643 target_imethod
= get_virtual_method (imethod
, vtable
);
644 mono_domain_lock (vtable
->domain
);
645 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
646 table
[offset
] = append_imethod (vtable
->domain
, (GSList
*)table
[offset
], imethod
, target_imethod
);
647 mono_domain_unlock (vtable
->domain
);
649 return target_imethod
;
654 stackval_from_data (MonoType
*type_
, stackval
*result
, void *data
, gboolean pinvoke
)
656 MonoType
*type
= mini_native_type_replace_type (type_
);
658 switch (type
->type
) {
659 case MONO_TYPE_OBJECT
:
660 case MONO_TYPE_CLASS
:
661 case MONO_TYPE_STRING
:
662 case MONO_TYPE_ARRAY
:
663 case MONO_TYPE_SZARRAY
:
668 result
->data
.p
= *(gpointer
*)data
;
671 switch (type
->type
) {
675 result
->data
.i
= *(gint8
*)data
;
678 case MONO_TYPE_BOOLEAN
:
679 result
->data
.i
= *(guint8
*)data
;
682 result
->data
.i
= *(gint16
*)data
;
686 result
->data
.i
= *(guint16
*)data
;
689 result
->data
.i
= *(gint32
*)data
;
693 result
->data
.nati
= *(mono_i
*)data
;
696 result
->data
.p
= *(gpointer
*)data
;
699 result
->data
.i
= *(guint32
*)data
;
702 /* memmove handles unaligned case */
703 memmove (&result
->data
.f_r4
, data
, sizeof (float));
707 memmove (&result
->data
.l
, data
, sizeof (gint64
));
710 memmove (&result
->data
.f
, data
, sizeof (double));
712 case MONO_TYPE_STRING
:
713 case MONO_TYPE_SZARRAY
:
714 case MONO_TYPE_CLASS
:
715 case MONO_TYPE_OBJECT
:
716 case MONO_TYPE_ARRAY
:
717 result
->data
.p
= *(gpointer
*)data
;
719 case MONO_TYPE_VALUETYPE
:
720 if (m_class_is_enumtype (type
->data
.klass
)) {
721 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
723 } else if (pinvoke
) {
724 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
726 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
729 case MONO_TYPE_GENERICINST
: {
730 if (mono_type_generic_inst_is_valuetype (type
)) {
731 mono_value_copy_internal (result
->data
.vt
, data
, mono_class_from_mono_type_internal (type
));
734 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
738 g_error ("got type 0x%02x", type
->type
);
743 stackval_to_data (MonoType
*type_
, stackval
*val
, void *data
, gboolean pinvoke
)
745 MonoType
*type
= mini_native_type_replace_type (type_
);
747 gpointer
*p
= (gpointer
*)data
;
751 /* printf ("TODAT0 %p\n", data); */
752 switch (type
->type
) {
755 guint8
*p
= (guint8
*)data
;
759 case MONO_TYPE_BOOLEAN
: {
760 guint8
*p
= (guint8
*)data
;
761 *p
= (val
->data
.i
!= 0);
766 case MONO_TYPE_CHAR
: {
767 guint16
*p
= (guint16
*)data
;
772 mono_i
*p
= (mono_i
*)data
;
773 /* In theory the value used by stloc should match the local var type
774 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
775 a native int - both by csc and mcs). Not sure what to do about sign extension
776 as it is outside the spec... doing the obvious */
777 *p
= (mono_i
)val
->data
.nati
;
781 mono_u
*p
= (mono_u
*)data
;
783 *p
= (mono_u
)val
->data
.nati
;
788 gint32
*p
= (gint32
*)data
;
794 memmove (data
, &val
->data
.l
, sizeof (gint64
));
798 /* memmove handles unaligned case */
799 memmove (data
, &val
->data
.f_r4
, sizeof (float));
803 memmove (data
, &val
->data
.f
, sizeof (double));
806 case MONO_TYPE_STRING
:
807 case MONO_TYPE_SZARRAY
:
808 case MONO_TYPE_CLASS
:
809 case MONO_TYPE_OBJECT
:
810 case MONO_TYPE_ARRAY
: {
811 gpointer
*p
= (gpointer
*) data
;
812 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
815 case MONO_TYPE_PTR
: {
816 gpointer
*p
= (gpointer
*) data
;
820 case MONO_TYPE_VALUETYPE
:
821 if (m_class_is_enumtype (type
->data
.klass
)) {
822 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
824 } else if (pinvoke
) {
825 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
827 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
830 case MONO_TYPE_GENERICINST
: {
831 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
833 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
834 mono_value_copy_internal (data
, val
->data
.vt
, mono_class_from_mono_type_internal (type
));
837 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
841 g_error ("got type %x", type
->type
);
846 * Same as stackval_to_data but return address of storage instead
847 * of copying the value.
850 stackval_to_data_addr (MonoType
*type_
, stackval
*val
)
852 MonoType
*type
= mini_native_type_replace_type (type_
);
856 switch (type
->type
) {
859 case MONO_TYPE_BOOLEAN
:
868 return &val
->data
.nati
;
873 return &val
->data
.f_r4
;
876 case MONO_TYPE_STRING
:
877 case MONO_TYPE_SZARRAY
:
878 case MONO_TYPE_CLASS
:
879 case MONO_TYPE_OBJECT
:
880 case MONO_TYPE_ARRAY
:
883 case MONO_TYPE_VALUETYPE
:
884 if (m_class_is_enumtype (type
->data
.klass
))
885 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
888 case MONO_TYPE_TYPEDBYREF
:
890 case MONO_TYPE_GENERICINST
: {
891 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
893 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
895 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
898 g_error ("got type %x", type
->type
);
904 * Throw an exception from the interpreter.
906 static MONO_NEVER_INLINE
void
907 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, const guint16
* ip
, gboolean rethrow
)
912 interp_push_lmf (&ext
, frame
);
916 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
917 MonoException
*mono_ex
= ex
;
919 mono_ex
->stack_trace
= NULL
;
920 mono_ex
->trace_ips
= NULL
;
923 mono_error_assert_ok (error
);
926 memset (&ctx
, 0, sizeof (MonoContext
));
927 MONO_CONTEXT_SET_SP (&ctx
, frame
);
930 * Call the JIT EH code. The EH code will call back to us using:
931 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
932 * Since ctx.ip is 0, this will start unwinding from the LMF frame
933 * pushed above, which points to our frames.
935 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
936 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
937 /* We need to unwind into non-interpreter code */
938 mono_restore_context (&ctx
);
939 g_assert_not_reached ();
942 interp_pop_lmf (&ext
);
944 g_assert (context
->has_resume_state
);
947 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
949 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
950 CHECK_RESUME_STATE(context); \
953 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
955 #define THROW_EX_OVF(ip) THROW_EX (mono_get_exception_overflow (), ip)
957 #define THROW_EX_DIV_ZERO(ip) THROW_EX (mono_get_exception_divide_by_zero (), ip)
959 #define NULL_CHECK(o) do { \
960 if (G_UNLIKELY (!(o))) \
961 THROW_EX (mono_get_exception_null_reference (), ip); \
964 #define EXCEPTION_CHECKPOINT \
966 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
967 MonoException *exc = mono_thread_interruption_checkpoint (); \
969 THROW_EX (exc, ip); \
974 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
976 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
977 MonoException *exc = mono_thread_interruption_checkpoint (); \
984 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
987 intptr_t *lower_bounds
;
990 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
991 for (i
= 0; i
< param_count
; ++i
) {
992 lengths
[i
] = values
->data
.i
;
995 if (m_class_get_rank (klass
) == param_count
) {
996 /* Only lengths provided. */
999 /* lower bounds are first. */
1000 lower_bounds
= (intptr_t *) lengths
;
1001 lengths
+= m_class_get_rank (klass
);
1003 return (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
1007 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
1009 g_assert (!frame
->ex
);
1010 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1014 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
1015 guint32 idx
= sp
[i
].data
.i
;
1016 guint32 lower
= ao
->bounds
[i
].lower_bound
;
1017 guint32 len
= ao
->bounds
[i
].length
;
1018 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
1019 frame
->ex
= mono_get_exception_index_out_of_range ();
1022 pos
= (pos
* len
) + idx
- lower
;
1025 pos
= sp
[0].data
.i
;
1026 if (safe
&& pos
>= ao
->max_length
) {
1027 frame
->ex
= mono_get_exception_index_out_of_range ();
1034 static MONO_NEVER_INLINE
void
1035 ves_array_set (InterpFrame
*frame
, stackval
*sp
, MonoMethodSignature
*sig
)
1037 MonoObject
*o
= sp
->data
.o
;
1038 MonoArray
*ao
= (MonoArray
*) o
;
1039 MonoClass
*ac
= o
->vtable
->klass
;
1041 g_assert (m_class_get_rank (ac
) >= 1);
1043 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, TRUE
);
1047 int val_index
= 1 + m_class_get_rank (ac
);
1048 if (sp
[val_index
].data
.p
&& !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o
)))) {
1050 MonoObject
*isinst
= mono_object_isinst_checked (sp
[val_index
].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
1051 mono_error_cleanup (error
);
1053 frame
->ex
= mono_get_exception_array_type_mismatch ();
1058 gint32 esize
= mono_array_element_size (ac
);
1059 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1061 MonoType
*mt
= sig
->params
[m_class_get_rank (ac
)];
1062 stackval_to_data (mt
, &sp
[val_index
], ea
, FALSE
);
1066 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1068 MonoObject
*o
= sp
->data
.o
;
1069 MonoArray
*ao
= (MonoArray
*) o
;
1070 MonoClass
*ac
= o
->vtable
->klass
;
1072 g_assert (m_class_get_rank (ac
) >= 1);
1074 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, safe
);
1078 gint32 esize
= mono_array_element_size (ac
);
1079 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1081 MonoType
*mt
= sig
->ret
;
1082 stackval_from_data (mt
, retval
, ea
, FALSE
);
1085 static MONO_NEVER_INLINE gpointer
1086 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1088 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1090 g_assert (m_class_get_rank (ac
) >= 1);
1092 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
1096 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
)) {
1097 frame
->ex
= mono_get_exception_array_type_mismatch ();
1100 gint32 esize
= mono_array_element_size (ac
);
1101 return mono_array_addr_with_size_fast (ao
, esize
, pos
);
1104 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1105 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1108 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1109 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1111 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1114 g_assert (mono_arm_eabi_supported ());
1115 int i8_align
= mono_arm_i8_align ();
1125 for (int i
= 0; i
< sig
->param_count
; i
++) {
1126 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1128 case MONO_TYPE_BOOLEAN
:
1129 case MONO_TYPE_CHAR
:
1139 case MONO_TYPE_SZARRAY
:
1140 case MONO_TYPE_CLASS
:
1141 case MONO_TYPE_OBJECT
:
1142 case MONO_TYPE_STRING
:
1143 case MONO_TYPE_VALUETYPE
:
1144 case MONO_TYPE_GENERICINST
:
1145 #if SIZEOF_VOID_P == 8
1151 #if SIZEOF_VOID_P == 4
1155 /* pairs begin at even registers */
1156 if (i8_align
== 8 && margs
->ilen
& 1)
1163 #if SIZEOF_VOID_P == 8
1168 #if SIZEOF_VOID_P == 4
1174 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1178 if (margs
->ilen
> 0)
1179 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1181 if (margs
->flen
> 0)
1182 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1184 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1185 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1187 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1188 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1195 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1199 for (int i
= 0; i
< sig
->param_count
; i
++) {
1200 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1202 case MONO_TYPE_BOOLEAN
:
1203 case MONO_TYPE_CHAR
:
1213 case MONO_TYPE_SZARRAY
:
1214 case MONO_TYPE_CLASS
:
1215 case MONO_TYPE_OBJECT
:
1216 case MONO_TYPE_STRING
:
1217 case MONO_TYPE_VALUETYPE
:
1218 case MONO_TYPE_GENERICINST
:
1219 #if SIZEOF_VOID_P == 8
1223 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1225 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1229 #if SIZEOF_VOID_P == 4
1231 case MONO_TYPE_U8
: {
1232 stackval
*sarg
= &frame
->stack_args
[i
];
1234 /* pairs begin at even registers */
1235 if (i8_align
== 8 && int_i
& 1)
1238 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1240 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1242 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
);
1250 if (ptype
== MONO_TYPE_R4
)
1251 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1253 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1255 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
);
1257 #if SIZEOF_VOID_P == 4
1264 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1268 switch (sig
->ret
->type
) {
1269 case MONO_TYPE_BOOLEAN
:
1270 case MONO_TYPE_CHAR
:
1280 case MONO_TYPE_SZARRAY
:
1281 case MONO_TYPE_CLASS
:
1282 case MONO_TYPE_OBJECT
:
1283 case MONO_TYPE_STRING
:
1286 case MONO_TYPE_VALUETYPE
:
1287 case MONO_TYPE_GENERICINST
:
1288 margs
->retval
= &(frame
->retval
->data
.p
);
1289 margs
->is_float_ret
= 0;
1293 margs
->retval
= &(frame
->retval
->data
.p
);
1294 margs
->is_float_ret
= 1;
1296 case MONO_TYPE_VOID
:
1297 margs
->retval
= NULL
;
1300 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1308 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1310 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1313 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1315 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1319 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1321 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1324 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1325 else if (sig
->hasthis
&& index
== 0)
1326 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1328 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1332 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1334 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1337 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1339 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1343 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1345 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1346 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1347 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1349 switch (type
->type
) {
1350 case MONO_TYPE_GENERICINST
:
1351 if (!MONO_TYPE_IS_REFERENCE (type
))
1352 val
->data
.vt
= storage
;
1354 case MONO_TYPE_VALUETYPE
:
1355 val
->data
.vt
= storage
;
1358 g_assert_not_reached ();
1363 get_interp_to_native_trampoline (void)
1365 static MonoPIFunc trampoline
= NULL
;
1368 if (mono_ee_features
.use_aot_trampolines
) {
1369 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1371 MonoTrampInfo
*info
;
1372 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1373 mono_tramp_info_register (info
, NULL
);
1375 mono_memory_barrier ();
1381 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1383 get_interp_to_native_trampoline () (addr
, ccontext
);
1386 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1388 #pragma optimize ("", off)
1390 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1391 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
, gboolean save_last_error
)
1398 g_assert (!frame
->imethod
);
1400 static MonoPIFunc entry_func
= NULL
;
1402 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1404 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
);
1405 mono_error_assert_ok (error
);
1407 entry_func
= get_interp_to_native_trampoline ();
1409 mono_memory_barrier ();
1412 #ifdef ENABLE_NETCORE
1413 if (save_last_error
) {
1414 mono_marshal_clear_last_error ();
1418 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1419 CallContext ccontext
;
1420 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1423 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1427 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_pinvoke
);
1428 entry_func ((gpointer
) addr
, args
);
1429 if (save_last_error
)
1430 mono_marshal_set_last_error ();
1431 interp_pop_lmf (&ext
);
1433 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1435 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1437 if (ccontext
.stack
!= NULL
)
1438 g_free (ccontext
.stack
);
1440 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1441 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1443 g_free (margs
->iargs
);
1444 g_free (margs
->fargs
);
1447 goto exit_pinvoke
; // prevent unused label warning in some configurations
1452 #pragma optimize ("", on)
1456 * interp_init_delegate:
1458 * Initialize del->interp_method.
1461 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1465 if (del
->interp_method
) {
1466 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1467 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1468 } else if (del
->method
) {
1469 /* Delegate created dynamically */
1470 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1472 /* Created from JITted code */
1473 g_assert_not_reached ();
1476 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1479 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1480 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1481 mono_class_is_abstract (method
->klass
))
1482 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1484 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1485 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1486 const char *name
= method
->name
;
1487 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1489 * When invoking the delegate interp_method is executed directly. If it's an
1490 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1492 * FIXME We should do this later, when we also know the delegate on which the
1493 * target method is called.
1495 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1496 mono_error_assert_ok (error
);
1500 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1501 /* Return any errors from method compilation */
1502 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1503 return_if_nok (error
);
1508 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1511 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1513 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1515 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1516 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1517 /* virtual invoke delegates must not have null check */
1518 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1519 && MONO_HANDLE_IS_NULL (target
)) {
1520 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1525 g_assert (imethod
->method
);
1526 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1527 return_if_nok (error
);
1529 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1531 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1536 * runtime specifies that the implementation of the method is automatically
1537 * provided by the runtime and is primarily used for the methods of delegates.
1539 static MONO_NEVER_INLINE
void
1540 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1542 const char *name
= method
->name
;
1543 mono_class_init_internal (method
->klass
);
1545 if (method
->klass
== mono_defaults
.array_class
) {
1546 if (!strcmp (name
, "UnsafeMov")) {
1547 /* TODO: layout checks */
1548 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1551 if (!strcmp (name
, "UnsafeLoad")) {
1552 ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1555 } else if (mini_class_is_system_array (method
->klass
)) {
1556 MonoObject
*obj
= (MonoObject
*) sp
->data
.p
;
1558 frame
->ex
= mono_get_exception_null_reference ();
1561 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1562 ves_array_set (frame
, sp
, sig
);
1565 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1566 ves_array_get (frame
, sp
, retval
, sig
, TRUE
);
1571 g_error ("Don't know how to exec runtime method %s.%s::%s",
1572 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1578 dump_stack (stackval
*stack
, stackval
*sp
)
1580 stackval
*s
= stack
;
1581 GString
*str
= g_string_new ("");
1584 return g_string_free (str
, FALSE
);
1587 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1590 return g_string_free (str
, FALSE
);
1594 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1596 switch (type
->type
) {
1603 case MONO_TYPE_CHAR
:
1604 case MONO_TYPE_BOOLEAN
:
1605 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1607 case MONO_TYPE_STRING
:
1608 case MONO_TYPE_SZARRAY
:
1609 case MONO_TYPE_CLASS
:
1610 case MONO_TYPE_OBJECT
:
1611 case MONO_TYPE_ARRAY
:
1615 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1617 case MONO_TYPE_VALUETYPE
:
1618 if (m_class_is_enumtype (type
->data
.klass
))
1619 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1621 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1624 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1627 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1632 GString
*res
= g_string_new ("");
1633 mono_type_get_desc (res
, type
, TRUE
);
1634 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1635 g_string_free (res
, TRUE
);
1642 dump_retval (InterpFrame
*inv
)
1644 GString
*str
= g_string_new ("");
1645 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1647 if (ret
->type
!= MONO_TYPE_VOID
)
1648 dump_stackval (str
, inv
->retval
, ret
);
1650 return g_string_free (str
, FALSE
);
1654 dump_args (InterpFrame
*inv
)
1656 GString
*str
= g_string_new ("");
1658 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1660 if (signature
->param_count
== 0 && !signature
->hasthis
)
1661 return g_string_free (str
, FALSE
);
1663 if (signature
->hasthis
) {
1664 MonoMethod
*method
= inv
->imethod
->method
;
1665 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1668 for (i
= 0; i
< signature
->param_count
; ++i
)
1669 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1671 return g_string_free (str
, FALSE
);
1675 #define CHECK_ADD_OVERFLOW(a,b) \
1676 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1677 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1679 #define CHECK_SUB_OVERFLOW(a,b) \
1680 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1681 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1683 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1684 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1686 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1687 (guint32)(a) < (guint32)(b) ? -1 : 0
1689 #define CHECK_ADD_OVERFLOW64(a,b) \
1690 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1691 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1693 #define CHECK_SUB_OVERFLOW64(a,b) \
1694 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1695 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1697 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1698 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1700 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1701 (guint64)(a) < (guint64)(b) ? -1 : 0
1703 #if SIZEOF_VOID_P == 4
1704 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1705 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1707 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1708 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1711 /* Resolves to TRUE if the operands would overflow */
1712 #define CHECK_MUL_OVERFLOW(a,b) \
1713 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1714 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1715 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1716 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1717 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1718 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1719 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1721 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1722 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1723 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1725 #define CHECK_MUL_OVERFLOW64(a,b) \
1726 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1727 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1728 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1729 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1730 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1731 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1732 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1734 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1735 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1736 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1738 #if SIZEOF_VOID_P == 4
1739 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1740 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1742 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1743 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1747 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1750 ThreadContext
*context
= get_context ();
1751 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1752 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1754 MonoMethod
*target_method
= method
;
1762 MonoDomain
*domain
= mono_domain_get ();
1764 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1765 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1766 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1768 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1770 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1774 args
[0].data
.p
= obj
;
1776 args
[0].data
.p
= NULL
;
1777 args
[1].data
.p
= params
;
1778 args
[2].data
.p
= exc
;
1779 args
[3].data
.p
= target_method
;
1781 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1782 mono_error_assert_ok (error
);
1783 init_frame (&frame
, NULL
, imethod
, args
, &result
);
1785 interp_exec_method (&frame
, context
, error
);
1789 *exc
= (MonoObject
*) frame
.ex
;
1792 mono_error_set_exception_instance (error
, frame
.ex
);
1795 return (MonoObject
*)result
.data
.p
;
1799 InterpMethod
*rmethod
;
1803 gpointer
*many_args
;
1806 /* Main function for entering the interpreter from compiled code */
1808 interp_entry (InterpEntryData
*data
)
1811 InterpMethod
*rmethod
;
1812 ThreadContext
*context
;
1816 MonoMethodSignature
*sig
;
1818 gpointer orig_domain
= NULL
, attach_cookie
;
1821 if ((gsize
)data
->rmethod
& 1) {
1823 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1824 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1826 rmethod
= data
->rmethod
;
1828 if (rmethod
->needs_thread_attach
)
1829 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1831 context
= get_context ();
1833 method
= rmethod
->method
;
1834 sig
= mono_method_signature_internal (method
);
1836 // FIXME: Optimize this
1838 //printf ("%s\n", mono_method_full_name (method, 1));
1842 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1844 args
[0].data
.p
= data
->this_arg
;
1847 if (data
->many_args
)
1848 params
= data
->many_args
;
1850 params
= data
->args
;
1851 for (i
= 0; i
< sig
->param_count
; ++i
) {
1852 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1853 if (sig
->params
[i
]->byref
) {
1854 args
[a_index
].data
.p
= params
[i
];
1857 type
= rmethod
->param_types
[i
];
1858 switch (type
->type
) {
1859 case MONO_TYPE_VALUETYPE
:
1860 args
[a_index
].data
.p
= params
[i
];
1862 case MONO_TYPE_GENERICINST
:
1863 if (MONO_TYPE_IS_REFERENCE (type
))
1864 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1866 args
[a_index
].data
.vt
= params
[i
];
1869 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1874 memset (&result
, 0, sizeof (result
));
1875 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1877 type
= rmethod
->rtype
;
1878 switch (type
->type
) {
1879 case MONO_TYPE_GENERICINST
:
1880 if (!MONO_TYPE_IS_REFERENCE (type
))
1881 frame
.retval
->data
.vt
= data
->res
;
1883 case MONO_TYPE_VALUETYPE
:
1884 frame
.retval
->data
.vt
= data
->res
;
1891 interp_exec_method (&frame
, context
, error
);
1893 if (rmethod
->needs_thread_attach
)
1894 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
1896 if (mono_llvm_only
) {
1898 mono_llvm_reraise_exception (frame
.ex
);
1900 g_assert (frame
.ex
== NULL
);
1903 type
= rmethod
->rtype
;
1904 switch (type
->type
) {
1905 case MONO_TYPE_VOID
:
1907 case MONO_TYPE_OBJECT
:
1908 /* No need for a write barrier */
1909 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1911 case MONO_TYPE_GENERICINST
:
1912 if (MONO_TYPE_IS_REFERENCE (type
)) {
1913 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1915 /* Already set before the call */
1918 case MONO_TYPE_VALUETYPE
:
1919 /* Already set before the call */
1922 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1928 do_icall (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
1930 #ifdef ENABLE_NETCORE
1931 if (save_last_error
)
1932 mono_marshal_clear_last_error ();
1936 case MINT_ICALL_V_V
: {
1937 typedef void (*T
)(void);
1942 case MINT_ICALL_V_P
: {
1943 typedef gpointer (*T
)(void);
1946 sp
[-1].data
.p
= func ();
1949 case MINT_ICALL_P_V
: {
1950 typedef void (*T
)(gpointer
);
1952 func (sp
[-1].data
.p
);
1956 case MINT_ICALL_P_P
: {
1957 typedef gpointer (*T
)(gpointer
);
1959 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1962 case MINT_ICALL_PP_V
: {
1963 typedef void (*T
)(gpointer
,gpointer
);
1966 func (sp
[0].data
.p
, sp
[1].data
.p
);
1969 case MINT_ICALL_PP_P
: {
1970 typedef gpointer (*T
)(gpointer
,gpointer
);
1973 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1976 case MINT_ICALL_PPP_V
: {
1977 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
1980 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1983 case MINT_ICALL_PPP_P
: {
1984 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
1987 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
1990 case MINT_ICALL_PPPP_V
: {
1991 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1994 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1997 case MINT_ICALL_PPPP_P
: {
1998 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2001 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2004 case MINT_ICALL_PPPPP_V
: {
2005 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2008 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
2011 case MINT_ICALL_PPPPP_P
: {
2012 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2015 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
);
2018 case MINT_ICALL_PPPPPP_V
: {
2019 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2022 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
);
2025 case MINT_ICALL_PPPPPP_P
: {
2026 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2029 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
);
2033 g_assert_not_reached ();
2036 if (save_last_error
)
2037 mono_marshal_set_last_error ();
2039 /* convert the native representation to the stackval representation */
2041 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2046 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2048 #pragma optimize ("", off)
2050 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
2051 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2054 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
2056 sp
= do_icall (frame
, sig
, op
, sp
, ptr
, save_last_error
);
2058 interp_pop_lmf (&ext
);
2060 goto exit_icall
; // prevent unused label warning in some configurations
2065 #pragma optimize ("", on)
2070 gpointer jit_wrapper
;
2072 MonoFtnDesc
*ftndesc
;
2076 jit_call_cb (gpointer arg
)
2078 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2079 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2080 int pindex
= cb_data
->pindex
;
2081 gpointer
*args
= cb_data
->args
;
2082 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2086 typedef void (*T
)(gpointer
);
2087 T func
= (T
)jit_wrapper
;
2093 typedef void (*T
)(gpointer
, gpointer
);
2094 T func
= (T
)jit_wrapper
;
2096 func (args
[0], &ftndesc
);
2100 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2101 T func
= (T
)jit_wrapper
;
2103 func (args
[0], args
[1], &ftndesc
);
2107 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2108 T func
= (T
)jit_wrapper
;
2110 func (args
[0], args
[1], args
[2], &ftndesc
);
2114 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2115 T func
= (T
)jit_wrapper
;
2117 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2121 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2122 T func
= (T
)jit_wrapper
;
2124 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2128 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2129 T func
= (T
)jit_wrapper
;
2131 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2135 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2136 T func
= (T
)jit_wrapper
;
2138 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2142 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2143 T func
= (T
)jit_wrapper
;
2145 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2149 g_assert_not_reached ();
2154 static MONO_NEVER_INLINE stackval
*
2155 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2157 MonoMethodSignature
*sig
;
2158 MonoFtnDesc ftndesc
;
2159 guint8 res_buf
[256];
2163 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2166 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2167 * by ref and return a return value using an explicit return value argument.
2169 if (!rmethod
->jit_wrapper
) {
2170 MonoMethod
*method
= rmethod
->method
;
2172 sig
= mono_method_signature_internal (method
);
2175 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2176 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2178 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2179 mono_error_assert_ok (error
);
2181 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2182 return_val_if_nok (error
, NULL
);
2185 rmethod
->jit_addr
= addr
;
2186 rmethod
->jit_sig
= sig
;
2187 mono_memory_barrier ();
2188 rmethod
->jit_wrapper
= jit_wrapper
;
2191 sig
= rmethod
->jit_sig
;
2194 sp
-= sig
->param_count
;
2198 ftndesc
.addr
= rmethod
->jit_addr
;
2201 // FIXME: Optimize this
2205 int stack_index
= 0;
2206 if (rmethod
->hasthis
) {
2207 args
[pindex
++] = sp
[0].data
.p
;
2210 type
= rmethod
->rtype
;
2211 if (type
->type
!= MONO_TYPE_VOID
) {
2212 if (MONO_TYPE_ISSTRUCT (type
))
2213 args
[pindex
++] = vt_sp
;
2215 args
[pindex
++] = res_buf
;
2217 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2218 MonoType
*t
= rmethod
->param_types
[i
];
2219 stackval
*sval
= &sp
[stack_index
+ i
];
2220 if (sig
->params
[i
]->byref
) {
2221 args
[pindex
++] = sval
->data
.p
;
2222 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2223 args
[pindex
++] = sval
->data
.p
;
2224 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2225 args
[pindex
++] = &sval
->data
.p
;
2234 case MONO_TYPE_VALUETYPE
:
2235 args
[pindex
++] = &sval
->data
.i
;
2238 case MONO_TYPE_FNPTR
:
2241 case MONO_TYPE_OBJECT
:
2242 args
[pindex
++] = &sval
->data
.p
;
2246 args
[pindex
++] = &sval
->data
.l
;
2249 args
[pindex
++] = &sval
->data
.f_r4
;
2252 args
[pindex
++] = &sval
->data
.f
;
2255 printf ("%s\n", mono_type_full_name (t
));
2256 g_assert_not_reached ();
2261 interp_push_lmf (&ext
, frame
);
2263 JitCallCbData cb_data
;
2264 memset (&cb_data
, 0, sizeof (cb_data
));
2265 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2266 cb_data
.pindex
= pindex
;
2267 cb_data
.args
= args
;
2268 cb_data
.ftndesc
= &ftndesc
;
2270 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2271 /* Catch the exception thrown by the native code using a try-catch */
2272 gboolean thrown
= FALSE
;
2273 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2274 interp_pop_lmf (&ext
);
2276 MonoObject
*obj
= mono_llvm_load_exception ();
2278 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2282 jit_call_cb (&cb_data
);
2283 interp_pop_lmf (&ext
);
2286 MonoType
*rtype
= rmethod
->rtype
;
2287 switch (rtype
->type
) {
2288 case MONO_TYPE_VOID
:
2289 case MONO_TYPE_OBJECT
:
2290 case MONO_TYPE_STRING
:
2291 case MONO_TYPE_CLASS
:
2292 case MONO_TYPE_ARRAY
:
2293 case MONO_TYPE_SZARRAY
:
2297 sp
->data
.p
= *(gpointer
*)res_buf
;
2300 sp
->data
.i
= *(gint8
*)res_buf
;
2303 sp
->data
.i
= *(guint8
*)res_buf
;
2306 sp
->data
.i
= *(gint16
*)res_buf
;
2309 sp
->data
.i
= *(guint16
*)res_buf
;
2312 sp
->data
.i
= *(gint32
*)res_buf
;
2315 sp
->data
.i
= *(guint32
*)res_buf
;
2318 sp
->data
.l
= *(gint64
*)res_buf
;
2321 sp
->data
.l
= *(guint64
*)res_buf
;
2324 sp
->data
.f_r4
= *(float*)res_buf
;
2327 sp
->data
.f
= *(double*)res_buf
;
2329 case MONO_TYPE_TYPEDBYREF
:
2330 case MONO_TYPE_VALUETYPE
:
2331 /* The result was written to vt_sp */
2334 case MONO_TYPE_GENERICINST
:
2335 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2336 sp
->data
.p
= *(gpointer
*)res_buf
;
2338 /* The result was written to vt_sp */
2343 g_print ("%s\n", mono_type_full_name (rtype
));
2344 g_assert_not_reached ();
2351 static MONO_NEVER_INLINE
void
2352 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2355 interp_push_lmf (&ext
, frame
);
2357 interp_pop_lmf (&ext
);
2360 static MONO_NEVER_INLINE
void
2361 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2364 /* Don't push lmf if we have no interp data */
2365 gboolean push_lmf
= frame
->parent
!= NULL
;
2368 /* Use the parent frame as the current frame is not complete yet */
2370 interp_push_lmf (&ext
, frame
->parent
);
2372 mono_interp_transform_method (frame
->imethod
, context
, error
);
2373 frame
->ex
= mono_error_convert_to_exception (error
);
2376 interp_pop_lmf (&ext
);
2379 static MONO_NEVER_INLINE guchar
*
2380 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, guchar
*vt_sp
)
2382 stackval
*first_arg
= sp
- csig
->param_count
;
2385 * We need to have the varargs linearly on the stack so the ArgIterator
2386 * can iterate over them. We pass the signature first and then copy them
2387 * one by one on the vtstack.
2389 *(gpointer
*)vt_sp
= csig
;
2390 vt_sp
+= sizeof (gpointer
);
2392 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2393 int align
, arg_size
;
2394 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2395 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, align
);
2397 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt_sp
, FALSE
);
2401 return (guchar
*)ALIGN_PTR_TO (vt_sp
, MINT_VT_ALIGNMENT
);
2405 * These functions are the entry points into the interpreter from compiled code.
2406 * They are called by the interp_in wrappers. They have the following signature:
2407 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2408 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2409 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2410 * more wrappers then these functions.
2411 * this/static * ret/void * 16 arguments -> 64 functions.
2414 #define MAX_INTERP_ENTRY_ARGS 8
2416 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2417 InterpEntryData data; \
2418 (data).rmethod = (_method); \
2419 (data).res = (_res); \
2420 (data).this_arg = (_this_arg); \
2421 (data).many_args = NULL;
2423 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2424 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2425 interp_entry (&data); \
2427 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2428 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2429 (data).args [0] = arg1; \
2430 interp_entry (&data); \
2432 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2433 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2434 (data).args [0] = arg1; \
2435 (data).args [1] = arg2; \
2436 interp_entry (&data); \
2438 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2439 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2440 (data).args [0] = arg1; \
2441 (data).args [1] = arg2; \
2442 (data).args [2] = arg3; \
2443 interp_entry (&data); \
2445 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2446 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2447 (data).args [0] = arg1; \
2448 (data).args [1] = arg2; \
2449 (data).args [2] = arg3; \
2450 (data).args [3] = arg4; \
2451 interp_entry (&data); \
2453 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2454 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2455 (data).args [0] = arg1; \
2456 (data).args [1] = arg2; \
2457 (data).args [2] = arg3; \
2458 (data).args [3] = arg4; \
2459 (data).args [4] = arg5; \
2460 interp_entry (&data); \
2462 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2463 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2464 (data).args [0] = arg1; \
2465 (data).args [1] = arg2; \
2466 (data).args [2] = arg3; \
2467 (data).args [3] = arg4; \
2468 (data).args [4] = arg5; \
2469 (data).args [5] = arg6; \
2470 interp_entry (&data); \
2472 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2473 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2474 (data).args [0] = arg1; \
2475 (data).args [1] = arg2; \
2476 (data).args [2] = arg3; \
2477 (data).args [3] = arg4; \
2478 (data).args [4] = arg5; \
2479 (data).args [5] = arg6; \
2480 (data).args [6] = arg7; \
2481 interp_entry (&data); \
2483 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2484 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2485 (data).args [0] = arg1; \
2486 (data).args [1] = arg2; \
2487 (data).args [2] = arg3; \
2488 (data).args [3] = arg4; \
2489 (data).args [4] = arg5; \
2490 (data).args [5] = arg6; \
2491 (data).args [6] = arg7; \
2492 (data).args [7] = arg8; \
2493 interp_entry (&data); \
2496 #define ARGLIST0 InterpMethod *rmethod
2497 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2498 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2499 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2500 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2501 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2502 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2503 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2504 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2506 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2507 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2508 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2509 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2510 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2511 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2512 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2513 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2514 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2515 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2516 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2517 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2518 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2519 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2520 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2521 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2522 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2523 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2524 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2525 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2526 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2527 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2528 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2529 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2530 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2531 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2532 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2533 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2534 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2535 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2536 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2537 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2538 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2539 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2540 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2541 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2543 #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
2545 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2546 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2547 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2548 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2550 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2552 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2554 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2555 data
.many_args
= args
;
2556 interp_entry (&data
);
2559 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2561 // inline so we can alloc on stack
2562 #define alloc_storage_for_stackval(s, t, p) do { \
2563 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2564 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2565 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2567 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2569 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2574 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2577 ThreadContext
*context
;
2581 MonoMethodSignature
*sig
;
2582 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2583 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2584 gpointer orig_domain
= NULL
, attach_cookie
;
2587 if (rmethod
->needs_thread_attach
)
2588 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2590 context
= get_context ();
2592 method
= rmethod
->method
;
2593 sig
= mono_method_signature_internal (method
);
2597 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2599 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2601 /* Allocate storage for value types */
2602 for (i
= 0; i
< sig
->param_count
; i
++) {
2603 MonoType
*type
= sig
->params
[i
];
2604 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2607 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2608 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2610 /* Copy the args saved in the trampoline to the frame stack */
2611 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2614 interp_exec_method (&frame
, context
, error
);
2616 if (rmethod
->needs_thread_attach
)
2617 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2620 g_assert (frame
.ex
== NULL
);
2622 /* Write back the return value */
2623 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2629 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2631 g_assert_not_reached ();
2634 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2636 static InterpMethod
*
2637 lookup_method_pointer (gpointer addr
)
2639 MonoDomain
*domain
= mono_domain_get ();
2640 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2641 InterpMethod
*res
= NULL
;
2643 mono_domain_lock (domain
);
2644 if (info
->interp_method_pointer_hash
)
2645 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2646 mono_domain_unlock (domain
);
2651 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2653 interp_no_native_to_managed (void)
2655 g_error ("interpreter: native-to-managed transition not available on this platform");
2660 no_llvmonly_interp_method_pointer (void)
2662 g_assert_not_reached ();
2666 * interp_create_method_pointer_llvmonly:
2668 * Return an ftndesc for entering the interpreter and executing METHOD.
2671 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2673 MonoDomain
*domain
= mono_domain_get ();
2674 gpointer addr
, entry_func
, entry_wrapper
;
2675 MonoMethodSignature
*sig
;
2676 MonoMethod
*wrapper
;
2677 MonoJitDomainInfo
*info
;
2678 InterpMethod
*imethod
;
2680 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2681 return_val_if_nok (error
, NULL
);
2684 if (imethod
->llvmonly_unbox_entry
)
2685 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2687 if (imethod
->jit_entry
)
2688 return (MonoFtnDesc
*)imethod
->jit_entry
;
2691 sig
= mono_method_signature_internal (method
);
2694 * The entry functions need access to the method to call, so we have
2695 * to use a ftndesc. The caller uses a normal signature, while the
2696 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2697 * a gsharedvt_in_sig wrapper.
2699 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2701 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2702 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2703 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2704 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2706 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2707 g_assert_not_reached ();
2708 //entry_func = (gpointer)interp_entry_general;
2709 } else if (sig
->hasthis
) {
2710 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2711 entry_func
= entry_funcs_instance
[sig
->param_count
];
2713 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2715 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2716 entry_func
= entry_funcs_static
[sig
->param_count
];
2718 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2720 g_assert (entry_func
);
2722 /* Encode unbox in the lower bit of imethod */
2723 gpointer entry_arg
= imethod
;
2725 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2726 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2728 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2730 info
= domain_jit_info (domain
);
2731 mono_domain_lock (domain
);
2732 if (!info
->interp_method_pointer_hash
)
2733 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2734 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2735 mono_domain_unlock (domain
);
2737 mono_memory_barrier ();
2739 imethod
->llvmonly_unbox_entry
= addr
;
2741 imethod
->jit_entry
= addr
;
2743 return (MonoFtnDesc
*)addr
;
2747 * interp_create_method_pointer:
2749 * Return a function pointer which can be used to call METHOD using the
2750 * interpreter. Return NULL for methods which are not supported.
2753 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2755 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2757 return (gpointer
)no_llvmonly_interp_method_pointer
;
2758 return (gpointer
)interp_no_native_to_managed
;
2760 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2761 MonoDomain
*domain
= mono_domain_get ();
2762 MonoJitDomainInfo
*info
;
2763 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2766 return (gpointer
)no_llvmonly_interp_method_pointer
;
2768 if (imethod
->jit_entry
)
2769 return imethod
->jit_entry
;
2771 if (compile
&& !imethod
->transformed
) {
2772 /* Return any errors from method compilation */
2773 mono_interp_transform_method (imethod
, get_context (), error
);
2774 return_val_if_nok (error
, NULL
);
2777 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2780 /* The caller should call interp_create_method_pointer_llvmonly */
2781 g_assert_not_reached ();
2783 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2786 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2788 * Interp in wrappers get the argument in the rgctx register. If
2789 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2790 * on that arch the rgctx register is not scratch, so we use a
2791 * separate temp register. We should update the wrappers for this
2792 * if we really care about those architectures (arm).
2794 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2796 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2798 if (entry_wrapper
) {
2799 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2800 entry_func
= (gpointer
)interp_entry_general
;
2801 } else if (sig
->hasthis
) {
2802 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2803 entry_func
= entry_funcs_instance
[sig
->param_count
];
2805 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2807 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2808 entry_func
= entry_funcs_static
[sig
->param_count
];
2810 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2813 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2814 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2815 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2816 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2818 mono_error_cleanup (error
);
2819 error_init_reuse (error
);
2820 if (!mono_native_to_interp_trampoline
) {
2821 if (mono_aot_only
) {
2822 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2824 MonoTrampInfo
*info
;
2825 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2826 mono_tramp_info_register (info
, NULL
);
2829 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2830 /* We need the lmf wrapper only when being called from mixed mode */
2832 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2834 static gpointer cached_func
= NULL
;
2836 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
);
2837 mono_memory_barrier ();
2839 entry_func
= cached_func
;
2844 g_assert (entry_func
);
2845 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2846 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2847 ftndesc
->addr
= entry_func
;
2848 ftndesc
->arg
= imethod
;
2849 mono_error_assert_ok (error
);
2852 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2853 * rgctx register using a trampoline.
2856 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2858 info
= domain_jit_info (domain
);
2859 mono_domain_lock (domain
);
2860 if (!info
->interp_method_pointer_hash
)
2861 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2862 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2863 mono_domain_unlock (domain
);
2865 mono_memory_barrier ();
2866 imethod
->jit_entry
= addr
;
2873 static int opcode_counts
[512];
2875 #define COUNT_OP(op) opcode_counts[op]++
2877 #define COUNT_OP(op)
2881 #define DUMP_INSTR() \
2882 if (tracing > 1) { \
2884 if (sp > frame->stack) { \
2885 ins = dump_stack (frame->stack, sp); \
2887 ins = g_strdup (""); \
2891 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2892 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2893 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2899 #define DUMP_INSTR()
2902 #define INIT_VTABLE(vtable) do { \
2903 if (G_UNLIKELY (!(vtable)->initialized)) { \
2904 mono_runtime_class_init_full ((vtable), error); \
2905 if (!is_ok (error)) \
2906 THROW_EX (mono_error_convert_to_exception (error), ip); \
2910 static MONO_NEVER_INLINE MonoObject
*
2911 mono_interp_new (MonoDomain
* domain
, MonoClass
* klass
)
2914 MonoObject
* const object
= mono_object_new_checked (domain
, klass
, error
);
2915 mono_error_cleanup (error
); // FIXME: do not swallow the error
2920 #ifndef DISABLE_REMOTING
2921 MONO_NEVER_INLINE
// To reduce stack.
2924 mono_interp_load_remote_field (
2925 InterpMethod
* imethod
,
2930 g_assert (o
); // Caller checks and throws exception properly.
2933 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
2935 #ifndef DISABLE_REMOTING
2937 if (mono_object_is_transparent_proxy (o
)) {
2938 MonoClass
* const klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
2940 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
2941 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2944 addr
= (char*)o
+ field
->offset
;
2945 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
2949 #ifndef DISABLE_REMOTING
2950 MONO_NEVER_INLINE
// To reduce stack.
2952 guchar
* // Return new vt_sp instead of take-address.
2953 mono_interp_load_remote_field_vt (
2954 InterpMethod
* imethod
,
2960 g_assert (o
); // Caller checks and throws exception properly.
2963 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
2964 MonoClass
* klass
= mono_class_from_mono_type_internal (field
->type
);
2965 int const i32
= mono_class_value_size (klass
, NULL
);
2967 #ifndef DISABLE_REMOTING
2969 if (mono_object_is_transparent_proxy (o
)) {
2970 klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
2972 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
2973 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
2976 addr
= (char*)o
+ field
->offset
;
2977 sp
[-1].data
.p
= vt_sp
;
2978 memcpy (vt_sp
, addr
, i32
);
2979 return vt_sp
+ ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
2982 static MONO_NEVER_INLINE gboolean
2983 mono_interp_isinst (MonoObject
* object
, MonoClass
* klass
)
2986 const gboolean isinst
= mono_object_isinst_checked (object
, klass
, error
) != NULL
;
2987 mono_error_cleanup (error
); // FIXME: do not swallow the error
2994 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2995 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2996 * should be followed:
2997 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2998 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2999 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
3000 * to be allocated to the C stack and not to registers.
3001 * - minimalize the number of MonoObject* locals/arguments.
3005 #define frame_objref(frame) (frame)->o
3007 #define frame_objref(frame) o
3010 // This function is outlined to help save stack in its caller, on the premise
3011 // that it is relatively rarely called. This also lets it use alloca.
3012 static MONO_NEVER_INLINE
void
3013 mono_interp_calli_nat_dynamic_pinvoke (
3014 // Parameters are sorted by name.
3015 InterpFrame
* child_frame
,
3017 ThreadContext
* context
,
3018 MonoMethodSignature
* csignature
,
3021 // Recompute to limit parameters, which can also contribute to caller stack.
3022 InterpMethod
* const imethod
= child_frame
->parent
->imethod
;
3024 g_assert (imethod
->method
->dynamic
&& csignature
->pinvoke
);
3026 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3027 MonoMarshalSpec
** mspecs
= g_newa (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3028 memset (mspecs
, 0, sizeof (MonoMarshalSpec
*) * (csignature
->param_count
+ 1));
3030 MonoMethodPInvoke iinfo
;
3031 memset (&iinfo
, 0, sizeof (iinfo
));
3033 MonoMethod
* m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &iinfo
, mspecs
, code
);
3035 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3037 mono_metadata_free_marshal_spec (mspecs
[i
]);
3041 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
3042 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3045 interp_exec_method (child_frame
, context
, error
);
3048 // Leave is split into pieces in order to consume less stack,
3049 // but not have to change how exception handling macros access labels and locals.
3050 static MONO_NEVER_INLINE MonoException
*
3051 mono_interp_leave (InterpFrame
* child_frame
)
3055 * We need for mono_thread_get_undeniable_exception to be able to unwind
3056 * to check the abort threshold. For this to work we use child_frame as a
3057 * dummy frame that is stored in the lmf and serves as the transition frame
3059 do_icall_wrapper (child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
3061 return (MonoException
*)tmp_sp
.data
.p
;
3064 static MONO_NEVER_INLINE
void
3065 mono_interp_newobj_vt (
3066 // Parameters are sorted by name and parameter list is minimized
3067 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3068 // use no stack in caller).
3069 InterpFrame
* child_frame
,
3070 ThreadContext
* context
,
3073 stackval
* const sp
= child_frame
->stack_args
;
3075 stackval valuetype_this
;
3077 memset (&valuetype_this
, 0, sizeof (stackval
));
3078 sp
->data
.p
= &valuetype_this
;
3080 // FIXME It is unfortunate to outline a recursive case as it
3081 // increases its stack usage. We do this however as it conserves
3082 // stack for all the other recursive cases.
3083 interp_exec_method (child_frame
, context
, error
);
3085 CHECK_RESUME_STATE_IN_HELPER_FUNCTION (context
, );
3087 *sp
= valuetype_this
;
3090 static MONO_NEVER_INLINE MonoException
*
3091 mono_interp_newobj (
3092 // Parameters are sorted by name and parameter list is minimized
3093 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3094 // use no stack in caller).
3095 InterpFrame
* child_frame
,
3096 ThreadContext
* context
,
3100 InterpFrame
* const frame
= child_frame
->parent
;
3101 InterpMethod
* const imethod
= frame
->imethod
;
3102 stackval
* const sp
= child_frame
->stack_args
;
3104 MonoObject
* o
= NULL
; // See the comment about GC safety above.
3105 stackval valuetype_this
;
3108 MonoClass
* const newobj_class
= child_frame
->imethod
->method
->klass
;
3109 /*if (profiling_classes) {
3110 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3112 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3116 * First arg is the object.
3118 if (m_class_is_valuetype (newobj_class
)) {
3119 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
3120 memset (&valuetype_this
, 0, sizeof (stackval
));
3121 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3123 valuetype_this
.data
.p
= vt_sp
;
3125 sp
->data
.p
= &valuetype_this
;
3128 if (newobj_class
!= mono_defaults
.string_class
) {
3129 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
3130 if (!is_ok (error
) || !mono_runtime_class_init_full (vtable
, error
)) {
3131 MonoException
* const exc
= mono_error_convert_to_exception (error
);
3136 frame_objref (frame
) = mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
3137 mono_error_cleanup (error
); // FIXME: do not swallow the error
3138 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION
;
3139 sp
->data
.o
= frame_objref (frame
);
3140 #ifndef DISABLE_REMOTING
3141 if (mono_object_is_transparent_proxy (frame_objref (frame
))) {
3142 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
->imethod
->method
, error
);
3143 mono_error_assert_ok (error
);
3144 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
3145 mono_error_assert_ok (error
);
3150 child_frame
->retval
= &retval
;
3154 interp_exec_method (child_frame
, context
, error
);
3156 CHECK_RESUME_STATE_IN_HELPER_FUNCTION (context
, NULL
);
3159 * a constructor returns void, but we need to return the object we created
3161 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
3162 *sp
= valuetype_this
;
3163 } else if (newobj_class
== mono_defaults
.string_class
) {
3166 sp
->data
.o
= frame_objref (frame
);
3171 static MONO_NEVER_INLINE
void
3172 mono_interp_enum_hasflag (stackval
* sp
, MonoClass
* klass
)
3174 guint64 a_val
= 0, b_val
= 0;
3176 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &b_val
, FALSE
);
3177 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &a_val
, FALSE
);
3178 sp
->data
.i
= (a_val
& b_val
) == b_val
;
3181 static MONO_NEVER_INLINE
int
3182 mono_interp_box_nullable (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3184 InterpMethod
* const imethod
= frame
->imethod
;
3185 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3187 int size
= mono_class_value_size (c
, NULL
);
3189 guint16 offset
= * (guint16
*)(ip
+ 2);
3190 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
3191 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
3193 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
3194 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3196 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3198 return pop_vt_sp
? size
: 0;
3201 static MONO_NEVER_INLINE
int
3202 mono_interp_store_remote_field_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3204 InterpMethod
* const imethod
= frame
->imethod
;
3205 MonoClassField
*field
;
3207 MonoObject
* const o
= sp
[-2].data
.o
;
3209 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3210 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
3211 int const i32
= mono_class_value_size (klass
, NULL
);
3213 #ifndef DISABLE_REMOTING
3214 if (mono_object_is_transparent_proxy (o
)) {
3215 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3216 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
3217 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3220 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3222 return ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3226 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3227 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3228 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3229 * to return error information.
3232 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
)
3234 InterpFrame child_frame
;
3235 GSList
*finally_ips
= NULL
;
3236 const guint16
*endfinally_ip
= NULL
;
3237 const guint16
*ip
= NULL
;
3239 InterpMethod
*imethod
= NULL
;
3241 gint tracing
= global_tracing
;
3242 unsigned char *vtalloc
;
3244 unsigned char *vt_sp
;
3245 unsigned char *locals
= NULL
;
3246 #if USE_COMPUTED_GOTO
3247 static void * const in_labels
[] = {
3248 #define OPDEF(a,b,c,d) &&LAB_ ## a,
3249 #include "mintops.def"
3255 debug_enter (frame
, &tracing
);
3258 imethod
= frame
->imethod
;
3259 if (!imethod
->transformed
) {
3261 char *mn
= mono_method_full_name (imethod
->method
, TRUE
);
3262 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
3267 do_transform_method (frame
, context
);
3269 THROW_EX (frame
->ex
, NULL
);
3270 EXCEPTION_CHECKPOINT
;
3274 frame
->stack
= (stackval
*)g_alloca (imethod
->alloca_size
);
3277 ip
= clause_args
->start_with_ip
;
3278 if (clause_args
->base_frame
) {
3279 frame
->stack
= (stackval
*)g_alloca (imethod
->alloca_size
);
3280 memcpy (frame
->stack
, clause_args
->base_frame
->stack
, imethod
->alloca_size
);
3284 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
3288 locals
= frame_locals (frame
);
3289 child_frame
.parent
= frame
;
3291 if (clause_args
&& clause_args
->filter_exception
) {
3292 sp
->data
.p
= clause_args
->filter_exception
;
3296 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3299 * using while (ip < end) may result in a 15% performance drop,
3300 * but it may be useful for debug
3304 /* g_assert (sp >= frame->stack); */
3305 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
3307 MINT_IN_SWITCH (*ip
) {
3308 MINT_IN_CASE(MINT_INITLOCALS
)
3309 memset (frame_locals (frame
), 0, imethod
->locals_size
);
3312 MINT_IN_CASE(MINT_NOP
)
3315 MINT_IN_CASE(MINT_NIY
)
3316 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3318 MINT_IN_CASE(MINT_BREAK
)
3320 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3322 MINT_IN_CASE(MINT_BREAKPOINT
)
3326 MINT_IN_CASE(MINT_LDNULL
)
3331 MINT_IN_CASE(MINT_ARGLIST
)
3332 g_assert (frame
->varargs
);
3334 *(gpointer
*)sp
->data
.p
= frame
->varargs
;
3335 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3339 MINT_IN_CASE(MINT_VTRESULT
) {
3340 int ret_size
= * (guint16
*)(ip
+ 1);
3341 unsigned char *ret_vt_sp
= vt_sp
;
3342 vt_sp
-= READ32(ip
+ 2);
3344 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3345 sp
[-1].data
.p
= vt_sp
;
3346 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3351 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3352 MINT_IN_CASE(MINT_LDC_I4_M1
)
3355 MINT_IN_CASE(MINT_LDC_I4_0
)
3358 MINT_IN_CASE(MINT_LDC_I4_1
)
3361 MINT_IN_CASE(MINT_LDC_I4_2
)
3364 MINT_IN_CASE(MINT_LDC_I4_3
)
3367 MINT_IN_CASE(MINT_LDC_I4_4
)
3370 MINT_IN_CASE(MINT_LDC_I4_5
)
3373 MINT_IN_CASE(MINT_LDC_I4_6
)
3376 MINT_IN_CASE(MINT_LDC_I4_7
)
3379 MINT_IN_CASE(MINT_LDC_I4_8
)
3382 MINT_IN_CASE(MINT_LDC_I4_S
)
3383 sp
->data
.i
= *(const short *)(ip
+ 1);
3387 MINT_IN_CASE(MINT_LDC_I4
)
3389 sp
->data
.i
= READ32 (ip
);
3393 MINT_IN_CASE(MINT_LDC_I8
)
3395 sp
->data
.l
= READ64 (ip
);
3399 MINT_IN_CASE(MINT_LDC_I8_S
)
3400 sp
->data
.l
= *(const short *)(ip
+ 1);
3404 MINT_IN_CASE(MINT_LDC_R4
) {
3408 sp
->data
.f_r4
= * (float *)&val
;
3413 MINT_IN_CASE(MINT_LDC_R8
)
3414 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3418 MINT_IN_CASE(MINT_DUP
)
3423 MINT_IN_CASE(MINT_DUP_VT
) {
3424 int const i32
= READ32 (ip
+ 1);
3426 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3427 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3432 MINT_IN_CASE(MINT_POP
) {
3433 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
3435 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
3440 MINT_IN_CASE(MINT_JMP
) {
3441 InterpMethod
*new_method
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3443 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3444 MONO_PROFILER_RAISE (method_tail_call
, (imethod
->method
, new_method
->method
));
3446 if (!new_method
->transformed
) {
3447 MONO_API_ERROR_INIT (error
);
3450 mono_interp_transform_method (new_method
, context
, error
);
3451 frame
->ex
= mono_error_convert_to_exception (error
);
3456 const gboolean realloc_frame
= new_method
->alloca_size
> imethod
->alloca_size
;
3457 imethod
= frame
->imethod
= new_method
;
3459 * We allocate the stack frame from scratch and store the arguments in the
3460 * locals again since it's possible for the caller stack frame to be smaller
3461 * than the callee stack frame (at the interp level)
3463 if (realloc_frame
) {
3464 frame
->stack
= (stackval
*)g_alloca (imethod
->alloca_size
);
3465 memset (frame
->stack
, 0, imethod
->alloca_size
);
3468 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
3472 locals
= frame_locals (frame
);
3476 MINT_IN_CASE(MINT_CALLI
) {
3477 MonoMethodSignature
*csignature
;
3481 csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3484 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
3487 child_frame
.retval
= sp
;
3488 /* decrement by the actual number of args */
3489 sp
-= csignature
->param_count
;
3490 if (csignature
->hasthis
)
3492 child_frame
.stack_args
= sp
;
3494 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3495 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
3496 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3499 if (csignature
->hasthis
) {
3500 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3502 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3503 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3504 sp
[0].data
.p
= unboxed
;
3508 interp_exec_method (&child_frame
, context
, error
);
3510 CHECK_RESUME_STATE (context
);
3512 /* need to handle typedbyref ... */
3513 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3514 *sp
= *child_frame
.retval
;
3519 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3520 gpointer target_ip
= sp
[-1].data
.p
;
3521 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3522 int opcode
= *(guint16
*)(ip
+ 2);
3523 gboolean save_last_error
= *(guint16
*)(ip
+ 3);
3528 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3529 EXCEPTION_CHECKPOINT
;
3530 CHECK_RESUME_STATE (context
);
3534 MINT_IN_CASE(MINT_CALLI_NAT
) {
3538 MonoMethodSignature
* csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3542 guchar
* const code
= (guchar
*)sp
->data
.p
;
3543 child_frame
.imethod
= NULL
;
3546 child_frame
.retval
= sp
;
3547 /* decrement by the actual number of args */
3548 sp
-= csignature
->param_count
;
3549 if (csignature
->hasthis
)
3551 child_frame
.stack_args
= sp
;
3553 if (imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3554 mono_interp_calli_nat_dynamic_pinvoke (&child_frame
, code
, context
, csignature
, error
);
3556 const gboolean save_last_error
= *(guint16
*)(ip
- 3 + 2);
3557 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
, save_last_error
);
3560 CHECK_RESUME_STATE (context
);
3562 /* need to handle typedbyref ... */
3563 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3564 *sp
= *child_frame
.retval
;
3569 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3570 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3571 MonoObject
*this_arg
;
3572 InterpMethod
*target_imethod
;
3575 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3579 target_imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3580 slot
= *(gint16
*)(ip
+ 2);
3583 child_frame
.retval
= sp
;
3585 /* decrement by the actual number of args */
3586 sp
-= target_imethod
->param_count
+ target_imethod
->hasthis
;
3587 child_frame
.stack_args
= sp
;
3589 this_arg
= (MonoObject
*)sp
->data
.p
;
3591 child_frame
.imethod
= get_virtual_method_fast (target_imethod
, this_arg
->vtable
, slot
);
3592 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3594 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3595 sp
[0].data
.p
= unboxed
;
3598 interp_exec_method (&child_frame
, context
, error
);
3600 CHECK_RESUME_STATE (context
);
3602 const gboolean is_void
= ip
[-3] == MINT_VCALLVIRT_FAST
;
3604 /* need to handle typedbyref ... */
3605 *sp
= *child_frame
.retval
;
3610 MINT_IN_CASE(MINT_CALL_VARARG
) {
3611 int num_varargs
= 0;
3612 MonoMethodSignature
*csig
;
3616 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3617 /* The real signature for vararg calls */
3618 csig
= (MonoMethodSignature
*) imethod
->data_items
[* (guint16
*) (ip
+ 2)];
3619 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3620 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
3621 child_frame
.varargs
= (char*) vt_sp
;
3622 vt_sp
= copy_varargs_vtstack (csig
, sp
, vt_sp
);
3626 child_frame
.retval
= sp
;
3628 /* decrement by the actual number of args */
3629 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
3630 child_frame
.stack_args
= sp
;
3632 interp_exec_method (&child_frame
, context
, error
);
3634 CHECK_RESUME_STATE (context
);
3636 if (csig
->ret
->type
!= MONO_TYPE_VOID
) {
3637 *sp
= *child_frame
.retval
;
3642 MINT_IN_CASE(MINT_CALL
)
3643 MINT_IN_CASE(MINT_VCALL
)
3644 MINT_IN_CASE(MINT_CALLVIRT
)
3645 MINT_IN_CASE(MINT_VCALLVIRT
) {
3649 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3652 child_frame
.retval
= sp
;
3654 /* decrement by the actual number of args */
3655 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
;
3656 child_frame
.stack_args
= sp
;
3658 const gboolean is_virtual
= ip
[-2] == MINT_CALLVIRT
|| ip
[-2] == MINT_VCALLVIRT
;
3660 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3662 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
->vtable
);
3663 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3665 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3666 sp
[0].data
.p
= unboxed
;
3670 interp_exec_method (&child_frame
, context
, error
);
3672 CHECK_RESUME_STATE (context
);
3674 const gboolean is_void
= ip
[-2] == MINT_VCALL
|| ip
[-2] == MINT_VCALLVIRT
;
3676 /* need to handle typedbyref ... */
3677 *sp
= *child_frame
.retval
;
3682 MINT_IN_CASE(MINT_JIT_CALL
) {
3683 InterpMethod
*rmethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3684 MONO_API_ERROR_INIT (error
);
3686 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3687 if (!is_ok (error
)) {
3688 MonoException
*ex
= mono_error_convert_to_exception (error
);
3693 CHECK_RESUME_STATE (context
);
3695 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3700 MINT_IN_CASE(MINT_CALLRUN
) {
3701 MonoMethod
*target_method
= (MonoMethod
*) imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3702 MonoMethodSignature
*sig
= (MonoMethodSignature
*) imethod
->data_items
[* (guint16
*)(ip
+ 2)];
3708 sp
-= sig
->param_count
;
3712 ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3714 THROW_EX (frame
->ex
, ip
);
3716 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3723 MINT_IN_CASE(MINT_RET
)
3725 *frame
->retval
= *sp
;
3726 if (sp
> frame
->stack
)
3727 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3729 MINT_IN_CASE(MINT_RET_VOID
)
3730 if (sp
> frame
->stack
)
3731 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (imethod
->method
, TRUE
));
3733 MINT_IN_CASE(MINT_RET_VT
) {
3734 int const i32
= READ32 (ip
+ 1);
3736 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3737 if (sp
> frame
->stack
)
3738 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3741 MINT_IN_CASE(MINT_BR_S
)
3742 ip
+= (short) *(ip
+ 1);
3744 MINT_IN_CASE(MINT_BR
)
3745 ip
+= (gint32
) READ32(ip
+ 1);
3747 #define ZEROP_S(datamem, op) \
3749 if (sp->data.datamem op 0) \
3750 ip += * (gint16 *)(ip + 1); \
3754 #define ZEROP(datamem, op) \
3756 if (sp->data.datamem op 0) \
3757 ip += (gint32)READ32(ip + 1); \
3761 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3764 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3767 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3770 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3773 MINT_IN_CASE(MINT_BRFALSE_I4
)
3776 MINT_IN_CASE(MINT_BRFALSE_I8
)
3779 MINT_IN_CASE(MINT_BRFALSE_R4
)
3782 MINT_IN_CASE(MINT_BRFALSE_R8
)
3785 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3788 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3791 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
3794 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3797 MINT_IN_CASE(MINT_BRTRUE_I4
)
3800 MINT_IN_CASE(MINT_BRTRUE_I8
)
3803 MINT_IN_CASE(MINT_BRTRUE_R4
)
3806 MINT_IN_CASE(MINT_BRTRUE_R8
)
3809 #define CONDBR_S(cond) \
3812 ip += * (gint16 *)(ip + 1); \
3815 #define BRELOP_S(datamem, op) \
3816 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3818 #define CONDBR(cond) \
3821 ip += (gint32)READ32(ip + 1); \
3825 #define BRELOP(datamem, op) \
3826 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3828 MINT_IN_CASE(MINT_BEQ_I4_S
)
3831 MINT_IN_CASE(MINT_BEQ_I8_S
)
3834 MINT_IN_CASE(MINT_BEQ_R4_S
)
3835 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3837 MINT_IN_CASE(MINT_BEQ_R8_S
)
3838 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3840 MINT_IN_CASE(MINT_BEQ_I4
)
3843 MINT_IN_CASE(MINT_BEQ_I8
)
3846 MINT_IN_CASE(MINT_BEQ_R4
)
3847 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3849 MINT_IN_CASE(MINT_BEQ_R8
)
3850 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3852 MINT_IN_CASE(MINT_BGE_I4_S
)
3855 MINT_IN_CASE(MINT_BGE_I8_S
)
3858 MINT_IN_CASE(MINT_BGE_R4_S
)
3859 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3861 MINT_IN_CASE(MINT_BGE_R8_S
)
3862 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3864 MINT_IN_CASE(MINT_BGE_I4
)
3867 MINT_IN_CASE(MINT_BGE_I8
)
3870 MINT_IN_CASE(MINT_BGE_R4
)
3871 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3873 MINT_IN_CASE(MINT_BGE_R8
)
3874 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3876 MINT_IN_CASE(MINT_BGT_I4_S
)
3879 MINT_IN_CASE(MINT_BGT_I8_S
)
3882 MINT_IN_CASE(MINT_BGT_R4_S
)
3883 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3885 MINT_IN_CASE(MINT_BGT_R8_S
)
3886 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3888 MINT_IN_CASE(MINT_BGT_I4
)
3891 MINT_IN_CASE(MINT_BGT_I8
)
3894 MINT_IN_CASE(MINT_BGT_R4
)
3895 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3897 MINT_IN_CASE(MINT_BGT_R8
)
3898 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3900 MINT_IN_CASE(MINT_BLT_I4_S
)
3903 MINT_IN_CASE(MINT_BLT_I8_S
)
3906 MINT_IN_CASE(MINT_BLT_R4_S
)
3907 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3909 MINT_IN_CASE(MINT_BLT_R8_S
)
3910 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3912 MINT_IN_CASE(MINT_BLT_I4
)
3915 MINT_IN_CASE(MINT_BLT_I8
)
3918 MINT_IN_CASE(MINT_BLT_R4
)
3919 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3921 MINT_IN_CASE(MINT_BLT_R8
)
3922 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3924 MINT_IN_CASE(MINT_BLE_I4_S
)
3927 MINT_IN_CASE(MINT_BLE_I8_S
)
3930 MINT_IN_CASE(MINT_BLE_R4_S
)
3931 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3933 MINT_IN_CASE(MINT_BLE_R8_S
)
3934 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3936 MINT_IN_CASE(MINT_BLE_I4
)
3939 MINT_IN_CASE(MINT_BLE_I8
)
3942 MINT_IN_CASE(MINT_BLE_R4
)
3943 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3945 MINT_IN_CASE(MINT_BLE_R8
)
3946 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3948 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3951 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3954 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
3955 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3957 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3958 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3960 MINT_IN_CASE(MINT_BNE_UN_I4
)
3963 MINT_IN_CASE(MINT_BNE_UN_I8
)
3966 MINT_IN_CASE(MINT_BNE_UN_R4
)
3967 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3969 MINT_IN_CASE(MINT_BNE_UN_R8
)
3970 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3973 #define BRELOP_S_CAST(datamem, op, type) \
3975 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3976 ip += * (gint16 *)(ip + 1); \
3980 #define BRELOP_CAST(datamem, op, type) \
3982 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3983 ip += (gint32)READ32(ip + 1); \
3987 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3988 BRELOP_S_CAST(i
, >=, guint32
);
3990 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3991 BRELOP_S_CAST(l
, >=, guint64
);
3993 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
3994 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3996 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3997 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3999 MINT_IN_CASE(MINT_BGE_UN_I4
)
4000 BRELOP_CAST(i
, >=, guint32
);
4002 MINT_IN_CASE(MINT_BGE_UN_I8
)
4003 BRELOP_CAST(l
, >=, guint64
);
4005 MINT_IN_CASE(MINT_BGE_UN_R4
)
4006 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4008 MINT_IN_CASE(MINT_BGE_UN_R8
)
4009 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4011 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
4012 BRELOP_S_CAST(i
, >, guint32
);
4014 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
4015 BRELOP_S_CAST(l
, >, guint64
);
4017 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
4018 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4020 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
4021 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4023 MINT_IN_CASE(MINT_BGT_UN_I4
)
4024 BRELOP_CAST(i
, >, guint32
);
4026 MINT_IN_CASE(MINT_BGT_UN_I8
)
4027 BRELOP_CAST(l
, >, guint64
);
4029 MINT_IN_CASE(MINT_BGT_UN_R4
)
4030 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4032 MINT_IN_CASE(MINT_BGT_UN_R8
)
4033 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4035 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
4036 BRELOP_S_CAST(i
, <=, guint32
);
4038 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
4039 BRELOP_S_CAST(l
, <=, guint64
);
4041 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
4042 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4044 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
4045 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4047 MINT_IN_CASE(MINT_BLE_UN_I4
)
4048 BRELOP_CAST(i
, <=, guint32
);
4050 MINT_IN_CASE(MINT_BLE_UN_I8
)
4051 BRELOP_CAST(l
, <=, guint64
);
4053 MINT_IN_CASE(MINT_BLE_UN_R4
)
4054 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4056 MINT_IN_CASE(MINT_BLE_UN_R8
)
4057 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4059 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
4060 BRELOP_S_CAST(i
, <, guint32
);
4062 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
4063 BRELOP_S_CAST(l
, <, guint64
);
4065 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
4066 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4068 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
4069 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4071 MINT_IN_CASE(MINT_BLT_UN_I4
)
4072 BRELOP_CAST(i
, <, guint32
);
4074 MINT_IN_CASE(MINT_BLT_UN_I8
)
4075 BRELOP_CAST(l
, <, guint64
);
4077 MINT_IN_CASE(MINT_BLT_UN_R4
)
4078 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4080 MINT_IN_CASE(MINT_BLT_UN_R8
)
4081 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4083 MINT_IN_CASE(MINT_SWITCH
) {
4085 const unsigned short *st
;
4091 if ((guint32
)sp
->data
.i
< n
) {
4093 ip
+= 2 * (guint32
)sp
->data
.i
;
4094 offset
= READ32 (ip
);
4101 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
4102 NULL_CHECK (sp
[-1].data
.p
);
4104 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
4106 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
4107 NULL_CHECK (sp
[-1].data
.p
);
4109 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
4111 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
4112 NULL_CHECK (sp
[-1].data
.p
);
4114 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
4116 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
4117 NULL_CHECK (sp
[-1].data
.p
);
4119 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
4121 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
4122 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
4123 NULL_CHECK (sp
[-1].data
.p
);
4125 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
4127 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
4128 NULL_CHECK (sp
[-1].data
.p
);
4130 #ifdef NO_UNALIGNED_ACCESS
4131 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4132 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
4135 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
4137 MINT_IN_CASE(MINT_LDIND_I
) {
4138 guint16 offset
= * (guint16
*)(ip
+ 1);
4139 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
4143 MINT_IN_CASE(MINT_LDIND_I8
) {
4144 guint16 offset
= * (guint16
*)(ip
+ 1);
4145 #ifdef NO_UNALIGNED_ACCESS
4146 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
4147 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
4150 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
4154 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
4155 NULL_CHECK (sp
[-1].data
.p
);
4157 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
4159 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
4160 NULL_CHECK (sp
[-1].data
.p
);
4162 #ifdef NO_UNALIGNED_ACCESS
4163 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4164 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
4167 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
4169 MINT_IN_CASE(MINT_LDIND_REF
)
4171 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4173 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
4174 NULL_CHECK (sp
[-1].data
.p
);
4176 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4179 MINT_IN_CASE(MINT_STIND_REF
)
4182 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
4184 MINT_IN_CASE(MINT_STIND_I1
)
4187 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
4189 MINT_IN_CASE(MINT_STIND_I2
)
4192 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
4194 MINT_IN_CASE(MINT_STIND_I4
)
4197 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
4199 MINT_IN_CASE(MINT_STIND_I
)
4202 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
4204 MINT_IN_CASE(MINT_STIND_I8
)
4207 #ifdef NO_UNALIGNED_ACCESS
4208 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4209 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
4212 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
4214 MINT_IN_CASE(MINT_STIND_R4
)
4217 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
4219 MINT_IN_CASE(MINT_STIND_R8
)
4222 #ifdef NO_UNALIGNED_ACCESS
4223 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4224 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
4227 * (double *) sp
->data
.p
= sp
[1].data
.f
;
4229 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
4232 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
4234 #define BINOP(datamem, op) \
4236 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4238 MINT_IN_CASE(MINT_ADD_I4
)
4241 MINT_IN_CASE(MINT_ADD_I8
)
4244 MINT_IN_CASE(MINT_ADD_R4
)
4247 MINT_IN_CASE(MINT_ADD_R8
)
4250 MINT_IN_CASE(MINT_ADD1_I4
)
4254 MINT_IN_CASE(MINT_ADD1_I8
)
4258 MINT_IN_CASE(MINT_SUB_I4
)
4261 MINT_IN_CASE(MINT_SUB_I8
)
4264 MINT_IN_CASE(MINT_SUB_R4
)
4267 MINT_IN_CASE(MINT_SUB_R8
)
4270 MINT_IN_CASE(MINT_SUB1_I4
)
4274 MINT_IN_CASE(MINT_SUB1_I8
)
4278 MINT_IN_CASE(MINT_MUL_I4
)
4281 MINT_IN_CASE(MINT_MUL_I8
)
4284 MINT_IN_CASE(MINT_MUL_R4
)
4287 MINT_IN_CASE(MINT_MUL_R8
)
4290 MINT_IN_CASE(MINT_DIV_I4
)
4291 if (sp
[-1].data
.i
== 0)
4292 THROW_EX_DIV_ZERO (ip
);
4293 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4297 MINT_IN_CASE(MINT_DIV_I8
)
4298 if (sp
[-1].data
.l
== 0)
4299 THROW_EX_DIV_ZERO (ip
);
4300 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4304 MINT_IN_CASE(MINT_DIV_R4
)
4307 MINT_IN_CASE(MINT_DIV_R8
)
4311 #define BINOP_CAST(datamem, op, type) \
4313 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4315 MINT_IN_CASE(MINT_DIV_UN_I4
)
4316 if (sp
[-1].data
.i
== 0)
4317 THROW_EX_DIV_ZERO (ip
);
4318 BINOP_CAST(i
, /, guint32
);
4320 MINT_IN_CASE(MINT_DIV_UN_I8
)
4321 if (sp
[-1].data
.l
== 0)
4322 THROW_EX_DIV_ZERO (ip
);
4323 BINOP_CAST(l
, /, guint64
);
4325 MINT_IN_CASE(MINT_REM_I4
)
4326 if (sp
[-1].data
.i
== 0)
4327 THROW_EX_DIV_ZERO (ip
);
4328 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4332 MINT_IN_CASE(MINT_REM_I8
)
4333 if (sp
[-1].data
.l
== 0)
4334 THROW_EX_DIV_ZERO (ip
);
4335 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4339 MINT_IN_CASE(MINT_REM_R4
)
4340 /* FIXME: what do we actually do here? */
4342 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4345 MINT_IN_CASE(MINT_REM_R8
)
4346 /* FIXME: what do we actually do here? */
4348 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4351 MINT_IN_CASE(MINT_REM_UN_I4
)
4352 if (sp
[-1].data
.i
== 0)
4353 THROW_EX_DIV_ZERO (ip
);
4354 BINOP_CAST(i
, %, guint32
);
4356 MINT_IN_CASE(MINT_REM_UN_I8
)
4357 if (sp
[-1].data
.l
== 0)
4358 THROW_EX_DIV_ZERO (ip
);
4359 BINOP_CAST(l
, %, guint64
);
4361 MINT_IN_CASE(MINT_AND_I4
)
4364 MINT_IN_CASE(MINT_AND_I8
)
4367 MINT_IN_CASE(MINT_OR_I4
)
4370 MINT_IN_CASE(MINT_OR_I8
)
4373 MINT_IN_CASE(MINT_XOR_I4
)
4376 MINT_IN_CASE(MINT_XOR_I8
)
4380 #define SHIFTOP(datamem, op) \
4382 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4385 MINT_IN_CASE(MINT_SHL_I4
)
4388 MINT_IN_CASE(MINT_SHL_I8
)
4391 MINT_IN_CASE(MINT_SHR_I4
)
4394 MINT_IN_CASE(MINT_SHR_I8
)
4397 MINT_IN_CASE(MINT_SHR_UN_I4
)
4399 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4402 MINT_IN_CASE(MINT_SHR_UN_I8
)
4404 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4407 MINT_IN_CASE(MINT_NEG_I4
)
4408 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4411 MINT_IN_CASE(MINT_NEG_I8
)
4412 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4415 MINT_IN_CASE(MINT_NEG_R4
)
4416 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4419 MINT_IN_CASE(MINT_NEG_R8
)
4420 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4423 MINT_IN_CASE(MINT_NOT_I4
)
4424 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4427 MINT_IN_CASE(MINT_NOT_I8
)
4428 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4431 MINT_IN_CASE(MINT_CONV_I1_I4
)
4432 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4435 MINT_IN_CASE(MINT_CONV_I1_I8
)
4436 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4439 MINT_IN_CASE(MINT_CONV_I1_R4
)
4440 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4443 MINT_IN_CASE(MINT_CONV_I1_R8
)
4444 /* without gint32 cast, C compiler is allowed to use undefined
4445 * behaviour if data.f is bigger than >255. See conv.fpint section
4447 * > The conversion truncates; that is, the fractional part
4448 * > is discarded. The behavior is undefined if the truncated
4449 * > value cannot be represented in the destination type.
4451 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4454 MINT_IN_CASE(MINT_CONV_U1_I4
)
4455 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4458 MINT_IN_CASE(MINT_CONV_U1_I8
)
4459 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4462 MINT_IN_CASE(MINT_CONV_U1_R4
)
4463 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4466 MINT_IN_CASE(MINT_CONV_U1_R8
)
4467 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4470 MINT_IN_CASE(MINT_CONV_I2_I4
)
4471 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4474 MINT_IN_CASE(MINT_CONV_I2_I8
)
4475 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4478 MINT_IN_CASE(MINT_CONV_I2_R4
)
4479 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4482 MINT_IN_CASE(MINT_CONV_I2_R8
)
4483 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4486 MINT_IN_CASE(MINT_CONV_U2_I4
)
4487 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4490 MINT_IN_CASE(MINT_CONV_U2_I8
)
4491 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4494 MINT_IN_CASE(MINT_CONV_U2_R4
)
4495 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4498 MINT_IN_CASE(MINT_CONV_U2_R8
)
4499 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4502 MINT_IN_CASE(MINT_CONV_I4_R4
)
4503 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4506 MINT_IN_CASE(MINT_CONV_I4_R8
)
4507 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4510 MINT_IN_CASE(MINT_CONV_U4_I8
)
4511 MINT_IN_CASE(MINT_CONV_I4_I8
)
4512 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4515 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4516 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4519 MINT_IN_CASE(MINT_CONV_U4_R4
)
4520 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4521 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4523 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4527 MINT_IN_CASE(MINT_CONV_U4_R8
)
4528 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4529 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
4531 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4535 MINT_IN_CASE(MINT_CONV_I8_I4
)
4536 sp
[-1].data
.l
= sp
[-1].data
.i
;
4539 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4540 sp
[-2].data
.l
= sp
[-2].data
.i
;
4543 MINT_IN_CASE(MINT_CONV_I8_U4
)
4544 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4547 MINT_IN_CASE(MINT_CONV_I8_R4
)
4548 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4551 MINT_IN_CASE(MINT_CONV_I8_R8
)
4552 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4555 MINT_IN_CASE(MINT_CONV_R4_I4
)
4556 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4559 MINT_IN_CASE(MINT_CONV_R4_I8
)
4560 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4563 MINT_IN_CASE(MINT_CONV_R4_R8
)
4564 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4567 MINT_IN_CASE(MINT_CONV_R8_I4
)
4568 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4571 MINT_IN_CASE(MINT_CONV_R8_I8
)
4572 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4575 MINT_IN_CASE(MINT_CONV_R8_R4
)
4576 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4579 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4580 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4583 MINT_IN_CASE(MINT_CONV_U8_I4
)
4584 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
4587 MINT_IN_CASE(MINT_CONV_U8_R4
)
4588 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4589 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
4591 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4595 MINT_IN_CASE(MINT_CONV_U8_R8
)
4596 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4597 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
4599 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4603 MINT_IN_CASE(MINT_CPOBJ
) {
4604 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4605 g_assert (m_class_is_valuetype (c
));
4606 /* if this assertion fails, we need to add a write barrier */
4607 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4608 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4613 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4614 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4615 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4620 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4621 int size
= READ32(ip
+ 1);
4623 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4624 sp
[-1].data
.p
= vt_sp
;
4625 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4628 MINT_IN_CASE(MINT_LDSTR
)
4629 sp
->data
.p
= imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4633 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4634 MonoString
*s
= NULL
;
4635 guint32 strtoken
= (guint32
)(gsize
)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4637 MonoMethod
*method
= imethod
->method
;
4638 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4639 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4640 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4641 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4643 g_assert_not_reached ();
4650 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4651 MonoClass
*newobj_class
;
4652 guint32 token
= * (guint16
*)(ip
+ 1);
4653 guint16 param_count
= * (guint16
*)(ip
+ 2);
4655 newobj_class
= (MonoClass
*) imethod
->data_items
[token
];
4658 sp
->data
.o
= ves_array_create (imethod
->domain
, newobj_class
, param_count
, sp
, error
);
4660 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4666 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
4668 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 3)];
4669 INIT_VTABLE (vtable
);
4671 MonoObject
* o
= NULL
; // See the comment about GC safety above.
4672 guint16 param_count
;
4673 guint16 imethod_index
= *(guint16
*) (ip
+ 1);
4675 const gboolean is_inlined
= imethod_index
== 0xffff;
4677 param_count
= *(guint16
*)(ip
+ 2);
4681 memmove (sp
+ 1 + is_inlined
, sp
, param_count
* sizeof (stackval
));
4684 frame_objref (frame
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4685 if (G_UNLIKELY (!frame_objref (frame
))) {
4686 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4687 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4690 sp
[0].data
.o
= frame_objref (frame
);
4692 sp
[1].data
.o
= frame_objref (frame
);
4693 sp
+= param_count
+ 2;
4695 InterpMethod
*ctor_method
= (InterpMethod
*) imethod
->data_items
[imethod_index
];
4698 child_frame
.imethod
= ctor_method
;
4699 child_frame
.stack_args
= sp
;
4701 interp_exec_method (&child_frame
, context
, error
);
4702 CHECK_RESUME_STATE (context
);
4703 sp
[0].data
.o
= frame_objref (frame
);
4710 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4711 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4713 // This is split up to:
4715 // - keep exception handling and resume mostly in the main function
4718 child_frame
.imethod
= (InterpMethod
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4719 guint16
const param_count
= *(guint16
*)(ip
+ 2);
4723 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
4725 child_frame
.stack_args
= sp
;
4726 gboolean
const vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4728 memset (vt_sp
, 0, *(guint16
*)(ip
+ 3));
4732 interp_exec_method (&child_frame
, context
, error
);
4734 CHECK_RESUME_STATE (context
);
4739 mono_interp_newobj_vt (&child_frame
, context
, error
);
4740 CHECK_RESUME_STATE (context
);
4746 MINT_IN_CASE(MINT_NEWOBJ
) {
4748 // This is split up to:
4750 // - keep exception handling and resume mostly in the main function
4754 guint32
const token
= * (guint16
*)(ip
+ 1);
4755 ip
+= 2; // FIXME: Do this after throw?
4757 child_frame
.ip
= NULL
;
4758 child_frame
.ex
= NULL
;
4760 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[token
];
4761 MonoMethodSignature
* const csig
= mono_method_signature_internal (child_frame
.imethod
->method
);
4763 g_assert (csig
->hasthis
);
4764 if (csig
->param_count
) {
4765 sp
-= csig
->param_count
;
4766 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
4769 child_frame
.stack_args
= sp
;
4771 MonoException
* const exc
= mono_interp_newobj (&child_frame
, context
, error
, vt_sp
);
4774 CHECK_RESUME_STATE (context
);
4778 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
4784 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
4785 MonoMethodSignature
*csig
;
4789 token
= * (guint16
*)(ip
+ 1);
4792 InterpMethod
*cmethod
= (InterpMethod
*)imethod
->data_items
[token
];
4793 csig
= mono_method_signature_internal (cmethod
->method
);
4795 g_assert (csig
->hasthis
);
4796 sp
-= csig
->param_count
;
4798 gpointer arg0
= sp
[0].data
.p
;
4800 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
4801 *byreference_this
= arg0
;
4803 /* Followed by a VTRESULT opcode which will push the result on the stack */
4807 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4808 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4809 sp
[-1].data
.p
= *byreference_this
;
4813 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
4815 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
4820 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
4822 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
4827 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
4829 MonoObject
*obj
= sp
[0].data
.o
;
4830 sp
[0].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
4835 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
4836 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
4837 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
4839 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4841 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
4843 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
4845 isinst
= mono_interp_isinst (o
, c
); // FIXME: do not swallow the error
4851 gboolean
const isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
4853 sp
[-1].data
.p
= NULL
;
4855 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4861 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
4862 MINT_IN_CASE(MINT_ISINST_COMMON
) {
4863 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above
4865 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4866 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
4869 gboolean
const isinst_instr
= *ip
== MINT_ISINST_COMMON
;
4871 sp
[-1].data
.p
= NULL
;
4873 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4879 MINT_IN_CASE(MINT_CASTCLASS
)
4880 MINT_IN_CASE(MINT_ISINST
) {
4881 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above
4883 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4884 if (!mono_interp_isinst (o
, c
)) { // FIXME: do not swallow the error
4885 gboolean
const isinst_instr
= *ip
== MINT_ISINST
;
4887 sp
[-1].data
.p
= NULL
;
4889 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4895 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4896 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4899 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4900 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4903 MINT_IN_CASE(MINT_UNBOX
) {
4904 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above
4906 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4908 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
4909 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4911 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
4915 MINT_IN_CASE(MINT_THROW
)
4918 sp
->data
.p
= mono_get_exception_null_reference ();
4920 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4922 MINT_IN_CASE(MINT_CHECKPOINT
)
4923 /* Do synchronous checking of abort requests */
4924 EXCEPTION_CHECKPOINT
;
4927 MINT_IN_CASE(MINT_SAFEPOINT
)
4928 /* Do synchronous checking of abort requests */
4929 EXCEPTION_CHECKPOINT
;
4930 /* Poll safepoint */
4931 mono_threads_safepoint ();
4934 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
) {
4935 sp
[-1].data
.p
= (char*)sp
[-1].data
.o
+ * (guint16
*)(ip
+ 1);
4939 MINT_IN_CASE(MINT_LDFLDA
) {
4940 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
4942 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4946 MINT_IN_CASE(MINT_CKNULL_N
) {
4947 /* Same as CKNULL, but further down the stack */
4948 int const n
= *(guint16
*)(ip
+ 1);
4949 MonoObject
* const o
= sp
[-n
].data
.o
; // See the comment about GC safety above.
4955 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4956 MonoObject* const o = sp [-1].data.o; \
4959 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4961 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4965 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4967 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4968 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4969 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4970 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4971 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4972 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4973 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
4974 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4975 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4976 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4977 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4978 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4980 MINT_IN_CASE(MINT_LDFLD_VT
) {
4981 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
4984 int size
= READ32(ip
+ 2);
4985 sp
[-1].data
.p
= vt_sp
;
4986 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), size
);
4987 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4992 MINT_IN_CASE(MINT_LDRMFLD
) {
4993 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
4995 mono_interp_load_remote_field (imethod
, o
, ip
, sp
);
4999 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
5000 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
5002 vt_sp
= mono_interp_load_remote_field_vt (imethod
, o
, ip
, sp
, vt_sp
);
5007 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5008 MonoObject* const o = sp [-2].data.o; /* See the comment about GC safety above. */ \
5012 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
5014 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
5018 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5020 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
5021 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
5022 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
5023 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
5024 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
5025 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
5026 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
5027 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
5028 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
5029 MINT_IN_CASE(MINT_STFLD_O
) {
5030 MonoObject
* const o
= sp
[-2].data
.o
; // See the comment about GC safety above.
5033 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.o
);
5037 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5038 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5040 MINT_IN_CASE(MINT_STFLD_VT
) {
5041 MonoObject
* const o
= sp
[-2].data
.o
; // See the comment about GC safety above.
5045 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 2)];
5046 int const i32
= mono_class_value_size (klass
, NULL
);
5048 guint16 offset
= * (guint16
*)(ip
+ 1);
5049 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
5051 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5055 MINT_IN_CASE(MINT_STRMFLD
) {
5056 MonoClassField
*field
;
5058 MonoObject
* const o
= sp
[-2].data
.o
; // See the comment about GC safety above.
5061 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5064 #ifndef DISABLE_REMOTING
5065 if (mono_object_is_transparent_proxy (o
)) {
5066 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
5067 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
5068 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5071 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
5076 MINT_IN_CASE(MINT_STRMFLD_VT
)
5078 NULL_CHECK (sp
[-2].data
.o
);
5079 vt_sp
-= mono_interp_store_remote_field_vt (frame
, ip
, sp
, error
);
5084 MINT_IN_CASE(MINT_LDSFLDA
) {
5085 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5086 INIT_VTABLE (vtable
);
5087 sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
5093 MINT_IN_CASE(MINT_LDSSFLDA
) {
5094 guint32 offset
= READ32(ip
+ 1);
5095 sp
->data
.p
= mono_get_special_static_data (offset
);
5101 /* We init class here to preserve cctor order */
5102 #define LDSFLD(datamem, fieldtype) { \
5103 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
5104 INIT_VTABLE (vtable); \
5105 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
5110 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
5111 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
5112 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
5113 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
5114 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
5115 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
5116 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
5117 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
5118 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5119 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5121 MINT_IN_CASE(MINT_LDSFLD_VT
) {
5122 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5123 INIT_VTABLE (vtable
);
5126 gpointer addr
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
5127 int const i32
= READ32 (ip
+ 3);
5128 memcpy (vt_sp
, addr
, i32
);
5129 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5135 #define LDTSFLD(datamem, fieldtype) { \
5136 MonoInternalThread *thread = mono_thread_internal_current (); \
5137 guint32 offset = READ32 (ip + 1); \
5138 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5139 sp[0].data.datamem = *(fieldtype*)addr; \
5143 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
5144 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
5145 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
5146 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
5147 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
5148 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
5149 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
5150 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
5151 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5152 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5154 MINT_IN_CASE(MINT_LDSSFLD
) {
5155 guint32 offset
= READ32(ip
+ 2);
5156 gpointer addr
= mono_get_special_static_data (offset
);
5157 MonoClassField
*field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5158 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
5163 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
5164 guint32 offset
= READ32(ip
+ 1);
5165 gpointer addr
= mono_get_special_static_data (offset
);
5167 int size
= READ32 (ip
+ 3);
5168 memcpy (vt_sp
, addr
, size
);
5170 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5175 #define STSFLD(datamem, fieldtype) { \
5176 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
5177 INIT_VTABLE (vtable); \
5179 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
5183 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5184 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5185 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5186 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5187 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5188 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5189 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5190 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5191 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5192 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5194 MINT_IN_CASE(MINT_STSFLD_VT
) {
5195 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5196 INIT_VTABLE (vtable
);
5197 int const i32
= READ32 (ip
+ 3);
5198 gpointer addr
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
5200 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5201 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5207 #define STTSFLD(datamem, fieldtype) { \
5208 MonoInternalThread *thread = mono_thread_internal_current (); \
5209 guint32 offset = READ32 (ip + 1); \
5210 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5212 *(fieldtype*)addr = sp[0].data.datamem; \
5216 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5217 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5218 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5219 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5220 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5221 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5222 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5223 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5224 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5225 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5227 MINT_IN_CASE(MINT_STSSFLD
) {
5228 guint32 offset
= READ32(ip
+ 2);
5229 gpointer addr
= mono_get_special_static_data (offset
);
5230 MonoClassField
*field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5232 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5236 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5237 guint32 offset
= READ32(ip
+ 1);
5238 gpointer addr
= mono_get_special_static_data (offset
);
5240 int size
= READ32 (ip
+ 3);
5241 memcpy (addr
, sp
->data
.vt
, size
);
5242 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5247 MINT_IN_CASE(MINT_STOBJ_VT
) {
5249 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5251 size
= mono_class_value_size (c
, NULL
);
5252 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5253 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5257 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5258 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5260 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5263 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5264 if (sp
[-1].data
.i
< 0)
5266 sp
[-1].data
.l
= sp
[-1].data
.i
;
5269 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5270 if (sp
[-1].data
.l
< 0)
5274 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5275 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5279 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5280 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5282 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5285 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5286 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5288 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5291 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5292 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
5294 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5297 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
)
5298 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT64
)
5300 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5303 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5304 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5306 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5309 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5310 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5312 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5315 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5316 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5318 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5321 MINT_IN_CASE(MINT_BOX
) {
5322 MonoObject
* o
; // See the comment about GC safety above.
5323 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5325 frame_objref (frame
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5327 guint16 offset
= * (guint16
*)(ip
+ 2);
5329 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (frame_objref (frame
)), FALSE
);
5331 sp
[-1 - offset
].data
.p
= frame_objref (frame
);
5336 MINT_IN_CASE(MINT_BOX_VT
) {
5337 MonoObject
* o
; // See the comment about GC safety above.
5338 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5339 MonoClass
* const c
= vtable
->klass
;
5341 int size
= mono_class_value_size (c
, NULL
);
5343 guint16 offset
= * (guint16
*)(ip
+ 2);
5344 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
5345 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
5347 frame_objref (frame
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5348 mono_value_copy_internal (mono_object_get_data (frame_objref (frame
)), sp
[-1 - offset
].data
.p
, c
);
5350 sp
[-1 - offset
].data
.p
= frame_objref (frame
);
5351 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5358 MINT_IN_CASE(MINT_BOX_NULLABLE
)
5360 vt_sp
-= mono_interp_box_nullable (frame
, ip
, sp
, error
);
5364 MINT_IN_CASE(MINT_NEWARR
) {
5365 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5366 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5367 if (!is_ok (error
)) {
5368 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5370 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5372 /*if (profiling_classes) {
5373 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5375 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5380 MINT_IN_CASE(MINT_LDLEN
) {
5381 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
5383 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5387 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5388 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
5390 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 1);
5391 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5395 MINT_IN_CASE(MINT_GETCHR
) {
5397 s
= (MonoString
*)sp
[-2].data
.p
;
5399 int const i32
= sp
[-1].data
.i
;
5400 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5401 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5403 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5407 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5408 guint8
* const span
= (guint8
*) sp
[-2].data
.p
;
5409 const int index
= sp
[-1].data
.i
;
5414 const gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 2);
5416 const gint32 length
= *(gint32
*) (span
+ offset_length
);
5417 if (index
< 0 || index
>= length
)
5418 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5420 const gsize element_size
= (gsize
) *(gint16
*) (ip
+ 1);
5421 const gsize offset_pointer
= (gsize
) *(gint16
*) (ip
+ 3);
5423 const gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5424 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5429 MINT_IN_CASE(MINT_STRLEN
) {
5431 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
5433 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5436 MINT_IN_CASE(MINT_ARRAY_RANK
) {
5437 MonoObject
* const o
= sp
[-1].data
.o
; // See the comment about GC safety above.
5439 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
5443 MINT_IN_CASE(MINT_LDELEMA_FAST
) {
5444 /* No bounds, one direction */
5445 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
5447 gint32
const index
= sp
[-1].data
.i
;
5448 if (index
>= ao
->max_length
)
5449 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5450 gint32
const size
= READ32 (ip
+ 1);
5451 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
5457 MINT_IN_CASE(MINT_LDELEMA
)
5458 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5460 guint16 numargs
= *(guint16
*) (ip
+ 2);
5464 MonoObject
* const o
= sp
[0].data
.o
; // See the comment about GC safety above.
5467 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[*(guint16
*) (ip
- 3 + 1)];
5468 const gboolean needs_typecheck
= ip
[-3] == MINT_LDELEMA_TC
;
5469 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
5471 THROW_EX (frame
->ex
, ip
);
5476 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
5477 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
5478 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
5479 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
5480 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
5481 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
5482 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
5483 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
5484 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
5485 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
5486 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
5487 MINT_IN_CASE(MINT_LDELEM_VT
) {
5493 o
= (MonoArray
*)sp
[0].data
.p
;
5496 aindex
= sp
[1].data
.i
;
5497 if (aindex
>= mono_array_length_internal (o
))
5498 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5501 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5504 case MINT_LDELEM_I1
:
5505 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
5507 case MINT_LDELEM_U1
:
5508 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
5510 case MINT_LDELEM_I2
:
5511 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
5513 case MINT_LDELEM_U2
:
5514 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
5517 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
5519 case MINT_LDELEM_I4
:
5520 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
5522 case MINT_LDELEM_U4
:
5523 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
5525 case MINT_LDELEM_I8
:
5526 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
5528 case MINT_LDELEM_R4
:
5529 sp
[0].data
.f_r4
= mono_array_get_fast (o
, float, aindex
);
5531 case MINT_LDELEM_R8
:
5532 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
5534 case MINT_LDELEM_REF
:
5535 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
5537 case MINT_LDELEM_VT
: {
5538 int const i32
= READ32 (ip
+ 1);
5539 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5540 sp
[0].data
.vt
= vt_sp
;
5541 // Copying to vtstack. No wbarrier needed
5542 memcpy (sp
[0].data
.vt
, src_addr
, i32
);
5543 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5555 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
5556 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
5557 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
5558 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
5559 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
5560 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
5561 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
5562 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
5563 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
5564 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
5565 MINT_IN_CASE(MINT_STELEM_VT
) {
5570 MonoObject
* const o
= sp
[0].data
.o
; // See the comment about GC safety above.
5573 aindex
= sp
[1].data
.i
;
5574 if (aindex
>= mono_array_length_internal ((MonoArray
*)o
))
5575 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5579 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
5581 case MINT_STELEM_I1
:
5582 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
5584 case MINT_STELEM_U1
:
5585 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
5587 case MINT_STELEM_I2
:
5588 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
5590 case MINT_STELEM_U2
:
5591 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
5593 case MINT_STELEM_I4
:
5594 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
5596 case MINT_STELEM_I8
:
5597 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
5599 case MINT_STELEM_R4
:
5600 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f_r4
);
5602 case MINT_STELEM_R8
:
5603 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
5605 case MINT_STELEM_REF
: {
5606 if (sp
[2].data
.p
) {
5607 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
5608 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5610 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5612 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5615 case MINT_STELEM_VT
: {
5616 MonoClass
*klass_vt
= (MonoClass
*)imethod
->data_items
[*(guint16
*) (ip
+ 1)];
5617 int const i32
= READ32 (ip
+ 2);
5618 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5620 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5621 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5632 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5633 if (sp
[-1].data
.i
< 0)
5637 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5638 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5640 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5643 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5644 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5646 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5649 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5650 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
)
5652 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5655 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5656 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
5658 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5661 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5662 if (sp
[-1].data
.i
< 0)
5666 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5667 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5669 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5672 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5673 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
)
5675 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5678 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5679 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
5681 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5684 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5685 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5689 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
5690 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
5694 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
5695 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
5697 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5700 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
5701 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
5703 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5706 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
5707 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
5709 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5712 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
5713 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
5715 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5718 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
5719 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
5723 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
5724 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
5726 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
5729 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
5730 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
5732 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
5735 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
5736 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
5740 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
5741 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
5745 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
5746 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
5748 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5751 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
5752 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
5754 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5757 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
5758 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
5760 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5763 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
5764 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
5766 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5769 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
5770 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
5774 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
5775 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
5777 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
5780 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
5781 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
5783 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
5786 MINT_IN_CASE(MINT_CKFINITE
)
5787 if (!mono_isfinite (sp
[-1].data
.f
))
5788 THROW_EX (mono_get_exception_arithmetic (), ip
);
5791 MINT_IN_CASE(MINT_MKREFANY
) {
5792 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5794 /* The value address is on the stack */
5795 gpointer addr
= sp
[-1].data
.p
;
5796 /* Push the typedref value on the stack */
5797 sp
[-1].data
.p
= vt_sp
;
5798 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5800 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5802 tref
->type
= m_class_get_byval_arg (c
);
5808 MINT_IN_CASE(MINT_REFANYTYPE
) {
5809 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5810 MonoType
*type
= tref
->type
;
5812 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5813 sp
[-1].data
.p
= vt_sp
;
5815 *(gpointer
*)sp
[-1].data
.p
= type
;
5819 MINT_IN_CASE(MINT_REFANYVAL
) {
5820 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5821 gpointer addr
= tref
->value
;
5823 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5824 if (c
!= tref
->klass
)
5825 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5827 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5829 sp
[-1].data
.p
= addr
;
5833 MINT_IN_CASE(MINT_LDTOKEN
)
5836 * (gpointer
*)sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5840 MINT_IN_CASE(MINT_ADD_OVF_I4
)
5841 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5845 MINT_IN_CASE(MINT_ADD_OVF_I8
)
5846 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5850 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
5851 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5853 BINOP_CAST(i
, +, guint32
);
5855 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
5856 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5858 BINOP_CAST(l
, +, guint64
);
5860 MINT_IN_CASE(MINT_MUL_OVF_I4
)
5861 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5865 MINT_IN_CASE(MINT_MUL_OVF_I8
)
5866 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5870 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
5871 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5873 BINOP_CAST(i
, *, guint32
);
5875 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
5876 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5878 BINOP_CAST(l
, *, guint64
);
5880 MINT_IN_CASE(MINT_SUB_OVF_I4
)
5881 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5885 MINT_IN_CASE(MINT_SUB_OVF_I8
)
5886 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5890 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
5891 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5893 BINOP_CAST(i
, -, guint32
);
5895 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
5896 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5898 BINOP_CAST(l
, -, guint64
);
5900 MINT_IN_CASE(MINT_START_ABORT_PROT
)
5901 mono_threads_begin_abort_protected_block ();
5904 MINT_IN_CASE(MINT_ENDFINALLY
) {
5906 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
5908 // After mono_threads_end_abort_protected_block to conserve stack.
5909 const int clause_index
= *ip
;
5911 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
5914 g_assert (sp
>= frame
->stack
);
5918 ip
= (const guint16
*)finally_ips
->data
;
5919 finally_ips
= g_slist_remove (finally_ips
, ip
);
5920 /* Throw abort after the last finally block to avoid confusing EH */
5921 if (pending_abort
&& !finally_ips
)
5922 EXCEPTION_CHECKPOINT
;
5923 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5924 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5931 MINT_IN_CASE(MINT_LEAVE
)
5932 MINT_IN_CASE(MINT_LEAVE_S
)
5933 MINT_IN_CASE(MINT_LEAVE_CHECK
)
5934 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
5936 // Leave is split into pieces in order to consume less stack,
5937 // but not have to change how exception handling macros access labels and locals.
5939 g_assert (sp
>= frame
->stack
);
5944 gboolean
const check
= opcode
== MINT_LEAVE_CHECK
|| opcode
== MINT_LEAVE_S_CHECK
;
5946 if (check
&& imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
5947 child_frame
.parent
= frame
;
5948 child_frame
.imethod
= NULL
;
5949 MonoException
*abort_exc
= mono_interp_leave (&child_frame
);
5951 THROW_EX (abort_exc
, frame
->ip
);
5954 opcode
= *ip
; // Refetch to avoid register/stack pressure.
5955 gboolean
const short_offset
= opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
;
5956 ip
+= short_offset
? (short)*(ip
+ 1) : (gint32
)READ32 (ip
+ 1);
5958 GSList
*old_list
= finally_ips
;
5959 MonoMethod
*method
= imethod
->method
;
5962 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- imethod
->code
);
5964 // FIXME Null check for imethod follows deref.
5965 if (imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5966 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5969 guint32
const ip_offset
= frame
->ip
- imethod
->code
;
5971 if (endfinally_ip
!= NULL
)
5972 finally_ips
= g_slist_prepend (finally_ips
, (void *)endfinally_ip
);
5974 for (int i
= imethod
->num_clauses
- 1; i
>= 0; i
--) {
5975 MonoExceptionClause
* const clause
= &imethod
->clauses
[i
];
5976 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- imethod
->code
)))) {
5977 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5978 ip
= imethod
->code
+ clause
->handler_offset
;
5979 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5982 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
5988 endfinally_ip
= NULL
;
5990 if (old_list
!= finally_ips
&& finally_ips
) {
5991 ip
= (const guint16
*)finally_ips
->data
;
5992 finally_ips
= g_slist_remove (finally_ips
, ip
);
5993 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5994 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
5995 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5996 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6003 MINT_IN_CASE(MINT_ICALL_V_V
)
6004 MINT_IN_CASE(MINT_ICALL_V_P
)
6005 MINT_IN_CASE(MINT_ICALL_P_V
)
6006 MINT_IN_CASE(MINT_ICALL_P_P
)
6007 MINT_IN_CASE(MINT_ICALL_PP_V
)
6008 MINT_IN_CASE(MINT_ICALL_PP_P
)
6009 MINT_IN_CASE(MINT_ICALL_PPP_V
)
6010 MINT_IN_CASE(MINT_ICALL_PPP_P
)
6011 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
6012 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
6013 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
6014 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
6015 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
6016 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
6018 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, imethod
->data_items
[*(guint16
*)(ip
+ 1)], FALSE
);
6019 EXCEPTION_CHECKPOINT
;
6020 CHECK_RESUME_STATE (context
);
6023 MINT_IN_CASE(MINT_MONO_LDPTR
)
6024 sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 1)];
6028 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
6029 sp
->data
.o
= mono_interp_new (imethod
->domain
, (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)]); // FIXME: do not swallow the error
6033 MINT_IN_CASE(MINT_MONO_FREE
)
6036 g_error ("that doesn't seem right");
6037 g_free (sp
->data
.p
);
6039 MINT_IN_CASE(MINT_MONO_RETOBJ
)
6042 stackval_from_data (mono_method_signature_internal (imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
6043 mono_method_signature_internal (imethod
->method
)->pinvoke
);
6044 if (sp
> frame
->stack
)
6045 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
6047 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
6048 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
6052 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
6054 mono_memory_barrier ();
6057 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
6058 sp
->data
.p
= mono_domain_get ();
6062 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
6063 if (G_UNLIKELY (ss_enabled
)) {
6064 typedef void (*T
) (void);
6068 void *tramp
= mini_get_single_step_trampoline ();
6069 mono_memory_barrier ();
6070 ss_tramp
= (T
)tramp
;
6074 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6075 * the address of that instruction is stored as the seq point address.
6080 * Use the same trampoline as the JIT. This ensures that
6081 * the debugger has the context for the last interpreter
6084 do_debugger_tramp (ss_tramp
, frame
);
6086 CHECK_RESUME_STATE (context
);
6090 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
6091 /* Just a placeholder for a breakpoint */
6094 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
6095 typedef void (*T
) (void);
6098 void *tramp
= mini_get_breakpoint_trampoline ();
6099 mono_memory_barrier ();
6100 bp_tramp
= (T
)tramp
;
6105 /* Use the same trampoline as the JIT */
6106 do_debugger_tramp (bp_tramp
, frame
);
6108 CHECK_RESUME_STATE (context
);
6114 #define RELOP(datamem, op) \
6116 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6119 #define RELOP_FP(datamem, op, noorder) \
6121 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6122 sp [-1].data.i = noorder; \
6124 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6127 MINT_IN_CASE(MINT_CEQ_I4
)
6130 MINT_IN_CASE(MINT_CEQ0_I4
)
6131 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
6134 MINT_IN_CASE(MINT_CEQ_I8
)
6137 MINT_IN_CASE(MINT_CEQ_R4
)
6138 RELOP_FP(f_r4
, ==, 0);
6140 MINT_IN_CASE(MINT_CEQ_R8
)
6143 MINT_IN_CASE(MINT_CNE_I4
)
6146 MINT_IN_CASE(MINT_CNE_I8
)
6149 MINT_IN_CASE(MINT_CNE_R4
)
6150 RELOP_FP(f_r4
, !=, 1);
6152 MINT_IN_CASE(MINT_CNE_R8
)
6155 MINT_IN_CASE(MINT_CGT_I4
)
6158 MINT_IN_CASE(MINT_CGT_I8
)
6161 MINT_IN_CASE(MINT_CGT_R4
)
6162 RELOP_FP(f_r4
, >, 0);
6164 MINT_IN_CASE(MINT_CGT_R8
)
6167 MINT_IN_CASE(MINT_CGE_I4
)
6170 MINT_IN_CASE(MINT_CGE_I8
)
6173 MINT_IN_CASE(MINT_CGE_R4
)
6174 RELOP_FP(f_r4
, >=, 0);
6176 MINT_IN_CASE(MINT_CGE_R8
)
6180 #define RELOP_CAST(datamem, op, type) \
6182 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6185 MINT_IN_CASE(MINT_CGE_UN_I4
)
6186 RELOP_CAST(l
, >=, guint32
);
6188 MINT_IN_CASE(MINT_CGE_UN_I8
)
6189 RELOP_CAST(l
, >=, guint64
);
6192 MINT_IN_CASE(MINT_CGT_UN_I4
)
6193 RELOP_CAST(i
, >, guint32
);
6195 MINT_IN_CASE(MINT_CGT_UN_I8
)
6196 RELOP_CAST(l
, >, guint64
);
6198 MINT_IN_CASE(MINT_CGT_UN_R4
)
6199 RELOP_FP(f_r4
, >, 1);
6201 MINT_IN_CASE(MINT_CGT_UN_R8
)
6204 MINT_IN_CASE(MINT_CLT_I4
)
6207 MINT_IN_CASE(MINT_CLT_I8
)
6210 MINT_IN_CASE(MINT_CLT_R4
)
6211 RELOP_FP(f_r4
, <, 0);
6213 MINT_IN_CASE(MINT_CLT_R8
)
6216 MINT_IN_CASE(MINT_CLT_UN_I4
)
6217 RELOP_CAST(i
, <, guint32
);
6219 MINT_IN_CASE(MINT_CLT_UN_I8
)
6220 RELOP_CAST(l
, <, guint64
);
6222 MINT_IN_CASE(MINT_CLT_UN_R4
)
6223 RELOP_FP(f_r4
, <, 1);
6225 MINT_IN_CASE(MINT_CLT_UN_R8
)
6228 MINT_IN_CASE(MINT_CLE_I4
)
6231 MINT_IN_CASE(MINT_CLE_I8
)
6234 MINT_IN_CASE(MINT_CLE_UN_I4
)
6235 RELOP_CAST(l
, <=, guint32
);
6237 MINT_IN_CASE(MINT_CLE_UN_I8
)
6238 RELOP_CAST(l
, <=, guint64
);
6240 MINT_IN_CASE(MINT_CLE_R4
)
6241 RELOP_FP(f_r4
, <=, 0);
6243 MINT_IN_CASE(MINT_CLE_R8
)
6251 MINT_IN_CASE(MINT_LDFTN
) {
6252 sp
->data
.p
= imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6257 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6258 InterpMethod
*m
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6260 NULL_CHECK (sp
->data
.p
);
6262 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6267 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6268 MONO_API_ERROR_INIT (error
);
6269 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6270 mono_error_assert_ok (error
);
6276 #define LDARG(datamem, argtype) \
6277 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6281 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
6282 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
6283 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
6284 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
6285 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
6286 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
6287 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
6288 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
6289 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6290 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6292 MINT_IN_CASE(MINT_LDARG_VT
) {
6294 int const i32
= READ32 (ip
+ 2);
6295 memcpy(sp
->data
.p
, frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
, i32
);
6296 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6302 #define STARG(datamem, argtype) \
6304 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6307 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
6308 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
6309 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
6310 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
6311 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
6312 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
6313 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6314 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6315 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6316 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6318 MINT_IN_CASE(MINT_STARG_VT
) {
6319 int const i32
= READ32 (ip
+ 2);
6321 memcpy(frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
, sp
->data
.p
, i32
);
6322 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6326 MINT_IN_CASE(MINT_PROF_ENTER
) {
6329 if (MONO_PROFILER_ENABLED (method_enter
)) {
6330 MonoProfilerCallContext
*prof_ctx
= NULL
;
6332 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
6333 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6334 prof_ctx
->interp_frame
= frame
;
6335 prof_ctx
->method
= imethod
->method
;
6338 MONO_PROFILER_RAISE (method_enter
, (imethod
->method
, prof_ctx
));
6346 MINT_IN_CASE(MINT_TRACE_ENTER
) {
6349 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6350 prof_ctx
->interp_frame
= frame
;
6351 prof_ctx
->method
= imethod
->method
;
6353 mono_trace_enter_method (imethod
->method
, prof_ctx
);
6357 MINT_IN_CASE(MINT_TRACE_EXIT
) {
6359 int const i32
= READ32 (ip
+ 1);
6364 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6366 *frame
->retval
= *sp
;
6368 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6369 prof_ctx
->interp_frame
= frame
;
6370 prof_ctx
->method
= imethod
->method
;
6372 mono_trace_leave_method (imethod
->method
, prof_ctx
);
6377 MINT_IN_CASE(MINT_LDARGA
)
6378 sp
->data
.p
= &frame
->stack_args
[* (guint16
*)(ip
+ 1)];
6383 MINT_IN_CASE(MINT_LDARGA_VT
)
6384 sp
->data
.p
= frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
;
6389 #define LDLOC(datamem, argtype) \
6390 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6394 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6395 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6396 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6397 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6398 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6399 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6400 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6401 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6402 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6403 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6405 MINT_IN_CASE(MINT_LDLOC_VT
) {
6407 int const i32
= READ32 (ip
+ 2);
6408 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
6409 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6414 MINT_IN_CASE(MINT_LDLOCA_S
)
6415 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
6420 #define STLOC(datamem, argtype) \
6422 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6425 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6426 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6427 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6428 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6429 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6430 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6431 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6432 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6433 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6434 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6436 #define STLOC_NP(datamem, argtype) \
6437 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6440 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6441 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6443 MINT_IN_CASE(MINT_STLOC_VT
) {
6444 int const i32
= READ32 (ip
+ 2);
6446 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
6447 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6451 MINT_IN_CASE(MINT_LOCALLOC
) {
6452 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6453 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6455 int len
= sp
[-1].data
.i
;
6456 sp
[-1].data
.p
= alloca (len
);
6458 if (imethod
->init_locals
)
6459 memset (sp
[-1].data
.p
, 0, len
);
6463 MINT_IN_CASE(MINT_ENDFILTER
)
6464 /* top of stack is result of filter */
6465 frame
->retval
= &sp
[-1];
6467 MINT_IN_CASE(MINT_INITOBJ
)
6469 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6472 MINT_IN_CASE(MINT_CPBLK
)
6474 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6475 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6477 /* FIXME: value and size may be int64... */
6478 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6481 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6483 /* FIXME: implement */
6485 token
= READ32 (ip
);
6490 MINT_IN_CASE(MINT_INITBLK
)
6492 NULL_CHECK (sp
[0].data
.p
);
6494 /* FIXME: value and size may be int64... */
6495 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6498 MINT_IN_CASE(MINT_NO_
)
6499 /* FIXME: implement */
6503 MINT_IN_CASE(MINT_RETHROW
) {
6504 int exvar_offset
= *(guint16
*)(ip
+ 1);
6505 THROW_EX_GENERAL (*(MonoException
**)(frame_locals (frame
) + exvar_offset
), ip
, TRUE
);
6508 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6510 * need to clarify what this should actually do:
6512 * Takes an exception from the stack and rethrows it.
6513 * This is useful for wrappers that don't want to have to
6514 * use CEE_THROW and lose the exception stacktrace.
6519 sp
->data
.p
= mono_get_exception_null_reference ();
6521 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6524 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6528 del
= (MonoDelegate
*)sp
->data
.p
;
6529 if (!del
->interp_method
) {
6530 /* Not created from interpreted code */
6531 MONO_API_ERROR_INIT (error
);
6532 g_assert (del
->method
);
6533 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6534 mono_error_assert_ok (error
);
6536 g_assert (del
->interp_method
);
6537 sp
->data
.p
= del
->interp_method
;
6542 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6544 int n
= *(guint16
*)(ip
+ 1);
6545 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6546 if (!del
->interp_invoke_impl
) {
6548 * First time we are called. Set up the invoke wrapper. We might be able to do this
6549 * in ctor but we would need to handle AllocDelegateLike_internal separately
6551 MONO_API_ERROR_INIT (error
);
6552 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6553 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6554 mono_error_assert_ok (error
);
6557 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6562 #define MATH_UNOP(mathfunc) \
6563 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6566 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
6567 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
6568 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
6569 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
6570 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
6571 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
6572 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
6573 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
6574 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
6575 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
6576 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
6577 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
6578 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
6579 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
6580 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
6582 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
6583 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6584 mono_interp_enum_hasflag (sp
, klass
);
6589 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
6590 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
6594 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
6595 NULL_CHECK (sp
[-1].data
.p
);
6596 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
6602 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-imethod
->code
);
6606 g_assert_not_reached ();
6609 error_init_reuse (error
);
6611 if (clause_args
&& clause_args
->base_frame
)
6612 memcpy (clause_args
->base_frame
->stack
, frame
->stack
, imethod
->alloca_size
);
6614 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
6615 imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
6616 MonoProfilerCallContext
*prof_ctx
= NULL
;
6618 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
6619 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6620 prof_ctx
->interp_frame
= frame
;
6621 prof_ctx
->method
= imethod
->method
;
6623 MonoType
*rtype
= mono_method_signature_internal (imethod
->method
)->ret
;
6625 switch (rtype
->type
) {
6626 case MONO_TYPE_VOID
:
6628 case MONO_TYPE_VALUETYPE
:
6629 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6632 prof_ctx
->return_value
= frame
->retval
;
6637 MONO_PROFILER_RAISE (method_leave
, (imethod
->method
, prof_ctx
));
6640 } else if (frame
->ex
&& imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
6641 MONO_PROFILER_RAISE (method_exception_leave
, (imethod
->method
, &frame
->ex
->object
));
6647 interp_parse_options (const char *options
)
6654 args
= g_strsplit (options
, ",", -1);
6655 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
6658 if (strncmp (arg
, "jit=", 4) == 0)
6659 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
6660 if (strncmp (arg
, "interp-only=", 4) == 0)
6661 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
6662 if (strncmp (arg
, "-inline", 7) == 0)
6663 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6668 * interp_set_resume_state:
6670 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6673 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
6675 ThreadContext
*context
;
6678 context
= (ThreadContext
*)jit_tls
->interp_context
;
6681 context
->has_resume_state
= TRUE
;
6682 context
->handler_frame
= (InterpFrame
*)interp_frame
;
6683 context
->handler_ei
= ei
;
6684 /* This is on the stack, so it doesn't need a wbarrier */
6685 context
->handler_frame
->ex
= ex
;
6688 *(MonoException
**)(frame_locals (context
->handler_frame
) + ei
->exvar_offset
) = ex
;
6689 context
->handler_ip
= (guint16
*) handler_ip
;
6693 interp_get_resume_state (const MonoJitTlsData
*jit_tls
, gboolean
*has_resume_state
, MonoInterpFrameHandle
*interp_frame
, gpointer
*handler_ip
)
6696 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
6698 *has_resume_state
= context
->has_resume_state
;
6699 if (context
->has_resume_state
) {
6700 *interp_frame
= context
->handler_frame
;
6701 *handler_ip
= context
->handler_ip
;
6706 * interp_run_finally:
6708 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6709 * frame->interp_frame.
6710 * Return TRUE if the finally clause threw an exception.
6713 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6715 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6716 ThreadContext
*context
= get_context ();
6717 const unsigned short *old_ip
= iframe
->ip
;
6718 FrameClauseArgs clause_args
;
6720 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6721 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6722 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6723 clause_args
.exit_clause
= clause_index
;
6726 interp_exec_method_full (iframe
, context
, &clause_args
, error
);
6727 if (context
->has_resume_state
) {
6730 iframe
->ip
= old_ip
;
6736 * interp_run_filter:
6738 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6739 * frame->interp_frame.
6742 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6744 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6745 ThreadContext
*context
= get_context ();
6746 InterpFrame child_frame
;
6748 FrameClauseArgs clause_args
;
6751 * Have to run the clause in a new frame which is a copy of IFRAME, since
6752 * during debugging, there are two copies of the frame on the stack.
6754 memset (&child_frame
, 0, sizeof (InterpFrame
));
6755 child_frame
.imethod
= iframe
->imethod
;
6756 child_frame
.retval
= &retval
;
6757 child_frame
.parent
= iframe
;
6758 child_frame
.stack_args
= iframe
->stack_args
;
6760 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6761 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6762 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6763 clause_args
.filter_exception
= ex
;
6764 clause_args
.base_frame
= iframe
;
6767 interp_exec_method_full (&child_frame
, context
, &clause_args
, error
);
6768 /* ENDFILTER stores the result into child_frame->retval */
6769 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
6773 InterpFrame
*current
;
6777 * interp_frame_iter_init:
6779 * Initialize an iterator for iterating through interpreted frames.
6782 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
6784 StackIter
*stack_iter
= (StackIter
*)iter
;
6786 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
6790 * interp_frame_iter_next:
6792 * Fill out FRAME with date for the next interpreter frame.
6795 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
6797 StackIter
*stack_iter
= (StackIter
*)iter
;
6798 InterpFrame
*iframe
= stack_iter
->current
;
6800 memset (frame
, 0, sizeof (StackFrameInfo
));
6801 /* pinvoke frames doesn't have imethod set */
6802 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
6803 iframe
= iframe
->parent
;
6807 MonoMethod
*method
= iframe
->imethod
->method
;
6808 frame
->domain
= iframe
->imethod
->domain
;
6809 frame
->interp_frame
= iframe
;
6810 frame
->method
= method
;
6811 frame
->actual_method
= method
;
6812 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
6813 frame
->native_offset
= -1;
6814 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
6816 frame
->type
= FRAME_TYPE_INTERP
;
6817 /* This is the offset in the interpreter IR */
6818 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
6819 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6820 frame
->managed
= TRUE
;
6822 frame
->ji
= iframe
->imethod
->jinfo
;
6823 frame
->frame_addr
= iframe
;
6825 stack_iter
->current
= iframe
->parent
;
6831 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
6833 InterpMethod
* imethod
;
6835 imethod
= lookup_imethod (domain
, method
);
6837 return imethod
->jinfo
;
6843 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6845 guint16
*code
= (guint16
*)ip
;
6846 g_assert (*code
== MINT_SDB_SEQ_POINT
);
6847 *code
= MINT_SDB_BREAKPOINT
;
6851 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6853 guint16
*code
= (guint16
*)ip
;
6854 g_assert (*code
== MINT_SDB_BREAKPOINT
);
6855 *code
= MINT_SDB_SEQ_POINT
;
6859 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
6861 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6863 g_assert (iframe
->imethod
);
6864 return iframe
->imethod
->jinfo
;
6868 interp_frame_get_ip (MonoInterpFrameHandle frame
)
6870 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6872 g_assert (iframe
->imethod
);
6873 return (gpointer
)iframe
->ip
;
6877 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
6879 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6880 MonoMethodSignature
*sig
;
6882 g_assert (iframe
->imethod
);
6884 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6885 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
6889 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
6891 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6893 g_assert (iframe
->imethod
);
6895 return frame_locals (iframe
) + iframe
->imethod
->local_offsets
[pos
];
6899 interp_frame_get_this (MonoInterpFrameHandle frame
)
6901 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6903 g_assert (iframe
->imethod
);
6904 g_assert (iframe
->imethod
->hasthis
);
6905 return &iframe
->stack_args
[0].data
.p
;
6908 static MonoInterpFrameHandle
6909 interp_frame_get_parent (MonoInterpFrameHandle frame
)
6911 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6913 return iframe
->parent
;
6917 interp_frame_get_res (MonoInterpFrameHandle frame
)
6919 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6920 MonoMethodSignature
*sig
;
6922 g_assert (iframe
->imethod
);
6923 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6924 if (sig
->ret
->type
== MONO_TYPE_VOID
)
6927 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
6931 interp_start_single_stepping (void)
6937 interp_stop_single_stepping (void)
6943 register_interp_stats (void)
6945 mono_counters_init ();
6946 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
6947 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
6948 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
6951 #undef MONO_EE_CALLBACK
6952 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6954 static const MonoEECallbacks mono_interp_callbacks
= {
6959 mono_ee_interp_init (const char *opts
)
6961 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
6962 g_assert (!interp_init_done
);
6963 interp_init_done
= TRUE
;
6965 mono_native_tls_alloc (&thread_context_id
, NULL
);
6968 interp_parse_options (opts
);
6969 if (mini_get_debug_options ()->mdb_optimizations
)
6970 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6971 mono_interp_transform_init ();
6973 mini_install_interp_callbacks (&mono_interp_callbacks
);
6975 register_interp_stats ();