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>
28 #include <mono/utils/mono-tls-inline.h>
29 #include <mono/utils/mono-membar.h>
35 # define alloca __builtin_alloca
39 /* trim excessive headers */
40 #include <mono/metadata/image.h>
41 #include <mono/metadata/assembly-internals.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/metadata/mono-endian.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/loader.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/profiler-private.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/reflection.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/utils/atomic.h>
64 #include "interp-internals.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/mini-runtime.h>
69 #include <mono/mini/aot-runtime.h>
70 #include <mono/mini/llvm-runtime.h>
71 #include <mono/mini/llvmonly-runtime.h>
72 #include <mono/mini/jit-icalls.h>
73 #include <mono/mini/debugger-agent.h>
74 #include <mono/mini/ee.h>
75 #include <mono/mini/trace.h>
78 #include <mono/mini/mini-arm.h>
80 #include <mono/metadata/icall-decl.h>
83 #pragma warning(disable:4102) // label' : unreferenced label
86 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
87 struct FrameClauseArgs
{
88 /* Where we start the frame execution from */
89 const guint16
*start_with_ip
;
91 * End ip of the exit_clause. We need it so we know whether the resume
92 * state is for this frame (which is called from EH) or for the original
93 * frame further down the stack.
95 const guint16
*end_at_ip
;
96 /* When exiting this clause we also exit the frame */
98 /* Exception that we are filtering */
99 MonoException
*filter_exception
;
100 InterpFrame
*base_frame
;
104 * This code synchronizes with interp_mark_stack () using compiler memory barriers.
107 static StackFragment
*
108 stack_frag_new (int size
)
110 StackFragment
*frag
= (StackFragment
*)g_malloc (size
);
112 frag
->pos
= (guint8
*)&frag
->data
;
113 frag
->end
= (guint8
*)frag
+ size
;
119 frame_stack_init (FrameStack
*stack
, int size
)
123 frag
= stack_frag_new (size
);
124 stack
->first
= stack
->current
= frag
;
125 mono_compiler_barrier ();
129 static StackFragment
*
130 add_frag (FrameStack
*stack
, int size
)
132 StackFragment
*new_frag
;
135 int frag_size
= 4096;
136 if (size
+ sizeof (StackFragment
) > frag_size
)
137 frag_size
= size
+ sizeof (StackFragment
);
138 new_frag
= stack_frag_new (frag_size
);
139 mono_compiler_barrier ();
140 stack
->current
->next
= new_frag
;
141 stack
->current
= new_frag
;
146 free_frag (StackFragment
*frag
)
149 StackFragment
*next
= frag
->next
;
155 static MONO_ALWAYS_INLINE gpointer
156 frame_stack_alloc_ovf (FrameStack
*stack
, int size
, StackFragment
**out_frag
)
158 StackFragment
*current
= stack
->current
;
161 if (current
->next
&& current
->next
->pos
+ size
<= current
->next
->end
) {
162 current
= stack
->current
= current
->next
;
163 current
->pos
= (guint8
*)¤t
->data
;
165 StackFragment
*tmp
= current
->next
;
166 /* avoid linking to be freed fragments, so the GC can't trip over it */
167 current
->next
= NULL
;
168 mono_compiler_barrier ();
171 current
= add_frag (stack
, size
);
173 g_assert (current
->pos
+ size
<= current
->end
);
174 res
= (gpointer
)current
->pos
;
175 current
->pos
+= size
;
177 mono_compiler_barrier ();
184 static MONO_ALWAYS_INLINE gpointer
185 frame_stack_alloc (FrameStack
*stack
, int size
, StackFragment
**out_frag
)
187 StackFragment
*current
= stack
->current
;
190 if (G_LIKELY (current
->pos
+ size
<= current
->end
)) {
192 current
->pos
+= size
;
193 mono_compiler_barrier ();
199 return frame_stack_alloc_ovf (stack
, size
, out_frag
);
203 static MONO_ALWAYS_INLINE
void
204 frame_stack_pop (FrameStack
*stack
, StackFragment
*frag
, gpointer pos
)
206 g_assert ((guint8
*)pos
>= (guint8
*)&frag
->data
&& (guint8
*)pos
<= (guint8
*)frag
->end
);
207 stack
->current
= frag
;
208 mono_compiler_barrier ();
209 stack
->current
->pos
= (guint8
*)pos
;
210 mono_compiler_barrier ();
211 //memset (stack->current->pos, 0, stack->current->end - stack->current->pos);
215 frame_stack_free (FrameStack
*stack
)
218 mono_compiler_barrier ();
219 free_frag (stack
->first
);
225 * Allocate a new frame from the frame stack.
227 static MONO_ALWAYS_INLINE InterpFrame
*
228 alloc_frame (ThreadContext
*ctx
, gpointer native_stack_addr
, InterpFrame
*parent
, InterpMethod
*imethod
, stackval
*args
, stackval
*retval
)
233 // FIXME: Add stack overflow checks
234 frame
= (InterpFrame
*)frame_stack_alloc (&ctx
->iframe_stack
, sizeof (InterpFrame
), &frag
);
236 frame
->iframe_frag
= frag
;
237 frame
->parent
= parent
;
238 frame
->native_stack_addr
= native_stack_addr
;
239 frame
->imethod
= imethod
;
240 frame
->stack_args
= args
;
241 frame
->retval
= retval
;
244 frame
->state
.ip
= NULL
;
252 * Allocate stack space for a frame.
254 static MONO_ALWAYS_INLINE
void
255 alloc_stack_data (ThreadContext
*ctx
, InterpFrame
*frame
, int size
)
260 res
= frame_stack_alloc (&ctx
->data_stack
, size
, &frag
);
262 frame
->stack
= (stackval
*)res
;
263 frame
->data_frag
= frag
;
267 alloc_extra_stack_data (ThreadContext
*ctx
, int size
)
271 return frame_stack_alloc (&ctx
->data_stack
, size
, &frag
);
277 * Pop FRAME and its child frames from the frame stack.
278 * FRAME stays valid until the next alloc_frame () call.
281 pop_frame (ThreadContext
*context
, InterpFrame
*frame
)
284 frame_stack_pop (&context
->data_stack
, frame
->data_frag
, frame
->stack
);
285 frame_stack_pop (&context
->iframe_stack
, frame
->iframe_frag
, frame
);
288 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
291 * List of classes whose methods will be executed by transitioning to JITted code.
294 GSList
*mono_interp_jit_classes
;
295 /* Optimizations enabled with interpreter */
296 int mono_interp_opt
= INTERP_OPT_DEFAULT
;
297 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
298 static gboolean ss_enabled
;
300 static gboolean interp_init_done
= FALSE
;
302 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
);
304 static InterpMethod
* lookup_method_pointer (gpointer addr
);
306 typedef void (*ICallMethod
) (InterpFrame
*frame
);
308 static MonoNativeTlsKey thread_context_id
;
310 #define DEBUG_INTERP 0
314 int mono_interp_traceopt
= 2;
315 /* If true, then we output the opcodes as we interpret them */
316 static int global_tracing
= 2;
318 static int debug_indent_level
= 0;
320 static int break_on_method
= 0;
321 static int nested_trace
= 0;
322 static GList
*db_methods
= NULL
;
323 static char* dump_args (InterpFrame
*inv
);
330 for (h
= 0; h
< debug_indent_level
; h
++)
335 db_match_method (gpointer data
, gpointer user_data
)
337 MonoMethod
*m
= (MonoMethod
*)user_data
;
338 MonoMethodDesc
*desc
= (MonoMethodDesc
*)data
;
340 if (mono_method_desc_full_match (desc
, m
))
345 debug_enter (InterpFrame
*frame
, int *tracing
)
348 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
350 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
354 MonoMethod
*method
= frame
->imethod
->method
;
355 char *mn
, *args
= dump_args (frame
);
356 debug_indent_level
++;
358 mn
= mono_method_full_name (method
, FALSE
);
359 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
361 g_print ("%s)\n", args
);
366 #define DEBUG_LEAVE() \
369 args = dump_retval (frame); \
371 mn = mono_method_full_name (frame->imethod->method, FALSE); \
372 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
374 g_print (" => %s\n", args); \
376 debug_indent_level--; \
377 if (tracing == 3) global_tracing = 0; \
382 int mono_interp_traceopt
= 0;
383 #define DEBUG_LEAVE()
387 #if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP
388 #define USE_COMPUTED_GOTO 1
391 #if USE_COMPUTED_GOTO
393 #define MINT_IN_DISPATCH(op) goto *in_labels [opcode = (MintOpcode)(op)]
394 #define MINT_IN_SWITCH(op) MINT_IN_DISPATCH (op);
395 #define MINT_IN_BREAK MINT_IN_DISPATCH (*ip)
396 #define MINT_IN_CASE(x) LAB_ ## x:
400 #define MINT_IN_SWITCH(op) COUNT_OP(op); switch (opcode = (MintOpcode)(op))
401 #define MINT_IN_CASE(x) case x:
402 #define MINT_IN_BREAK break
407 clear_resume_state (ThreadContext
*context
, GSList
*finally_ips
)
409 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
410 while (finally_ips
&&
411 finally_ips
->data
>= context
->handler_ei
->try_start
&&
412 finally_ips
->data
< context
->handler_ei
->try_end
)
413 finally_ips
= g_slist_remove (finally_ips
, finally_ips
->data
);
414 context
->has_resume_state
= 0;
415 context
->handler_frame
= NULL
;
416 context
->handler_ei
= NULL
;
417 g_assert (context
->exc_gchandle
);
418 mono_gchandle_free_internal (context
->exc_gchandle
);
419 context
->exc_gchandle
= 0;
424 * If this bit is set, it means the call has thrown the exception, and we
425 * reached this point because the EH code in mono_handle_exception ()
426 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
427 * has set the fields in context to indicate where we have to resume execution.
429 #define CHECK_RESUME_STATE(context) do { \
430 if ((context)->has_resume_state) \
435 set_context (ThreadContext
*context
)
437 mono_native_tls_set_value (thread_context_id
, context
);
442 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
443 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
445 /* jit_tls assumes ownership of 'context' */
446 jit_tls
->interp_context
= context
;
449 static ThreadContext
*
452 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
453 if (context
== NULL
) {
454 context
= g_new0 (ThreadContext
, 1);
456 * Use two stacks, one for InterpFrame structures, one for data.
457 * This is useful because InterpFrame structures don't need to be GC tracked.
459 frame_stack_init (&context
->iframe_stack
, 8192);
460 frame_stack_init (&context
->data_stack
, 8192);
461 set_context (context
);
467 interp_free_context (gpointer ctx
)
469 ThreadContext
*context
= (ThreadContext
*)ctx
;
471 frame_stack_free (&context
->iframe_stack
);
472 frame_stack_free (&context
->data_stack
);
477 mono_interp_error_cleanup (MonoError
* error
)
479 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
480 error_init_reuse (error
); // one instruction, so this function is good inline candidate
483 static MONO_NEVER_INLINE
void
484 ves_real_abort (int line
, MonoMethod
*mh
,
485 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
488 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
489 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
490 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
491 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
492 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
493 mono_metadata_free_mh (header
);
494 g_assert_not_reached ();
497 #define ves_abort() \
499 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
504 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
506 InterpMethod
*imethod
;
507 MonoJitDomainInfo
*info
;
509 info
= domain_jit_info (domain
);
510 mono_domain_jit_code_hash_lock (domain
);
511 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
512 mono_domain_jit_code_hash_unlock (domain
);
517 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
519 #ifndef DISABLE_REMOTING
520 InterpMethod
*imethod
;
523 imethod
= lookup_method_pointer (addr
);
526 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
527 return_val_if_nok (error
, NULL
);
530 g_assert (mono_use_interpreter
);
532 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
533 return_val_if_nok (error
, NULL
);
534 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
536 g_assert_not_reached ();
542 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
544 InterpMethod
*imethod
;
545 MonoJitDomainInfo
*info
;
546 MonoMethodSignature
*sig
;
551 info
= domain_jit_info (domain
);
552 mono_domain_jit_code_hash_lock (domain
);
553 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
554 mono_domain_jit_code_hash_unlock (domain
);
558 sig
= mono_method_signature_internal (method
);
560 imethod
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
561 imethod
->method
= method
;
562 imethod
->domain
= domain
;
563 imethod
->param_count
= sig
->param_count
;
564 imethod
->hasthis
= sig
->hasthis
;
565 imethod
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
566 imethod
->code_type
= IMETHOD_CODE_UNKNOWN
;
567 if (imethod
->method
->string_ctor
)
568 imethod
->rtype
= m_class_get_byval_arg (mono_defaults
.string_class
);
570 imethod
->rtype
= mini_get_underlying_type (sig
->ret
);
571 imethod
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
572 for (i
= 0; i
< sig
->param_count
; ++i
)
573 imethod
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
575 mono_domain_jit_code_hash_lock (domain
);
576 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
577 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, imethod
);
578 mono_domain_jit_code_hash_unlock (domain
);
580 imethod
->prof_flags
= mono_profiler_get_call_instrumentation_flags (imethod
->method
);
585 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
586 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
587 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
589 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
590 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
591 * (registers are not accurate), thus resuming to the label does not work. */
592 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
593 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
594 #elif defined (_MSC_VER)
595 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
596 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
597 (ext).interp_exit_label_set = FALSE; \
598 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
599 if ((ext).interp_exit_label_set == FALSE) \
600 mono_arch_do_ip_adjustment (&(ext).ctx); \
601 if ((ext).interp_exit_label_set == TRUE) \
603 (ext).interp_exit_label_set = TRUE;
604 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
605 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
606 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
607 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
608 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
609 mono_arch_do_ip_adjustment (&(ext).ctx);
611 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
614 /* INTERP_PUSH_LMF_WITH_CTX:
616 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
617 * This is needed to resume into the interp when the exception is thrown from
618 * native code (see ./mono/tests/install_eh_callback.exe).
620 * This must be a macro in order to retrieve the right register values for
623 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
624 memset (&(ext), 0, sizeof (MonoLMFExt)); \
625 (ext).interp_exit_data = (frame); \
626 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
627 mono_push_lmf (&(ext));
632 * Push an LMF frame on the LMF stack
633 * to mark the transition to native code.
634 * This is needed for the native code to
635 * be able to do stack walks.
638 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
640 memset (ext
, 0, sizeof (MonoLMFExt
));
641 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
642 ext
->interp_exit_data
= frame
;
648 interp_pop_lmf (MonoLMFExt
*ext
)
650 mono_pop_lmf (&ext
->lmf
);
653 static MONO_NEVER_INLINE InterpMethod
*
654 get_virtual_method (InterpMethod
*imethod
, MonoVTable
*vtable
)
656 MonoMethod
*m
= imethod
->method
;
657 MonoDomain
*domain
= imethod
->domain
;
658 InterpMethod
*ret
= NULL
;
660 #ifndef DISABLE_REMOTING
661 if (mono_class_is_transparent_proxy (vtable
->klass
)) {
663 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
664 mono_error_assert_ok (error
);
665 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
666 mono_error_assert_ok (error
);
671 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
672 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
674 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
675 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
682 mono_class_setup_vtable (vtable
->klass
);
684 int slot
= mono_method_get_vtable_slot (m
);
685 if (mono_class_is_interface (m
->klass
)) {
686 g_assert (vtable
->klass
!= m
->klass
);
687 /* TODO: interface offset lookup is slow, go through IMT instead */
688 gboolean non_exact_match
;
689 slot
+= mono_class_interface_offset_with_variance (vtable
->klass
, m
->klass
, &non_exact_match
);
692 MonoMethod
*virtual_method
= m_class_get_vtable (vtable
->klass
) [slot
];
693 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
694 MonoGenericContext context
= { NULL
, NULL
};
696 if (mono_class_is_ginst (virtual_method
->klass
))
697 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
698 else if (mono_class_is_gtd (virtual_method
->klass
))
699 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
700 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
703 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
704 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
707 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
708 virtual_method
= mono_marshal_get_native_wrapper (virtual_method
, FALSE
, FALSE
);
711 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
712 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
716 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
717 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
718 return virtual_imethod
;
722 InterpMethod
*imethod
;
723 InterpMethod
*target_imethod
;
726 /* domain lock must be held */
728 append_imethod (MonoDomain
*domain
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
731 InterpVTableEntry
*entry
;
733 entry
= (InterpVTableEntry
*) mono_mempool_alloc (domain
->mp
, sizeof (InterpVTableEntry
));
734 entry
->imethod
= imethod
;
735 entry
->target_imethod
= target_imethod
;
736 ret
= g_slist_append_mempool (domain
->mp
, list
, entry
);
742 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
744 while (list
!= NULL
) {
745 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
746 if (entry
->imethod
== imethod
)
747 return entry
->target_imethod
;
754 get_method_table (MonoVTable
*vtable
, int offset
)
757 return vtable
->interp_vtable
;
759 return (gpointer
*)vtable
;
763 alloc_method_table (MonoVTable
*vtable
, int offset
)
768 table
= mono_domain_alloc0 (vtable
->domain
, m_class_get_vtable_size (vtable
->klass
) * sizeof (gpointer
));
769 vtable
->interp_vtable
= table
;
771 table
= (gpointer
*)vtable
;
777 static MONO_NEVER_INLINE InterpMethod
* // Inlining causes additional stack use in caller.
778 get_virtual_method_fast (InterpMethod
*imethod
, MonoVTable
*vtable
, int offset
)
782 #ifndef DISABLE_REMOTING
784 if (mono_class_is_transparent_proxy (vtable
->klass
))
785 return get_virtual_method (imethod
, vtable
);
788 table
= get_method_table (vtable
, offset
);
791 /* Lazily allocate method table */
792 mono_domain_lock (vtable
->domain
);
793 table
= get_method_table (vtable
, offset
);
795 table
= alloc_method_table (vtable
, offset
);
796 mono_domain_unlock (vtable
->domain
);
799 if (!table
[offset
]) {
800 InterpMethod
*target_imethod
= get_virtual_method (imethod
, vtable
);
801 /* Lazily initialize the method table slot */
802 mono_domain_lock (vtable
->domain
);
803 if (!table
[offset
]) {
804 if (imethod
->method
->is_inflated
|| offset
< 0)
805 table
[offset
] = append_imethod (vtable
->domain
, NULL
, imethod
, target_imethod
);
807 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
809 mono_domain_unlock (vtable
->domain
);
812 if ((gsize
)table
[offset
] & 0x1) {
813 /* Non generic virtual call. Only one method in slot */
814 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
816 /* Virtual generic or interface call. Multiple methods in slot */
817 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
819 if (!target_imethod
) {
820 target_imethod
= get_virtual_method (imethod
, vtable
);
821 mono_domain_lock (vtable
->domain
);
822 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
823 table
[offset
] = append_imethod (vtable
->domain
, (GSList
*)table
[offset
], imethod
, target_imethod
);
824 mono_domain_unlock (vtable
->domain
);
826 return target_imethod
;
831 stackval_from_data (MonoType
*type
, stackval
*result
, const void *data
, gboolean pinvoke
)
833 type
= mini_native_type_replace_type (type
);
835 switch (type
->type
) {
836 case MONO_TYPE_OBJECT
:
837 case MONO_TYPE_CLASS
:
838 case MONO_TYPE_STRING
:
839 case MONO_TYPE_ARRAY
:
840 case MONO_TYPE_SZARRAY
:
845 result
->data
.p
= *(gpointer
*)data
;
848 switch (type
->type
) {
852 result
->data
.i
= *(gint8
*)data
;
855 case MONO_TYPE_BOOLEAN
:
856 result
->data
.i
= *(guint8
*)data
;
859 result
->data
.i
= *(gint16
*)data
;
863 result
->data
.i
= *(guint16
*)data
;
866 result
->data
.i
= *(gint32
*)data
;
870 result
->data
.nati
= *(mono_i
*)data
;
873 result
->data
.p
= *(gpointer
*)data
;
876 result
->data
.i
= *(guint32
*)data
;
879 /* memmove handles unaligned case */
880 memmove (&result
->data
.f_r4
, data
, sizeof (float));
884 memmove (&result
->data
.l
, data
, sizeof (gint64
));
887 memmove (&result
->data
.f
, data
, sizeof (double));
889 case MONO_TYPE_STRING
:
890 case MONO_TYPE_SZARRAY
:
891 case MONO_TYPE_CLASS
:
892 case MONO_TYPE_OBJECT
:
893 case MONO_TYPE_ARRAY
:
894 result
->data
.p
= *(gpointer
*)data
;
896 case MONO_TYPE_VALUETYPE
:
897 if (m_class_is_enumtype (type
->data
.klass
)) {
898 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
900 } else if (pinvoke
) {
901 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
903 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
906 case MONO_TYPE_GENERICINST
: {
907 if (mono_type_generic_inst_is_valuetype (type
)) {
908 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
910 memcpy (result
->data
.vt
, data
, mono_class_native_size (klass
, NULL
));
912 mono_value_copy_internal (result
->data
.vt
, data
, klass
);
915 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
919 g_error ("got type 0x%02x", type
->type
);
924 stackval_to_data (MonoType
*type
, stackval
*val
, void *data
, gboolean pinvoke
)
926 type
= mini_native_type_replace_type (type
);
928 gpointer
*p
= (gpointer
*)data
;
932 /* printf ("TODAT0 %p\n", data); */
933 switch (type
->type
) {
936 guint8
*p
= (guint8
*)data
;
940 case MONO_TYPE_BOOLEAN
: {
941 guint8
*p
= (guint8
*)data
;
942 *p
= (val
->data
.i
!= 0);
947 case MONO_TYPE_CHAR
: {
948 guint16
*p
= (guint16
*)data
;
953 mono_i
*p
= (mono_i
*)data
;
954 /* In theory the value used by stloc should match the local var type
955 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
956 a native int - both by csc and mcs). Not sure what to do about sign extension
957 as it is outside the spec... doing the obvious */
958 *p
= (mono_i
)val
->data
.nati
;
962 mono_u
*p
= (mono_u
*)data
;
964 *p
= (mono_u
)val
->data
.nati
;
969 gint32
*p
= (gint32
*)data
;
975 memmove (data
, &val
->data
.l
, sizeof (gint64
));
979 /* memmove handles unaligned case */
980 memmove (data
, &val
->data
.f_r4
, sizeof (float));
984 memmove (data
, &val
->data
.f
, sizeof (double));
987 case MONO_TYPE_STRING
:
988 case MONO_TYPE_SZARRAY
:
989 case MONO_TYPE_CLASS
:
990 case MONO_TYPE_OBJECT
:
991 case MONO_TYPE_ARRAY
: {
992 gpointer
*p
= (gpointer
*) data
;
993 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
996 case MONO_TYPE_PTR
: {
997 gpointer
*p
= (gpointer
*) data
;
1001 case MONO_TYPE_VALUETYPE
:
1002 if (m_class_is_enumtype (type
->data
.klass
)) {
1003 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
1005 } else if (pinvoke
) {
1006 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
1008 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
1011 case MONO_TYPE_GENERICINST
: {
1012 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
1014 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
1015 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
1017 memcpy (data
, val
->data
.vt
, mono_class_native_size (klass
, NULL
));
1019 mono_value_copy_internal (data
, val
->data
.vt
, klass
);
1022 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
1026 g_error ("got type %x", type
->type
);
1031 * Same as stackval_to_data but return address of storage instead
1032 * of copying the value.
1035 stackval_to_data_addr (MonoType
*type
, stackval
*val
)
1037 type
= mini_native_type_replace_type (type
);
1039 return &val
->data
.p
;
1041 switch (type
->type
) {
1044 case MONO_TYPE_BOOLEAN
:
1047 case MONO_TYPE_CHAR
:
1050 return &val
->data
.i
;
1053 return &val
->data
.nati
;
1056 return &val
->data
.l
;
1058 return &val
->data
.f_r4
;
1060 return &val
->data
.f
;
1061 case MONO_TYPE_STRING
:
1062 case MONO_TYPE_SZARRAY
:
1063 case MONO_TYPE_CLASS
:
1064 case MONO_TYPE_OBJECT
:
1065 case MONO_TYPE_ARRAY
:
1067 return &val
->data
.p
;
1068 case MONO_TYPE_VALUETYPE
:
1069 if (m_class_is_enumtype (type
->data
.klass
))
1070 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
1072 return val
->data
.vt
;
1073 case MONO_TYPE_TYPEDBYREF
:
1074 return val
->data
.vt
;
1075 case MONO_TYPE_GENERICINST
: {
1076 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
1078 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
1079 return val
->data
.vt
;
1080 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
1083 g_error ("got type %x", type
->type
);
1089 * Throw an exception from the interpreter.
1091 static MONO_NEVER_INLINE
void
1092 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, const guint16
* ip
, gboolean rethrow
)
1097 interp_push_lmf (&ext
, frame
);
1100 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
1101 MonoException
*mono_ex
= ex
;
1103 mono_ex
->stack_trace
= NULL
;
1104 mono_ex
->trace_ips
= NULL
;
1107 mono_error_assert_ok (error
);
1110 memset (&ctx
, 0, sizeof (MonoContext
));
1111 MONO_CONTEXT_SET_SP (&ctx
, frame
->native_stack_addr
);
1114 * Call the JIT EH code. The EH code will call back to us using:
1115 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
1116 * Since ctx.ip is 0, this will start unwinding from the LMF frame
1117 * pushed above, which points to our frames.
1119 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
1120 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
1121 /* We need to unwind into non-interpreter code */
1122 mono_restore_context (&ctx
);
1123 g_assert_not_reached ();
1126 interp_pop_lmf (&ext
);
1128 g_assert (context
->has_resume_state
);
1131 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
1133 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
1137 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
1139 #define NULL_CHECK(o) do { \
1140 if (G_UNLIKELY (!(o))) \
1144 #define EXCEPTION_CHECKPOINT \
1146 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
1147 MonoException *exc = mono_thread_interruption_checkpoint (); \
1149 THROW_EX (exc, ip); \
1153 /* Don't throw exception if thread is in GC Safe mode. Should only happen in managed-to-native wrapper. */
1154 #define EXCEPTION_CHECKPOINT_GC_UNSAFE \
1156 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method) && mono_thread_is_gc_unsafe_mode ()) { \
1157 MonoException *exc = mono_thread_interruption_checkpoint (); \
1159 THROW_EX (exc, ip); \
1163 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
1165 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
1166 MonoException *exc = mono_thread_interruption_checkpoint (); \
1173 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
1176 intptr_t *lower_bounds
;
1179 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
1180 for (i
= 0; i
< param_count
; ++i
) {
1181 lengths
[i
] = values
->data
.i
;
1184 if (m_class_get_rank (klass
) == param_count
) {
1185 /* Only lengths provided. */
1186 lower_bounds
= NULL
;
1188 /* lower bounds are first. */
1189 lower_bounds
= (intptr_t *) lengths
;
1190 lengths
+= m_class_get_rank (klass
);
1192 return (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
1196 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, gboolean safe
)
1198 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1202 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
1203 guint32 idx
= sp
[i
].data
.i
;
1204 guint32 lower
= ao
->bounds
[i
].lower_bound
;
1205 guint32 len
= ao
->bounds
[i
].length
;
1206 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
))
1208 pos
= (pos
* len
) + idx
- lower
;
1211 pos
= sp
[0].data
.i
;
1212 if (safe
&& pos
>= ao
->max_length
)
1218 static MonoException
*
1219 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1221 MonoObject
*o
= sp
->data
.o
;
1222 MonoArray
*ao
= (MonoArray
*) o
;
1223 MonoClass
*ac
= o
->vtable
->klass
;
1225 g_assert (m_class_get_rank (ac
) >= 1);
1227 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, safe
);
1229 return mono_get_exception_index_out_of_range ();
1231 gint32 esize
= mono_array_element_size (ac
);
1232 gconstpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1234 MonoType
*mt
= sig
->ret
;
1235 stackval_from_data (mt
, retval
, ea
, FALSE
);
1239 static MONO_NEVER_INLINE MonoException
*
1240 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1242 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1244 g_assert (m_class_get_rank (ac
) >= 1);
1246 gint32 pos
= ves_array_calculate_index (ao
, sp
, TRUE
);
1248 return mono_get_exception_index_out_of_range ();
1250 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
))
1251 return mono_get_exception_array_type_mismatch ();
1252 gint32 esize
= mono_array_element_size (ac
);
1253 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1257 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1258 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1261 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1262 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1264 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1267 g_assert (mono_arm_eabi_supported ());
1268 int i8_align
= mono_arm_i8_align ();
1278 for (int i
= 0; i
< sig
->param_count
; i
++) {
1279 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1281 case MONO_TYPE_BOOLEAN
:
1282 case MONO_TYPE_CHAR
:
1292 case MONO_TYPE_SZARRAY
:
1293 case MONO_TYPE_CLASS
:
1294 case MONO_TYPE_OBJECT
:
1295 case MONO_TYPE_STRING
:
1296 case MONO_TYPE_VALUETYPE
:
1297 case MONO_TYPE_GENERICINST
:
1298 #if SIZEOF_VOID_P == 8
1304 #if SIZEOF_VOID_P == 4
1308 /* pairs begin at even registers */
1309 if (i8_align
== 8 && margs
->ilen
& 1)
1316 #if SIZEOF_VOID_P == 8
1321 #if SIZEOF_VOID_P == 4
1327 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1331 if (margs
->ilen
> 0)
1332 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1334 if (margs
->flen
> 0)
1335 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1337 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1338 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1340 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1341 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1348 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1352 for (int i
= 0; i
< sig
->param_count
; i
++) {
1353 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1355 case MONO_TYPE_BOOLEAN
:
1356 case MONO_TYPE_CHAR
:
1366 case MONO_TYPE_SZARRAY
:
1367 case MONO_TYPE_CLASS
:
1368 case MONO_TYPE_OBJECT
:
1369 case MONO_TYPE_STRING
:
1370 case MONO_TYPE_VALUETYPE
:
1371 case MONO_TYPE_GENERICINST
:
1372 #if SIZEOF_VOID_P == 8
1376 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1378 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1382 #if SIZEOF_VOID_P == 4
1384 case MONO_TYPE_U8
: {
1385 stackval
*sarg
= &frame
->stack_args
[i
];
1387 /* pairs begin at even registers */
1388 if (i8_align
== 8 && int_i
& 1)
1391 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1393 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1395 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016" PRIx64
", 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
);
1403 if (ptype
== MONO_TYPE_R4
)
1404 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1406 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1408 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
);
1410 #if SIZEOF_VOID_P == 4
1417 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1421 switch (sig
->ret
->type
) {
1422 case MONO_TYPE_BOOLEAN
:
1423 case MONO_TYPE_CHAR
:
1433 case MONO_TYPE_SZARRAY
:
1434 case MONO_TYPE_CLASS
:
1435 case MONO_TYPE_OBJECT
:
1436 case MONO_TYPE_STRING
:
1439 case MONO_TYPE_VALUETYPE
:
1440 case MONO_TYPE_GENERICINST
:
1441 margs
->retval
= &(frame
->retval
->data
.p
);
1442 margs
->is_float_ret
= 0;
1446 margs
->retval
= &(frame
->retval
->data
.p
);
1447 margs
->is_float_ret
= 1;
1449 case MONO_TYPE_VOID
:
1450 margs
->retval
= NULL
;
1453 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1461 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1463 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1466 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1468 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1472 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gconstpointer data
)
1474 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1477 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1478 else if (sig
->hasthis
&& index
== 0)
1479 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1481 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1485 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1487 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1490 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1492 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1496 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1498 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1499 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1500 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1502 switch (type
->type
) {
1503 case MONO_TYPE_GENERICINST
:
1504 if (!MONO_TYPE_IS_REFERENCE (type
))
1505 val
->data
.vt
= storage
;
1507 case MONO_TYPE_VALUETYPE
:
1508 val
->data
.vt
= storage
;
1511 g_assert_not_reached ();
1516 get_interp_to_native_trampoline (void)
1518 static MonoPIFunc trampoline
= NULL
;
1521 if (mono_ee_features
.use_aot_trampolines
) {
1522 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1524 MonoTrampInfo
*info
;
1525 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1526 mono_tramp_info_register (info
, NULL
);
1528 mono_memory_barrier ();
1534 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1536 get_interp_to_native_trampoline () (addr
, ccontext
);
1539 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1541 #pragma optimize ("", off)
1543 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1544 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, ThreadContext
*context
, gboolean save_last_error
)
1549 g_assert (!frame
->imethod
);
1551 static MonoPIFunc entry_func
= NULL
;
1553 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1555 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
);
1556 mono_error_assert_ok (error
);
1558 entry_func
= get_interp_to_native_trampoline ();
1560 mono_memory_barrier ();
1563 #ifdef ENABLE_NETCORE
1564 if (save_last_error
) {
1565 mono_marshal_clear_last_error ();
1569 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1570 CallContext ccontext
;
1571 MONO_ENTER_GC_UNSAFE
;
1572 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1573 MONO_EXIT_GC_UNSAFE
;
1576 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1580 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_pinvoke
);
1581 entry_func ((gpointer
) addr
, args
);
1582 if (save_last_error
)
1583 mono_marshal_set_last_error ();
1584 interp_pop_lmf (&ext
);
1586 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1587 if (!context
->has_resume_state
) {
1588 MONO_ENTER_GC_UNSAFE
;
1589 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1590 MONO_EXIT_GC_UNSAFE
;
1593 if (ccontext
.stack
!= NULL
)
1594 g_free (ccontext
.stack
);
1596 if (!context
->has_resume_state
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1597 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1599 g_free (margs
->iargs
);
1600 g_free (margs
->fargs
);
1603 goto exit_pinvoke
; // prevent unused label warning in some configurations
1608 #pragma optimize ("", on)
1612 * interp_init_delegate:
1614 * Initialize del->interp_method.
1617 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1621 if (del
->interp_method
) {
1622 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1623 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1624 } else if (del
->method
) {
1625 /* Delegate created dynamically */
1626 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1628 /* Created from JITted code */
1629 g_assert_not_reached ();
1632 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1635 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1636 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1637 mono_class_is_abstract (method
->klass
))
1638 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1640 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1641 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1642 const char *name
= method
->name
;
1643 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1645 * When invoking the delegate interp_method is executed directly. If it's an
1646 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1648 * FIXME We should do this later, when we also know the delegate on which the
1649 * target method is called.
1651 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1652 mono_error_assert_ok (error
);
1656 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1657 /* Return any errors from method compilation */
1658 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1659 return_if_nok (error
);
1664 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1667 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1669 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1671 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1672 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1673 /* virtual invoke delegates must not have null check */
1674 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1675 && MONO_HANDLE_IS_NULL (target
)) {
1676 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1681 g_assert (imethod
->method
);
1682 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1683 return_if_nok (error
);
1685 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1687 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1692 * runtime specifies that the implementation of the method is automatically
1693 * provided by the runtime and is primarily used for the methods of delegates.
1695 #ifndef ENABLE_NETCORE
1696 static MONO_NEVER_INLINE MonoException
*
1697 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1699 const char *name
= method
->name
;
1700 mono_class_init_internal (method
->klass
);
1702 if (method
->klass
== mono_defaults
.array_class
) {
1703 if (!strcmp (name
, "UnsafeMov")) {
1704 /* TODO: layout checks */
1705 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1708 if (!strcmp (name
, "UnsafeLoad"))
1709 return ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1712 g_error ("Don't know how to exec runtime method %s.%s::%s",
1713 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1720 dump_stack (stackval
*stack
, stackval
*sp
)
1722 stackval
*s
= stack
;
1723 GString
*str
= g_string_new ("");
1726 return g_string_free (str
, FALSE
);
1729 g_string_append_printf (str
, "[%p (%" PRId64
")] ", s
->data
.l
, (gint64
)s
->data
.l
);
1732 return g_string_free (str
, FALSE
);
1736 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1738 switch (type
->type
) {
1745 case MONO_TYPE_CHAR
:
1746 case MONO_TYPE_BOOLEAN
:
1747 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1749 case MONO_TYPE_STRING
:
1750 case MONO_TYPE_SZARRAY
:
1751 case MONO_TYPE_CLASS
:
1752 case MONO_TYPE_OBJECT
:
1753 case MONO_TYPE_ARRAY
:
1757 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1759 case MONO_TYPE_VALUETYPE
:
1760 if (m_class_is_enumtype (type
->data
.klass
))
1761 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1763 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1766 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1769 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1774 GString
*res
= g_string_new ("");
1775 mono_type_get_desc (res
, type
, TRUE
);
1776 g_string_append_printf (str
, "[{%s} %" PRId64
"/0x%0" PRIx64
"] ", res
->str
, (gint64
)s
->data
.l
, (guint64
)s
->data
.l
);
1777 g_string_free (res
, TRUE
);
1784 dump_retval (InterpFrame
*inv
)
1786 GString
*str
= g_string_new ("");
1787 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1789 if (ret
->type
!= MONO_TYPE_VOID
)
1790 dump_stackval (str
, inv
->retval
, ret
);
1792 return g_string_free (str
, FALSE
);
1796 dump_args (InterpFrame
*inv
)
1798 GString
*str
= g_string_new ("");
1800 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1802 if (signature
->param_count
== 0 && !signature
->hasthis
)
1803 return g_string_free (str
, FALSE
);
1805 if (signature
->hasthis
) {
1806 MonoMethod
*method
= inv
->imethod
->method
;
1807 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1810 for (i
= 0; i
< signature
->param_count
; ++i
)
1811 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1813 return g_string_free (str
, FALSE
);
1817 #define CHECK_ADD_OVERFLOW(a,b) \
1818 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1819 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1821 #define CHECK_SUB_OVERFLOW(a,b) \
1822 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1823 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1825 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1826 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1828 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1829 (guint32)(a) < (guint32)(b) ? -1 : 0
1831 #define CHECK_ADD_OVERFLOW64(a,b) \
1832 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1833 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1835 #define CHECK_SUB_OVERFLOW64(a,b) \
1836 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1837 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1839 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1840 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1842 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1843 (guint64)(a) < (guint64)(b) ? -1 : 0
1845 #if SIZEOF_VOID_P == 4
1846 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1847 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1849 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1850 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1853 /* Resolves to TRUE if the operands would overflow */
1854 #define CHECK_MUL_OVERFLOW(a,b) \
1855 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1856 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1857 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1858 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1859 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1860 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1861 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1863 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1864 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1865 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1867 #define CHECK_MUL_OVERFLOW64(a,b) \
1868 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1869 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1870 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1871 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1872 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1873 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1874 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1876 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1877 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1878 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1880 #if SIZEOF_VOID_P == 4
1881 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1882 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1884 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1885 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1889 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1892 ThreadContext
*context
= get_context ();
1893 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1894 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1896 MonoMethod
*target_method
= method
;
1902 MonoDomain
*domain
= mono_domain_get ();
1904 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1905 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1906 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1908 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1910 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1914 args
[0].data
.p
= obj
;
1916 args
[0].data
.p
= NULL
;
1917 args
[1].data
.p
= params
;
1918 args
[2].data
.p
= exc
;
1919 args
[3].data
.p
= target_method
;
1921 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1922 mono_error_assert_ok (error
);
1923 frame
= alloc_frame (context
, &result
, NULL
, imethod
, args
, &result
);
1925 interp_exec_method (frame
, context
, error
);
1927 if (context
->has_resume_state
) {
1928 // This can happen on wasm !?
1929 MonoException
*thrown_exc
= (MonoException
*) mono_gchandle_get_target_internal (context
->exc_gchandle
);
1931 *exc
= (MonoObject
*)thrown_exc
;
1933 mono_error_set_exception_instance (error
, thrown_exc
);
1936 return (MonoObject
*)result
.data
.p
;
1940 InterpMethod
*rmethod
;
1944 gpointer
*many_args
;
1947 /* Main function for entering the interpreter from compiled code */
1949 interp_entry (InterpEntryData
*data
)
1952 InterpMethod
*rmethod
;
1953 ThreadContext
*context
;
1958 MonoMethodSignature
*sig
;
1960 gpointer orig_domain
= NULL
, attach_cookie
;
1963 if ((gsize
)data
->rmethod
& 1) {
1965 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1966 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1968 rmethod
= data
->rmethod
;
1970 if (rmethod
->needs_thread_attach
)
1971 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1973 context
= get_context ();
1975 method
= rmethod
->method
;
1976 sig
= mono_method_signature_internal (method
);
1978 // FIXME: Optimize this
1980 //printf ("%s\n", mono_method_full_name (method, 1));
1982 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1984 args
[0].data
.p
= data
->this_arg
;
1987 if (data
->many_args
)
1988 params
= data
->many_args
;
1990 params
= data
->args
;
1991 for (i
= 0; i
< sig
->param_count
; ++i
) {
1992 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1993 if (sig
->params
[i
]->byref
) {
1994 args
[a_index
].data
.p
= params
[i
];
1997 type
= rmethod
->param_types
[i
];
1998 switch (type
->type
) {
1999 case MONO_TYPE_VALUETYPE
:
2000 args
[a_index
].data
.p
= params
[i
];
2002 case MONO_TYPE_GENERICINST
:
2003 if (MONO_TYPE_IS_REFERENCE (type
))
2004 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
2006 args
[a_index
].data
.vt
= params
[i
];
2009 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
2014 memset (&result
, 0, sizeof (result
));
2016 frame
= alloc_frame (context
, &result
, NULL
, data
->rmethod
, args
, retval
);
2018 type
= rmethod
->rtype
;
2019 switch (type
->type
) {
2020 case MONO_TYPE_GENERICINST
:
2021 if (!MONO_TYPE_IS_REFERENCE (type
))
2022 retval
->data
.vt
= data
->res
;
2024 case MONO_TYPE_VALUETYPE
:
2025 retval
->data
.vt
= data
->res
;
2032 interp_exec_method (frame
, context
, error
);
2034 g_assert (!context
->has_resume_state
);
2036 if (rmethod
->needs_thread_attach
)
2037 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2039 if (mono_llvm_only
) {
2040 if (context
->has_resume_state
)
2041 mono_llvm_reraise_exception ((MonoException
*)mono_gchandle_get_target_internal (context
->exc_gchandle
));
2043 g_assert (!context
->has_resume_state
);
2046 type
= rmethod
->rtype
;
2047 switch (type
->type
) {
2048 case MONO_TYPE_VOID
:
2050 case MONO_TYPE_OBJECT
:
2051 /* No need for a write barrier */
2052 *(MonoObject
**)data
->res
= (MonoObject
*)retval
->data
.p
;
2054 case MONO_TYPE_GENERICINST
:
2055 if (MONO_TYPE_IS_REFERENCE (type
)) {
2056 *(MonoObject
**)data
->res
= (MonoObject
*)retval
->data
.p
;
2058 /* Already set before the call */
2061 case MONO_TYPE_VALUETYPE
:
2062 /* Already set before the call */
2065 stackval_to_data (type
, retval
, data
->res
, FALSE
);
2071 do_icall (MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2073 #ifdef ENABLE_NETCORE
2074 if (save_last_error
)
2075 mono_marshal_clear_last_error ();
2079 case MINT_ICALL_V_V
: {
2080 typedef void (*T
)(void);
2085 case MINT_ICALL_V_P
: {
2086 typedef gpointer (*T
)(void);
2089 sp
[-1].data
.p
= func ();
2092 case MINT_ICALL_P_V
: {
2093 typedef void (*T
)(gpointer
);
2095 func (sp
[-1].data
.p
);
2099 case MINT_ICALL_P_P
: {
2100 typedef gpointer (*T
)(gpointer
);
2102 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
2105 case MINT_ICALL_PP_V
: {
2106 typedef void (*T
)(gpointer
,gpointer
);
2109 func (sp
[0].data
.p
, sp
[1].data
.p
);
2112 case MINT_ICALL_PP_P
: {
2113 typedef gpointer (*T
)(gpointer
,gpointer
);
2116 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
2119 case MINT_ICALL_PPP_V
: {
2120 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
2123 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2126 case MINT_ICALL_PPP_P
: {
2127 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
2130 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
2133 case MINT_ICALL_PPPP_V
: {
2134 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2137 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
2140 case MINT_ICALL_PPPP_P
: {
2141 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2144 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2147 case MINT_ICALL_PPPPP_V
: {
2148 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2151 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
2154 case MINT_ICALL_PPPPP_P
: {
2155 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2158 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
);
2161 case MINT_ICALL_PPPPPP_V
: {
2162 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2165 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
);
2168 case MINT_ICALL_PPPPPP_P
: {
2169 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2172 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
);
2176 g_assert_not_reached ();
2179 if (save_last_error
)
2180 mono_marshal_set_last_error ();
2182 /* convert the native representation to the stackval representation */
2184 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2189 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2191 #pragma optimize ("", off)
2193 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
2194 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2197 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
2199 sp
= do_icall (sig
, op
, sp
, ptr
, save_last_error
);
2201 interp_pop_lmf (&ext
);
2203 goto exit_icall
; // prevent unused label warning in some configurations
2208 #pragma optimize ("", on)
2213 gpointer jit_wrapper
;
2215 MonoFtnDesc
*ftndesc
;
2219 jit_call_cb (gpointer arg
)
2221 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2222 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2223 int pindex
= cb_data
->pindex
;
2224 gpointer
*args
= cb_data
->args
;
2225 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2229 typedef void (*T
)(gpointer
);
2230 T func
= (T
)jit_wrapper
;
2236 typedef void (*T
)(gpointer
, gpointer
);
2237 T func
= (T
)jit_wrapper
;
2239 func (args
[0], &ftndesc
);
2243 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2244 T func
= (T
)jit_wrapper
;
2246 func (args
[0], args
[1], &ftndesc
);
2250 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2251 T func
= (T
)jit_wrapper
;
2253 func (args
[0], args
[1], args
[2], &ftndesc
);
2257 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2258 T func
= (T
)jit_wrapper
;
2260 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2264 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2265 T func
= (T
)jit_wrapper
;
2267 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2271 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2272 T func
= (T
)jit_wrapper
;
2274 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2278 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2279 T func
= (T
)jit_wrapper
;
2281 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2285 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2286 T func
= (T
)jit_wrapper
;
2288 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2292 g_assert_not_reached ();
2297 static MONO_NEVER_INLINE
void
2298 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2300 MonoMethodSignature
*sig
;
2301 MonoFtnDesc ftndesc
;
2302 guint8 res_buf
[256];
2306 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2309 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2310 * by ref and return a return value using an explicit return value argument.
2312 if (G_UNLIKELY (!rmethod
->jit_wrapper
)) {
2313 MonoMethod
*method
= rmethod
->method
;
2315 sig
= mono_method_signature_internal (method
);
2318 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2319 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2321 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2322 mono_error_assert_ok (error
);
2324 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2325 return_if_nok (error
);
2328 rmethod
->jit_addr
= addr
;
2329 rmethod
->jit_sig
= sig
;
2330 mono_memory_barrier ();
2331 rmethod
->jit_wrapper
= jit_wrapper
;
2334 sig
= rmethod
->jit_sig
;
2337 ftndesc
.addr
= rmethod
->jit_addr
;
2340 // FIXME: Optimize this
2344 int stack_index
= 0;
2345 if (rmethod
->hasthis
) {
2346 args
[pindex
++] = sp
[0].data
.p
;
2349 type
= rmethod
->rtype
;
2350 if (type
->type
!= MONO_TYPE_VOID
) {
2351 if (MONO_TYPE_ISSTRUCT (type
))
2352 args
[pindex
++] = vt_sp
;
2354 args
[pindex
++] = res_buf
;
2356 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2357 MonoType
*t
= rmethod
->param_types
[i
];
2358 stackval
*sval
= &sp
[stack_index
+ i
];
2359 if (sig
->params
[i
]->byref
) {
2360 args
[pindex
++] = sval
->data
.p
;
2361 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2362 args
[pindex
++] = sval
->data
.p
;
2363 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2364 args
[pindex
++] = &sval
->data
.p
;
2373 case MONO_TYPE_VALUETYPE
:
2374 args
[pindex
++] = &sval
->data
.i
;
2377 case MONO_TYPE_FNPTR
:
2380 case MONO_TYPE_OBJECT
:
2381 args
[pindex
++] = &sval
->data
.p
;
2385 args
[pindex
++] = &sval
->data
.l
;
2388 args
[pindex
++] = &sval
->data
.f_r4
;
2391 args
[pindex
++] = &sval
->data
.f
;
2394 printf ("%s\n", mono_type_full_name (t
));
2395 g_assert_not_reached ();
2400 interp_push_lmf (&ext
, frame
);
2402 JitCallCbData cb_data
;
2403 memset (&cb_data
, 0, sizeof (cb_data
));
2404 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2405 cb_data
.pindex
= pindex
;
2406 cb_data
.args
= args
;
2407 cb_data
.ftndesc
= &ftndesc
;
2409 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2410 /* Catch the exception thrown by the native code using a try-catch */
2411 gboolean thrown
= FALSE
;
2412 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2413 interp_pop_lmf (&ext
);
2415 MonoObject
*obj
= mono_llvm_load_exception ();
2417 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2421 jit_call_cb (&cb_data
);
2422 interp_pop_lmf (&ext
);
2425 MonoType
*rtype
= rmethod
->rtype
;
2426 switch (rtype
->type
) {
2427 case MONO_TYPE_VOID
:
2428 case MONO_TYPE_OBJECT
:
2429 case MONO_TYPE_STRING
:
2430 case MONO_TYPE_CLASS
:
2431 case MONO_TYPE_ARRAY
:
2432 case MONO_TYPE_SZARRAY
:
2436 sp
->data
.p
= *(gpointer
*)res_buf
;
2439 sp
->data
.i
= *(gint8
*)res_buf
;
2442 sp
->data
.i
= *(guint8
*)res_buf
;
2445 sp
->data
.i
= *(gint16
*)res_buf
;
2448 sp
->data
.i
= *(guint16
*)res_buf
;
2451 sp
->data
.i
= *(gint32
*)res_buf
;
2454 sp
->data
.i
= *(guint32
*)res_buf
;
2457 sp
->data
.l
= *(gint64
*)res_buf
;
2460 sp
->data
.l
= *(guint64
*)res_buf
;
2463 sp
->data
.f_r4
= *(float*)res_buf
;
2466 sp
->data
.f
= *(double*)res_buf
;
2468 case MONO_TYPE_TYPEDBYREF
:
2469 case MONO_TYPE_VALUETYPE
:
2470 /* The result was written to vt_sp */
2473 case MONO_TYPE_GENERICINST
:
2474 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2475 sp
->data
.p
= *(gpointer
*)res_buf
;
2477 /* The result was written to vt_sp */
2482 g_print ("%s\n", mono_type_full_name (rtype
));
2483 g_assert_not_reached ();
2488 static MONO_NEVER_INLINE
void
2489 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2492 interp_push_lmf (&ext
, frame
);
2494 interp_pop_lmf (&ext
);
2497 static MONO_NEVER_INLINE MonoException
*
2498 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2501 /* Don't push lmf if we have no interp data */
2502 gboolean push_lmf
= frame
->parent
!= NULL
;
2505 /* Use the parent frame as the current frame is not complete yet */
2507 interp_push_lmf (&ext
, frame
->parent
);
2509 mono_interp_transform_method (frame
->imethod
, context
, error
);
2512 interp_pop_lmf (&ext
);
2514 return mono_error_convert_to_exception (error
);
2517 static MONO_NEVER_INLINE guchar
*
2518 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, guchar
*vt_sp_start
)
2520 stackval
*first_arg
= sp
- csig
->param_count
;
2521 guchar
*vt_sp
= vt_sp_start
;
2524 * We need to have the varargs linearly on the stack so the ArgIterator
2525 * can iterate over them. We pass the signature first and then copy them
2526 * one by one on the vtstack. At the end we pass the original vt_stack
2527 * so the callee (MINT_ARGLIST) can find the varargs space.
2529 *(gpointer
*)vt_sp
= csig
;
2530 vt_sp
+= sizeof (gpointer
);
2532 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2533 int align
, arg_size
;
2534 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2535 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, align
);
2537 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt_sp
, FALSE
);
2541 vt_sp
+= sizeof (gpointer
);
2542 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, MINT_VT_ALIGNMENT
);
2544 ((gpointer
*)vt_sp
) [-1] = vt_sp_start
;
2550 * These functions are the entry points into the interpreter from compiled code.
2551 * They are called by the interp_in wrappers. They have the following signature:
2552 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2553 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2554 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2555 * more wrappers then these functions.
2556 * this/static * ret/void * 16 arguments -> 64 functions.
2559 #define MAX_INTERP_ENTRY_ARGS 8
2561 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2562 InterpEntryData data; \
2563 (data).rmethod = (_method); \
2564 (data).res = (_res); \
2565 (data).this_arg = (_this_arg); \
2566 (data).many_args = NULL;
2568 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2569 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2570 interp_entry (&data); \
2572 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2573 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2574 (data).args [0] = arg1; \
2575 interp_entry (&data); \
2577 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2578 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2579 (data).args [0] = arg1; \
2580 (data).args [1] = arg2; \
2581 interp_entry (&data); \
2583 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2584 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2585 (data).args [0] = arg1; \
2586 (data).args [1] = arg2; \
2587 (data).args [2] = arg3; \
2588 interp_entry (&data); \
2590 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2591 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2592 (data).args [0] = arg1; \
2593 (data).args [1] = arg2; \
2594 (data).args [2] = arg3; \
2595 (data).args [3] = arg4; \
2596 interp_entry (&data); \
2598 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2599 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2600 (data).args [0] = arg1; \
2601 (data).args [1] = arg2; \
2602 (data).args [2] = arg3; \
2603 (data).args [3] = arg4; \
2604 (data).args [4] = arg5; \
2605 interp_entry (&data); \
2607 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2608 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2609 (data).args [0] = arg1; \
2610 (data).args [1] = arg2; \
2611 (data).args [2] = arg3; \
2612 (data).args [3] = arg4; \
2613 (data).args [4] = arg5; \
2614 (data).args [5] = arg6; \
2615 interp_entry (&data); \
2617 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2618 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2619 (data).args [0] = arg1; \
2620 (data).args [1] = arg2; \
2621 (data).args [2] = arg3; \
2622 (data).args [3] = arg4; \
2623 (data).args [4] = arg5; \
2624 (data).args [5] = arg6; \
2625 (data).args [6] = arg7; \
2626 interp_entry (&data); \
2628 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2629 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2630 (data).args [0] = arg1; \
2631 (data).args [1] = arg2; \
2632 (data).args [2] = arg3; \
2633 (data).args [3] = arg4; \
2634 (data).args [4] = arg5; \
2635 (data).args [5] = arg6; \
2636 (data).args [6] = arg7; \
2637 (data).args [7] = arg8; \
2638 interp_entry (&data); \
2641 #define ARGLIST0 InterpMethod *rmethod
2642 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2643 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2644 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2645 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2646 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2647 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2648 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2649 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2651 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2652 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2653 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2654 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2655 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2656 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2657 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2658 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2659 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2660 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2661 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2662 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2663 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2664 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2665 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2666 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2667 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2668 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2669 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2670 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2671 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2672 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2673 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2674 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2675 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2676 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2677 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2678 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2679 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2680 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2681 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2682 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2683 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2684 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2685 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2686 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2688 #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
2690 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2691 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2692 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2693 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2695 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2697 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2699 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2700 data
.many_args
= args
;
2701 interp_entry (&data
);
2704 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2706 // inline so we can alloc on stack
2707 #define alloc_storage_for_stackval(s, t, p) do { \
2708 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2709 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2710 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2712 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2714 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2719 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2722 ThreadContext
*context
;
2726 MonoMethodSignature
*sig
;
2727 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2728 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2729 gpointer orig_domain
= NULL
, attach_cookie
;
2732 if (rmethod
->needs_thread_attach
)
2733 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2735 context
= get_context ();
2737 method
= rmethod
->method
;
2738 sig
= mono_method_signature_internal (method
);
2739 if (method
->string_ctor
) {
2740 MonoMethodSignature
*newsig
= g_alloca (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
2741 memcpy (newsig
, sig
, mono_metadata_signature_size (sig
));
2742 newsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2746 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2748 frame
= alloc_frame (context
, &result
, NULL
, rmethod
, args
, &result
);
2750 /* Allocate storage for value types */
2751 for (i
= 0; i
< sig
->param_count
; i
++) {
2752 MonoType
*type
= sig
->params
[i
];
2753 alloc_storage_for_stackval (&frame
->stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2756 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2757 alloc_storage_for_stackval (frame
->retval
, sig
->ret
, sig
->pinvoke
);
2759 /* Copy the args saved in the trampoline to the frame stack */
2760 mono_arch_get_native_call_context_args (ccontext
, frame
, sig
);
2763 interp_exec_method (frame
, context
, error
);
2765 g_assert (!context
->has_resume_state
);
2767 if (rmethod
->needs_thread_attach
)
2768 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2770 /* Write back the return value */
2771 /* 'frame' is still valid */
2772 mono_arch_set_native_call_context_ret (ccontext
, frame
, sig
);
2778 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2780 g_assert_not_reached ();
2783 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2785 static InterpMethod
*
2786 lookup_method_pointer (gpointer addr
)
2788 MonoDomain
*domain
= mono_domain_get ();
2789 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2790 InterpMethod
*res
= NULL
;
2792 mono_domain_lock (domain
);
2793 if (info
->interp_method_pointer_hash
)
2794 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2795 mono_domain_unlock (domain
);
2800 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2802 interp_no_native_to_managed (void)
2804 g_error ("interpreter: native-to-managed transition not available on this platform");
2809 no_llvmonly_interp_method_pointer (void)
2811 g_assert_not_reached ();
2815 * interp_create_method_pointer_llvmonly:
2817 * Return an ftndesc for entering the interpreter and executing METHOD.
2820 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2822 MonoDomain
*domain
= mono_domain_get ();
2823 gpointer addr
, entry_func
, entry_wrapper
;
2824 MonoMethodSignature
*sig
;
2825 MonoMethod
*wrapper
;
2826 MonoJitDomainInfo
*info
;
2827 InterpMethod
*imethod
;
2829 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2830 return_val_if_nok (error
, NULL
);
2833 if (imethod
->llvmonly_unbox_entry
)
2834 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2836 if (imethod
->jit_entry
)
2837 return (MonoFtnDesc
*)imethod
->jit_entry
;
2840 sig
= mono_method_signature_internal (method
);
2843 * The entry functions need access to the method to call, so we have
2844 * to use a ftndesc. The caller uses a normal signature, while the
2845 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2846 * a gsharedvt_in_sig wrapper.
2848 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2850 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2851 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2852 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2853 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2855 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2856 g_assert_not_reached ();
2857 //entry_func = (gpointer)interp_entry_general;
2858 } else if (sig
->hasthis
) {
2859 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2860 entry_func
= entry_funcs_instance
[sig
->param_count
];
2862 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2864 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2865 entry_func
= entry_funcs_static
[sig
->param_count
];
2867 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2869 g_assert (entry_func
);
2871 /* Encode unbox in the lower bit of imethod */
2872 gpointer entry_arg
= imethod
;
2874 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2875 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2877 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2879 info
= domain_jit_info (domain
);
2880 mono_domain_lock (domain
);
2881 if (!info
->interp_method_pointer_hash
)
2882 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2883 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2884 mono_domain_unlock (domain
);
2886 mono_memory_barrier ();
2888 imethod
->llvmonly_unbox_entry
= addr
;
2890 imethod
->jit_entry
= addr
;
2892 return (MonoFtnDesc
*)addr
;
2896 * interp_create_method_pointer:
2898 * Return a function pointer which can be used to call METHOD using the
2899 * interpreter. Return NULL for methods which are not supported.
2902 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2904 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2906 return (gpointer
)no_llvmonly_interp_method_pointer
;
2907 return (gpointer
)interp_no_native_to_managed
;
2909 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2910 MonoDomain
*domain
= mono_domain_get ();
2911 MonoJitDomainInfo
*info
;
2912 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2915 return (gpointer
)no_llvmonly_interp_method_pointer
;
2917 if (imethod
->jit_entry
)
2918 return imethod
->jit_entry
;
2920 if (compile
&& !imethod
->transformed
) {
2921 /* Return any errors from method compilation */
2922 mono_interp_transform_method (imethod
, get_context (), error
);
2923 return_val_if_nok (error
, NULL
);
2926 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2927 if (method
->string_ctor
) {
2928 MonoMethodSignature
*newsig
= g_alloca (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
2929 memcpy (newsig
, sig
, mono_metadata_signature_size (sig
));
2930 newsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2935 /* The caller should call interp_create_method_pointer_llvmonly */
2936 g_assert_not_reached ();
2938 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2941 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2943 * Interp in wrappers get the argument in the rgctx register. If
2944 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2945 * on that arch the rgctx register is not scratch, so we use a
2946 * separate temp register. We should update the wrappers for this
2947 * if we really care about those architectures (arm).
2949 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2951 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2953 if (entry_wrapper
) {
2954 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2955 entry_func
= (gpointer
)interp_entry_general
;
2956 } else if (sig
->hasthis
) {
2957 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2958 entry_func
= entry_funcs_instance
[sig
->param_count
];
2960 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2962 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2963 entry_func
= entry_funcs_static
[sig
->param_count
];
2965 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2968 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2969 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2970 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2971 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2973 mono_error_cleanup (error
);
2974 error_init_reuse (error
);
2975 if (!mono_native_to_interp_trampoline
) {
2976 if (mono_aot_only
) {
2977 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2979 MonoTrampInfo
*info
;
2980 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2981 mono_tramp_info_register (info
, NULL
);
2984 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2985 /* We need the lmf wrapper only when being called from mixed mode */
2987 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2989 static gpointer cached_func
= NULL
;
2991 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
);
2992 mono_memory_barrier ();
2994 entry_func
= cached_func
;
2999 g_assert (entry_func
);
3000 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
3001 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
3002 ftndesc
->addr
= entry_func
;
3003 ftndesc
->arg
= imethod
;
3004 mono_error_assert_ok (error
);
3007 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
3008 * rgctx register using a trampoline.
3011 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
3013 info
= domain_jit_info (domain
);
3014 mono_domain_lock (domain
);
3015 if (!info
->interp_method_pointer_hash
)
3016 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
3017 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
3018 mono_domain_unlock (domain
);
3020 mono_memory_barrier ();
3021 imethod
->jit_entry
= addr
;
3028 interp_free_method (MonoDomain
*domain
, MonoMethod
*method
)
3030 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3032 mono_domain_jit_code_hash_lock (domain
);
3033 /* InterpMethod is allocated in the domain mempool. We might haven't
3034 * allocated an InterpMethod for this instance yet */
3035 mono_internal_hash_table_remove (&info
->interp_code_hash
, method
);
3036 mono_domain_jit_code_hash_unlock (domain
);
3040 static long opcode_counts
[MINT_LASTOP
];
3042 #define COUNT_OP(op) opcode_counts[op]++
3044 #define COUNT_OP(op)
3048 #define DUMP_INSTR() \
3049 if (tracing > 1) { \
3051 if (sp > frame->stack) { \
3052 ins = dump_stack (frame->stack, sp); \
3054 ins = g_strdup (""); \
3058 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
3059 char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
3060 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
3066 #define DUMP_INSTR()
3069 #define INIT_VTABLE(vtable) do { \
3070 if (G_UNLIKELY (!(vtable)->initialized)) { \
3071 mono_runtime_class_init_full ((vtable), error); \
3072 if (!is_ok (error)) \
3073 goto throw_error_label; \
3077 static MONO_NEVER_INLINE MonoObject
*
3078 mono_interp_new (MonoDomain
* domain
, MonoClass
* klass
)
3081 MonoObject
* const object
= mono_object_new_checked (domain
, klass
, error
);
3082 mono_error_cleanup (error
); // FIXME: do not swallow the error
3087 #ifndef DISABLE_REMOTING
3088 MONO_NEVER_INLINE
// To reduce stack.
3091 mono_interp_load_remote_field (
3092 InterpMethod
* imethod
,
3097 g_assert (o
); // Caller checks and throws exception properly.
3100 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3102 #ifndef DISABLE_REMOTING
3104 if (mono_object_is_transparent_proxy (o
)) {
3105 MonoClass
* const klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3107 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3108 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3111 addr
= (char*)o
+ field
->offset
;
3112 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
3116 #ifndef DISABLE_REMOTING
3117 MONO_NEVER_INLINE
// To reduce stack.
3119 guchar
* // Return new vt_sp instead of take-address.
3120 mono_interp_load_remote_field_vt (
3121 InterpMethod
* imethod
,
3127 g_assert (o
); // Caller checks and throws exception properly.
3130 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3131 MonoClass
* klass
= mono_class_from_mono_type_internal (field
->type
);
3132 int const i32
= mono_class_value_size (klass
, NULL
);
3134 #ifndef DISABLE_REMOTING
3136 if (mono_object_is_transparent_proxy (o
)) {
3137 klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3139 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3140 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3143 addr
= (char*)o
+ field
->offset
;
3144 sp
[-1].data
.p
= vt_sp
;
3145 memcpy (vt_sp
, addr
, i32
);
3146 return vt_sp
+ ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3149 static MONO_NEVER_INLINE gboolean
3150 mono_interp_isinst (MonoObject
* object
, MonoClass
* klass
)
3154 MonoClass
*obj_class
= mono_object_class (object
);
3155 // mono_class_is_assignable_from_checked can't handle remoting casts
3156 if (mono_class_is_transparent_proxy (obj_class
))
3157 isinst
= mono_object_isinst_checked (object
, klass
, error
) != NULL
;
3159 mono_class_is_assignable_from_checked (klass
, obj_class
, &isinst
, error
);
3160 mono_error_cleanup (error
); // FIXME: do not swallow the error
3164 // This function is outlined to help save stack in its caller, on the premise
3165 // that it is relatively rarely called. This also lets it use alloca.
3166 static MONO_NEVER_INLINE
void
3167 mono_interp_calli_nat_dynamic_pinvoke (
3168 // Parameters are sorted by name.
3169 InterpFrame
* child_frame
,
3171 ThreadContext
* context
,
3172 MonoMethodSignature
* csignature
,
3175 // Recompute to limit parameters, which can also contribute to caller stack.
3176 InterpMethod
* const imethod
= child_frame
->parent
->imethod
;
3178 g_assert (imethod
->method
->dynamic
&& csignature
->pinvoke
);
3180 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3181 MonoMarshalSpec
** mspecs
= g_newa (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3182 memset (mspecs
, 0, sizeof (MonoMarshalSpec
*) * (csignature
->param_count
+ 1));
3184 MonoMethodPInvoke iinfo
;
3185 memset (&iinfo
, 0, sizeof (iinfo
));
3187 MonoMethod
* m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &iinfo
, mspecs
, code
);
3189 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3191 mono_metadata_free_marshal_spec (mspecs
[i
]);
3195 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
3196 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3199 interp_exec_method (child_frame
, context
, error
);
3202 // Leave is split into pieces in order to consume less stack,
3203 // but not have to change how exception handling macros access labels and locals.
3204 static MONO_NEVER_INLINE MonoException
*
3205 mono_interp_leave (InterpFrame
* child_frame
)
3209 * We need for mono_thread_get_undeniable_exception to be able to unwind
3210 * to check the abort threshold. For this to work we use child_frame as a
3211 * dummy frame that is stored in the lmf and serves as the transition frame
3213 do_icall_wrapper (child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
3215 return (MonoException
*)tmp_sp
.data
.p
;
3218 static MONO_NEVER_INLINE MonoException
*
3219 mono_interp_newobj (
3220 // Parameters are sorted by name and parameter list is minimized
3221 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3222 // use no stack in caller).
3223 InterpFrame
* child_frame
,
3224 ThreadContext
* context
,
3228 InterpFrame
* const frame
= child_frame
->parent
;
3229 InterpMethod
* const imethod
= frame
->imethod
;
3230 stackval
* const sp
= child_frame
->stack_args
;
3232 MonoObject
* o
= NULL
; // See the comment about GC safety.
3233 stackval valuetype_this
;
3236 MonoClass
* const newobj_class
= child_frame
->imethod
->method
->klass
;
3237 /*if (profiling_classes) {
3238 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3240 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3244 * First arg is the object.
3246 if (m_class_is_valuetype (newobj_class
)) {
3247 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
3248 memset (&valuetype_this
, 0, sizeof (stackval
));
3249 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3251 valuetype_this
.data
.p
= vt_sp
;
3253 sp
->data
.p
= &valuetype_this
;
3256 if (newobj_class
!= mono_defaults
.string_class
) {
3257 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
3258 if (!is_ok (error
) || !mono_runtime_class_init_full (vtable
, error
)) {
3259 MonoException
* const exc
= mono_error_convert_to_exception (error
);
3264 OBJREF (o
) = mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
3265 mono_error_cleanup (error
); // FIXME: do not swallow the error
3266 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION
;
3268 #ifndef DISABLE_REMOTING
3269 if (mono_object_is_transparent_proxy (o
)) {
3270 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
->imethod
->method
, error
);
3271 mono_error_assert_ok (error
);
3272 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
3273 mono_error_assert_ok (error
);
3278 child_frame
->retval
= &retval
;
3282 interp_exec_method (child_frame
, context
, error
);
3284 CHECK_RESUME_STATE (context
);
3287 * a constructor returns void, but we need to return the object we created
3289 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
3290 *sp
= valuetype_this
;
3291 } else if (newobj_class
== mono_defaults
.string_class
) {
3300 static MONO_NEVER_INLINE
void
3301 mono_interp_enum_hasflag (stackval
* sp
, MonoClass
* klass
)
3303 guint64 a_val
= 0, b_val
= 0;
3305 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &b_val
, FALSE
);
3306 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &a_val
, FALSE
);
3307 sp
->data
.i
= (a_val
& b_val
) == b_val
;
3310 static MONO_NEVER_INLINE
int
3311 mono_interp_box_nullable (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3313 InterpMethod
* const imethod
= frame
->imethod
;
3314 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[ip
[1]];
3316 int const size
= mono_class_value_size (c
, NULL
);
3318 guint16 offset
= ip
[2];
3319 guint16 pop_vt_sp
= !ip
[3];
3321 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
3322 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3324 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3327 static MONO_NEVER_INLINE
int
3328 mono_interp_box_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3330 InterpMethod
* const imethod
= frame
->imethod
;
3332 MonoObject
* o
; // See the comment about GC safety.
3333 MonoVTable
* const vtable
= (MonoVTable
*)imethod
->data_items
[ip
[1]];
3334 MonoClass
* const c
= vtable
->klass
;
3336 int const size
= mono_class_value_size (c
, NULL
);
3338 guint16 offset
= ip
[2];
3339 guint16 pop_vt_sp
= !ip
[3];
3341 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3342 mono_value_copy_internal (mono_object_get_data (o
), sp
[-1 - offset
].data
.p
, c
);
3344 sp
[-1 - offset
].data
.p
= o
;
3345 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3348 static MONO_NEVER_INLINE
void
3349 mono_interp_box (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3351 MonoObject
*o
; // See the comment about GC safety.
3352 MonoVTable
* const vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
3354 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3356 guint16
const offset
= ip
[2];
3358 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (o
), FALSE
);
3360 sp
[-1 - offset
].data
.p
= o
;
3363 static MONO_NEVER_INLINE
int
3364 mono_interp_store_remote_field_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3366 InterpMethod
* const imethod
= frame
->imethod
;
3367 MonoClassField
*field
;
3369 MonoObject
* const o
= sp
[-2].data
.o
;
3371 field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3372 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
3373 int const i32
= mono_class_value_size (klass
, NULL
);
3375 #ifndef DISABLE_REMOTING
3376 if (mono_object_is_transparent_proxy (o
)) {
3377 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3378 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
3379 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3382 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3384 return ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3387 // varargs in wasm consumes extra linear stack per call-site.
3388 // These g_warning/g_error wrappers fix that. It is not the
3389 // small wasm stack, but conserving it is still desirable.
3391 g_warning_d (const char *format
, int d
)
3393 g_warning (format
, d
);
3397 g_warning_ds (const char *format
, int d
, const char *s
)
3399 g_warning (format
, d
, s
);
3402 #if !USE_COMPUTED_GOTO
3404 g_error_xsx (const char *format
, int x1
, const char *s
, int x2
)
3406 g_error (format
, x1
, s
, x2
);
3410 static MONO_ALWAYS_INLINE gboolean
3411 method_entry (ThreadContext
*context
, InterpFrame
*frame
,
3415 MonoException
**out_ex
, FrameClauseArgs
*clause_args
)
3417 gboolean slow
= FALSE
;
3420 debug_enter (frame
, out_tracing
);
3424 if (!G_UNLIKELY (frame
->imethod
->transformed
)) {
3427 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
3428 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
3432 MonoException
*ex
= do_transform_method (frame
, context
);
3439 if (!clause_args
|| clause_args
->base_frame
)
3440 alloc_stack_data (context
, frame
, frame
->imethod
->alloca_size
);
3445 /* Save the state of the interpeter main loop into FRAME */
3446 #define SAVE_INTERP_STATE(frame) do { \
3447 frame->state.ip = ip; \
3448 frame->state.sp = sp; \
3449 frame->state.vt_sp = vt_sp; \
3450 frame->state.is_void = is_void; \
3451 frame->state.finally_ips = finally_ips; \
3452 frame->state.clause_args = clause_args; \
3455 /* Load and clear state from FRAME */
3456 #define LOAD_INTERP_STATE(frame) do { \
3457 ip = frame->state.ip; \
3458 sp = frame->state.sp; \
3459 is_void = frame->state.is_void; \
3460 vt_sp = frame->state.vt_sp; \
3461 finally_ips = frame->state.finally_ips; \
3462 clause_args = frame->state.clause_args; \
3463 locals = (unsigned char *)frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size; \
3464 frame->state.ip = NULL; \
3467 /* Initialize interpreter state for executing FRAME */
3468 #define INIT_INTERP_STATE(frame, _clause_args) do { \
3469 ip = _clause_args ? (_clause_args)->start_with_ip : (frame)->imethod->code; \
3470 sp = (frame)->stack; \
3471 vt_sp = (unsigned char *) sp + (frame)->imethod->stack_size; \
3472 locals = (unsigned char *) vt_sp + (frame)->imethod->vt_stack_size; \
3473 finally_ips = NULL; \
3477 * If CLAUSE_ARGS is non-null, start executing from it.
3478 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3479 * to return error information.
3480 * FRAME is only valid until the next call to alloc_frame ().
3482 static MONO_NEVER_INLINE
void
3483 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
)
3485 InterpMethod
*cmethod
;
3490 /* Interpreter main loop state (InterpState) */
3491 const guint16
*ip
= NULL
;
3493 unsigned char *vt_sp
;
3494 unsigned char *locals
= NULL
;
3495 GSList
*finally_ips
= NULL
;
3497 InterpFrame
*child_frame
;
3499 int tracing
= global_tracing
;
3500 unsigned char *vtalloc
;
3502 #if USE_COMPUTED_GOTO
3503 static void * const in_labels
[] = {
3504 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3505 #include "mintops.def"
3509 if (method_entry (context
, frame
,
3513 &ex
, clause_args
)) {
3515 THROW_EX (ex
, NULL
);
3516 EXCEPTION_CHECKPOINT
;
3519 if (clause_args
&& clause_args
->base_frame
)
3520 memcpy (frame
->stack
, clause_args
->base_frame
->stack
, frame
->imethod
->alloca_size
);
3522 INIT_INTERP_STATE (frame
, clause_args
);
3528 if (clause_args
&& clause_args
->filter_exception
) {
3529 sp
->data
.p
= clause_args
->filter_exception
;
3533 #ifdef ENABLE_EXPERIMENT_TIERED
3534 mini_tiered_inc (frame
->imethod
->domain
, frame
->imethod
->method
, &frame
->imethod
->tiered_counter
, 0);
3536 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3538 #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND)
3539 mono_threads_safepoint ();
3542 * using while (ip < end) may result in a 15% performance drop,
3543 * but it may be useful for debug
3548 /* g_assert (sp >= frame->stack); */
3549 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3551 MINT_IN_SWITCH (*ip
) {
3552 MINT_IN_CASE(MINT_INITLOCALS
)
3553 memset (locals
, 0, frame
->imethod
->locals_size
);
3556 MINT_IN_CASE(MINT_NOP
)
3557 MINT_IN_CASE(MINT_NIY
)
3558 g_assert_not_reached ();
3560 MINT_IN_CASE(MINT_BREAK
)
3562 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3564 MINT_IN_CASE(MINT_BREAKPOINT
)
3568 MINT_IN_CASE(MINT_LDNULL
)
3573 MINT_IN_CASE(MINT_ARGLIST
)
3575 *(gpointer
*)sp
->data
.p
= ((gpointer
*)frame
->retval
->data
.p
) [-1];
3576 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3580 MINT_IN_CASE(MINT_VTRESULT
) {
3581 int ret_size
= ip
[1];
3582 unsigned char *ret_vt_sp
= vt_sp
;
3583 vt_sp
-= READ32(ip
+ 2);
3585 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3586 sp
[-1].data
.p
= vt_sp
;
3587 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3592 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3593 MINT_IN_CASE(MINT_LDC_I4_M1
)
3596 MINT_IN_CASE(MINT_LDC_I4_0
)
3599 MINT_IN_CASE(MINT_LDC_I4_1
)
3602 MINT_IN_CASE(MINT_LDC_I4_2
)
3605 MINT_IN_CASE(MINT_LDC_I4_3
)
3608 MINT_IN_CASE(MINT_LDC_I4_4
)
3611 MINT_IN_CASE(MINT_LDC_I4_5
)
3614 MINT_IN_CASE(MINT_LDC_I4_6
)
3617 MINT_IN_CASE(MINT_LDC_I4_7
)
3620 MINT_IN_CASE(MINT_LDC_I4_8
)
3623 MINT_IN_CASE(MINT_LDC_I4_S
)
3624 sp
->data
.i
= (short)ip
[1];
3628 MINT_IN_CASE(MINT_LDC_I4
)
3630 sp
->data
.i
= READ32 (ip
);
3634 MINT_IN_CASE(MINT_LDC_I8
)
3636 sp
->data
.l
= READ64 (ip
);
3640 MINT_IN_CASE(MINT_LDC_I8_S
)
3641 sp
->data
.l
= (short)ip
[1];
3645 MINT_IN_CASE(MINT_LDC_R4
) {
3649 sp
->data
.f_r4
= * (float *)&val
;
3654 MINT_IN_CASE(MINT_LDC_R8
)
3655 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3659 MINT_IN_CASE(MINT_DUP
)
3664 MINT_IN_CASE(MINT_DUP_VT
) {
3665 int const i32
= READ32 (ip
+ 1);
3667 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3668 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3673 MINT_IN_CASE(MINT_POP
) {
3678 MINT_IN_CASE(MINT_POP1
) {
3684 MINT_IN_CASE(MINT_JMP
) {
3685 g_assert (sp
== frame
->stack
);
3686 InterpMethod
*new_method
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3688 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3689 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
3691 if (!new_method
->transformed
) {
3692 error_init_reuse (error
);
3695 mono_interp_transform_method (new_method
, context
, error
);
3696 MonoException
*ex
= mono_error_convert_to_exception (error
);
3701 const gboolean realloc_frame
= new_method
->alloca_size
> frame
->imethod
->alloca_size
;
3702 frame
->imethod
= new_method
;
3704 * We allocate the stack frame from scratch and store the arguments in the
3705 * locals again since it's possible for the caller stack frame to be smaller
3706 * than the callee stack frame (at the interp level)
3708 if (realloc_frame
) {
3709 //frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3710 alloc_stack_data (context
, frame
, frame
->imethod
->alloca_size
);
3711 memset (frame
->stack
, 0, frame
->imethod
->alloca_size
);
3714 vt_sp
= (unsigned char *) sp
+ frame
->imethod
->stack_size
;
3718 locals
= vt_sp
+ frame
->imethod
->vt_stack_size
;
3719 ip
= frame
->imethod
->code
;
3722 MINT_IN_CASE(MINT_CALLI
) {
3723 MonoMethodSignature
*csignature
;
3727 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3731 cmethod
= (InterpMethod
*)sp
->data
.p
;
3732 if (cmethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3733 cmethod
= mono_interp_get_imethod (frame
->imethod
->domain
, mono_marshal_get_native_wrapper (cmethod
->method
, FALSE
, FALSE
), error
);
3734 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3737 is_void
= csignature
->ret
->type
== MONO_TYPE_VOID
;
3738 retval
= is_void
? NULL
: sp
;
3741 /* decrement by the actual number of args */
3742 sp
-= csignature
->param_count
;
3743 if (csignature
->hasthis
)
3746 if (csignature
->hasthis
) {
3747 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3749 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3750 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3751 sp
[0].data
.p
= unboxed
;
3757 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3758 gpointer target_ip
= sp
[-1].data
.p
;
3759 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3760 int opcode
= ip
[2];
3761 gboolean save_last_error
= ip
[3];
3766 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3767 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
3768 CHECK_RESUME_STATE (context
);
3772 MINT_IN_CASE(MINT_CALLI_NAT
) {
3773 MonoMethodSignature
* csignature
;
3777 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3781 guchar
* const code
= (guchar
*)sp
->data
.p
;
3783 child_frame
= alloc_frame (context
, &retval
, frame
, NULL
, NULL
, retval
);
3786 /* decrement by the actual number of args */
3787 sp
-= csignature
->param_count
;
3788 if (csignature
->hasthis
)
3790 child_frame
->stack_args
= sp
;
3792 if (frame
->imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3793 mono_interp_calli_nat_dynamic_pinvoke (child_frame
, code
, context
, csignature
, error
);
3795 const gboolean save_last_error
= ip
[-3 + 2];
3796 ves_pinvoke_method (child_frame
, csignature
, (MonoFuncV
) code
, context
, save_last_error
);
3798 CHECK_RESUME_STATE (context
);
3800 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3806 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3807 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3808 MonoObject
*this_arg
;
3809 is_void
= *ip
== MINT_VCALLVIRT_FAST
;
3814 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3815 slot
= (gint16
)ip
[2];
3819 retval
= is_void
? NULL
: sp
;
3821 /* decrement by the actual number of args */
3822 sp
-= cmethod
->param_count
+ cmethod
->hasthis
;
3824 this_arg
= (MonoObject
*)sp
->data
.p
;
3826 cmethod
= get_virtual_method_fast (cmethod
, this_arg
->vtable
, slot
);
3827 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (cmethod
->method
->klass
)) {
3829 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3830 sp
[0].data
.p
= unboxed
;
3833 InterpMethodCodeType code_type
= cmethod
->code_type
;
3835 g_assert (code_type
== IMETHOD_CODE_UNKNOWN
||
3836 code_type
== IMETHOD_CODE_INTERP
||
3837 code_type
== IMETHOD_CODE_COMPILED
);
3839 if (G_UNLIKELY (code_type
== IMETHOD_CODE_UNKNOWN
)) {
3840 MonoMethodSignature
*sig
= mono_method_signature_internal (cmethod
->method
);
3841 if (mono_interp_jit_call_supported (cmethod
->method
, sig
))
3842 code_type
= IMETHOD_CODE_COMPILED
;
3844 code_type
= IMETHOD_CODE_INTERP
;
3845 cmethod
->code_type
= code_type
;
3848 if (code_type
== IMETHOD_CODE_INTERP
) {
3852 } else if (code_type
== IMETHOD_CODE_COMPILED
) {
3853 error_init_reuse (error
);
3854 do_jit_call (sp
, vt_sp
, context
, frame
, cmethod
, error
);
3855 if (!is_ok (error
)) {
3856 MonoException
*ex
= mono_error_convert_to_exception (error
);
3860 CHECK_RESUME_STATE (context
);
3862 if (cmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3868 MINT_IN_CASE(MINT_CALL_VARARG
) {
3869 MonoMethodSignature
*csig
;
3871 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3873 /* The real signature for vararg calls */
3874 csig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3878 // Retval must be set unconditionally due to MINT_ARGLIST.
3879 // is_void guides exit_frame instead of retval nullness.
3881 is_void
= csig
->ret
->type
== MONO_TYPE_VOID
;
3883 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3884 vt_sp
= copy_varargs_vtstack (csig
, sp
, vt_sp
);
3889 /* decrement by the actual number of args */
3890 // FIXME This seems excessive: frame and csig param_count.
3891 sp
-= cmethod
->param_count
+ cmethod
->hasthis
+ csig
->param_count
- csig
->sentinelpos
;
3895 MINT_IN_CASE(MINT_VCALL
)
3896 MINT_IN_CASE(MINT_CALL
)
3897 MINT_IN_CASE(MINT_CALLVIRT
)
3898 MINT_IN_CASE(MINT_VCALLVIRT
) {
3899 // FIXME CALLVIRT opcodes are not used on netcore. We should kill them.
3900 // FIXME braces from here until call: label.
3901 is_void
= *ip
== MINT_VCALL
|| *ip
== MINT_VCALLVIRT
;
3902 gboolean is_virtual
;
3903 is_virtual
= *ip
== MINT_CALLVIRT
|| *ip
== MINT_VCALLVIRT
;
3905 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3907 retval
= is_void
? NULL
: sp
;
3909 /* decrement by the actual number of args */
3913 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3915 cmethod
= get_virtual_method (cmethod
, this_arg
->vtable
);
3916 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (cmethod
->method
->klass
)) {
3918 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3919 sp
[0].data
.p
= unboxed
;
3924 #ifdef ENABLE_EXPERIMENT_TIERED
3930 // FIXME This assumes a grow-down stack.
3931 gpointer native_stack_addr
= frame
->native_stack_addr
? (gpointer
)((guint8
*)frame
->native_stack_addr
- 1) : (gpointer
)&retval
;
3934 * Make a non-recursive call by loading the new interpreter state based on child frame,
3935 * and going back to the main loop.
3937 SAVE_INTERP_STATE (frame
);
3939 frame
= alloc_frame (context
, native_stack_addr
, frame
, cmethod
, sp
, retval
);
3944 if (method_entry (context
, frame
,
3950 THROW_EX (ex
, NULL
);
3951 EXCEPTION_CHECKPOINT
;
3955 INIT_INTERP_STATE (frame
, clause_args
);
3959 MINT_IN_CASE(MINT_JIT_CALL
) {
3960 InterpMethod
*rmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3961 error_init_reuse (error
);
3963 sp
-= rmethod
->param_count
+ rmethod
->hasthis
;
3964 do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3965 if (!is_ok (error
)) {
3966 MonoException
*ex
= mono_error_convert_to_exception (error
);
3971 CHECK_RESUME_STATE (context
);
3973 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3978 MINT_IN_CASE(MINT_JIT_CALL2
) {
3979 #ifdef ENABLE_EXPERIMENT_TIERED
3980 InterpMethod
*rmethod
= (InterpMethod
*) READ64 (ip
+ 1);
3982 error_init_reuse (error
);
3985 sp
-= rmethod
->param_count
+ rmethod
->hasthis
;
3986 do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3987 if (!is_ok (error
)) {
3988 MonoException
*ex
= mono_error_convert_to_exception (error
);
3993 CHECK_RESUME_STATE (context
);
3995 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3998 g_error ("MINT_JIT_ICALL2 shouldn't be used");
4002 MINT_IN_CASE(MINT_CALLRUN
) {
4003 #ifndef ENABLE_NETCORE
4004 MonoMethod
*target_method
= (MonoMethod
*) frame
->imethod
->data_items
[ip
[1]];
4005 MonoMethodSignature
*sig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
4010 sp
-= sig
->param_count
;
4014 MonoException
*ex
= ves_imethod (frame
, target_method
, sig
, sp
, retval
);
4018 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
4024 g_assert_not_reached ();
4028 MINT_IN_CASE(MINT_RET
)
4030 *frame
->retval
= *sp
;
4031 if (sp
> frame
->stack
)
4032 g_warning_d ("ret: more values on stack: %d", sp
- frame
->stack
);
4034 MINT_IN_CASE(MINT_RET_VOID
)
4035 if (sp
> frame
->stack
)
4036 g_warning_ds ("ret.void: more values on stack: %d %s", sp
- frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
4038 MINT_IN_CASE(MINT_RET_VT
) {
4039 int const i32
= READ32 (ip
+ 1);
4041 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
4042 if (sp
> frame
->stack
)
4043 g_warning_d ("ret.vt: more values on stack: %d", sp
- frame
->stack
);
4047 #ifdef ENABLE_EXPERIMENT_TIERED
4048 #define BACK_BRANCH_PROFILE(offset) do { \
4050 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0); \
4053 #define BACK_BRANCH_PROFILE(offset)
4056 MINT_IN_CASE(MINT_BR_S
) {
4057 short br_offset
= (short) *(ip
+ 1);
4058 BACK_BRANCH_PROFILE (br_offset
);
4062 MINT_IN_CASE(MINT_BR
) {
4063 gint32 br_offset
= (gint32
) READ32(ip
+ 1);
4064 BACK_BRANCH_PROFILE (br_offset
);
4069 #define ZEROP_S(datamem, op) \
4071 if (sp->data.datamem op 0) { \
4072 gint16 br_offset = (gint16) ip [1]; \
4073 BACK_BRANCH_PROFILE (br_offset); \
4078 #define ZEROP(datamem, op) \
4080 if (sp->data.datamem op 0) { \
4081 gint32 br_offset = (gint32)READ32(ip + 1); \
4082 BACK_BRANCH_PROFILE (br_offset); \
4087 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
4090 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
4093 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
4096 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
4099 MINT_IN_CASE(MINT_BRFALSE_I4
)
4102 MINT_IN_CASE(MINT_BRFALSE_I8
)
4105 MINT_IN_CASE(MINT_BRFALSE_R4
)
4108 MINT_IN_CASE(MINT_BRFALSE_R8
)
4111 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
4114 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
4117 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
4120 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
4123 MINT_IN_CASE(MINT_BRTRUE_I4
)
4126 MINT_IN_CASE(MINT_BRTRUE_I8
)
4129 MINT_IN_CASE(MINT_BRTRUE_R4
)
4132 MINT_IN_CASE(MINT_BRTRUE_R8
)
4135 #define CONDBR_S(cond) \
4138 gint16 br_offset = (gint16) ip [1]; \
4139 BACK_BRANCH_PROFILE (br_offset); \
4143 #define BRELOP_S(datamem, op) \
4144 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
4146 #define CONDBR(cond) \
4149 gint32 br_offset = (gint32) READ32 (ip + 1); \
4150 BACK_BRANCH_PROFILE (br_offset); \
4155 #define BRELOP(datamem, op) \
4156 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
4158 MINT_IN_CASE(MINT_BEQ_I4_S
)
4161 MINT_IN_CASE(MINT_BEQ_I8_S
)
4164 MINT_IN_CASE(MINT_BEQ_R4_S
)
4165 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
4167 MINT_IN_CASE(MINT_BEQ_R8_S
)
4168 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
4170 MINT_IN_CASE(MINT_BEQ_I4
)
4173 MINT_IN_CASE(MINT_BEQ_I8
)
4176 MINT_IN_CASE(MINT_BEQ_R4
)
4177 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
4179 MINT_IN_CASE(MINT_BEQ_R8
)
4180 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
4182 MINT_IN_CASE(MINT_BGE_I4_S
)
4185 MINT_IN_CASE(MINT_BGE_I8_S
)
4188 MINT_IN_CASE(MINT_BGE_R4_S
)
4189 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4191 MINT_IN_CASE(MINT_BGE_R8_S
)
4192 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
4194 MINT_IN_CASE(MINT_BGE_I4
)
4197 MINT_IN_CASE(MINT_BGE_I8
)
4200 MINT_IN_CASE(MINT_BGE_R4
)
4201 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4203 MINT_IN_CASE(MINT_BGE_R8
)
4204 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
4206 MINT_IN_CASE(MINT_BGT_I4_S
)
4209 MINT_IN_CASE(MINT_BGT_I8_S
)
4212 MINT_IN_CASE(MINT_BGT_R4_S
)
4213 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4215 MINT_IN_CASE(MINT_BGT_R8_S
)
4216 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
4218 MINT_IN_CASE(MINT_BGT_I4
)
4221 MINT_IN_CASE(MINT_BGT_I8
)
4224 MINT_IN_CASE(MINT_BGT_R4
)
4225 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4227 MINT_IN_CASE(MINT_BGT_R8
)
4228 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
4230 MINT_IN_CASE(MINT_BLT_I4_S
)
4233 MINT_IN_CASE(MINT_BLT_I8_S
)
4236 MINT_IN_CASE(MINT_BLT_R4_S
)
4237 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4239 MINT_IN_CASE(MINT_BLT_R8_S
)
4240 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
4242 MINT_IN_CASE(MINT_BLT_I4
)
4245 MINT_IN_CASE(MINT_BLT_I8
)
4248 MINT_IN_CASE(MINT_BLT_R4
)
4249 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4251 MINT_IN_CASE(MINT_BLT_R8
)
4252 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
4254 MINT_IN_CASE(MINT_BLE_I4_S
)
4257 MINT_IN_CASE(MINT_BLE_I8_S
)
4260 MINT_IN_CASE(MINT_BLE_R4_S
)
4261 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4263 MINT_IN_CASE(MINT_BLE_R8_S
)
4264 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
4266 MINT_IN_CASE(MINT_BLE_I4
)
4269 MINT_IN_CASE(MINT_BLE_I8
)
4272 MINT_IN_CASE(MINT_BLE_R4
)
4273 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4275 MINT_IN_CASE(MINT_BLE_R8
)
4276 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
4278 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
4281 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
4284 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
4285 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
4287 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
4288 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
4290 MINT_IN_CASE(MINT_BNE_UN_I4
)
4293 MINT_IN_CASE(MINT_BNE_UN_I8
)
4296 MINT_IN_CASE(MINT_BNE_UN_R4
)
4297 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
4299 MINT_IN_CASE(MINT_BNE_UN_R8
)
4300 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
4303 #define BRELOP_S_CAST(datamem, op, type) \
4305 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4306 gint16 br_offset = (gint16) ip [1]; \
4307 BACK_BRANCH_PROFILE (br_offset); \
4312 #define BRELOP_CAST(datamem, op, type) \
4314 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4315 gint32 br_offset = (gint32) ip [1]; \
4316 BACK_BRANCH_PROFILE (br_offset); \
4321 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
4322 BRELOP_S_CAST(i
, >=, guint32
);
4324 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
4325 BRELOP_S_CAST(l
, >=, guint64
);
4327 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
4328 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4330 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
4331 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4333 MINT_IN_CASE(MINT_BGE_UN_I4
)
4334 BRELOP_CAST(i
, >=, guint32
);
4336 MINT_IN_CASE(MINT_BGE_UN_I8
)
4337 BRELOP_CAST(l
, >=, guint64
);
4339 MINT_IN_CASE(MINT_BGE_UN_R4
)
4340 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4342 MINT_IN_CASE(MINT_BGE_UN_R8
)
4343 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4345 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
4346 BRELOP_S_CAST(i
, >, guint32
);
4348 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
4349 BRELOP_S_CAST(l
, >, guint64
);
4351 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
4352 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4354 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
4355 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4357 MINT_IN_CASE(MINT_BGT_UN_I4
)
4358 BRELOP_CAST(i
, >, guint32
);
4360 MINT_IN_CASE(MINT_BGT_UN_I8
)
4361 BRELOP_CAST(l
, >, guint64
);
4363 MINT_IN_CASE(MINT_BGT_UN_R4
)
4364 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4366 MINT_IN_CASE(MINT_BGT_UN_R8
)
4367 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4369 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
4370 BRELOP_S_CAST(i
, <=, guint32
);
4372 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
4373 BRELOP_S_CAST(l
, <=, guint64
);
4375 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
4376 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4378 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
4379 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4381 MINT_IN_CASE(MINT_BLE_UN_I4
)
4382 BRELOP_CAST(i
, <=, guint32
);
4384 MINT_IN_CASE(MINT_BLE_UN_I8
)
4385 BRELOP_CAST(l
, <=, guint64
);
4387 MINT_IN_CASE(MINT_BLE_UN_R4
)
4388 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4390 MINT_IN_CASE(MINT_BLE_UN_R8
)
4391 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4393 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
4394 BRELOP_S_CAST(i
, <, guint32
);
4396 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
4397 BRELOP_S_CAST(l
, <, guint64
);
4399 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
4400 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4402 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
4403 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4405 MINT_IN_CASE(MINT_BLT_UN_I4
)
4406 BRELOP_CAST(i
, <, guint32
);
4408 MINT_IN_CASE(MINT_BLT_UN_I8
)
4409 BRELOP_CAST(l
, <, guint64
);
4411 MINT_IN_CASE(MINT_BLT_UN_R4
)
4412 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4414 MINT_IN_CASE(MINT_BLT_UN_R8
)
4415 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4417 MINT_IN_CASE(MINT_SWITCH
) {
4419 const unsigned short *st
;
4425 if ((guint32
)sp
->data
.i
< n
) {
4427 ip
+= 2 * (guint32
)sp
->data
.i
;
4428 offset
= READ32 (ip
);
4435 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
4436 NULL_CHECK (sp
[-1].data
.p
);
4438 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
4440 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
4441 NULL_CHECK (sp
[-1].data
.p
);
4443 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
4445 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
4446 NULL_CHECK (sp
[-1].data
.p
);
4448 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
4450 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
4451 NULL_CHECK (sp
[-1].data
.p
);
4453 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
4455 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
4456 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
4457 NULL_CHECK (sp
[-1].data
.p
);
4459 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
4461 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
4462 NULL_CHECK (sp
[-1].data
.p
);
4464 #ifdef NO_UNALIGNED_ACCESS
4465 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4466 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
4469 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
4471 MINT_IN_CASE(MINT_LDIND_I
) {
4472 guint16 offset
= ip
[1];
4473 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
4477 MINT_IN_CASE(MINT_LDIND_I8
) {
4478 guint16 offset
= ip
[1];
4479 #ifdef NO_UNALIGNED_ACCESS
4480 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
4481 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
4484 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
4488 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
4489 NULL_CHECK (sp
[-1].data
.p
);
4491 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
4493 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
4494 NULL_CHECK (sp
[-1].data
.p
);
4496 #ifdef NO_UNALIGNED_ACCESS
4497 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4498 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
4501 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
4503 MINT_IN_CASE(MINT_LDIND_REF
)
4505 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4507 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
4508 NULL_CHECK (sp
[-1].data
.p
);
4510 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4513 MINT_IN_CASE(MINT_STIND_REF
)
4516 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
4518 MINT_IN_CASE(MINT_STIND_I1
)
4521 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
4523 MINT_IN_CASE(MINT_STIND_I2
)
4526 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
4528 MINT_IN_CASE(MINT_STIND_I4
)
4531 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
4533 MINT_IN_CASE(MINT_STIND_I
)
4536 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
4538 MINT_IN_CASE(MINT_STIND_I8
)
4541 #ifdef NO_UNALIGNED_ACCESS
4542 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4543 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
4546 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
4548 MINT_IN_CASE(MINT_STIND_R4
)
4551 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
4553 MINT_IN_CASE(MINT_STIND_R8
)
4556 #ifdef NO_UNALIGNED_ACCESS
4557 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4558 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
4561 * (double *) sp
->data
.p
= sp
[1].data
.f
;
4563 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
4566 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
4568 #define BINOP(datamem, op) \
4570 sp [-1].data.datamem op ## = sp [0].data.datamem; \
4572 MINT_IN_CASE(MINT_ADD_I4
)
4575 MINT_IN_CASE(MINT_ADD_I8
)
4578 MINT_IN_CASE(MINT_ADD_R4
)
4581 MINT_IN_CASE(MINT_ADD_R8
)
4584 MINT_IN_CASE(MINT_ADD1_I4
)
4588 MINT_IN_CASE(MINT_ADD1_I8
)
4592 MINT_IN_CASE(MINT_LOCADD1_I4
)
4593 *(gint32
*)(locals
+ ip
[1]) += 1;
4596 MINT_IN_CASE(MINT_LOCADD1_I8
)
4597 *(gint64
*)(locals
+ ip
[1]) += 1;
4600 MINT_IN_CASE(MINT_SUB_I4
)
4603 MINT_IN_CASE(MINT_SUB_I8
)
4606 MINT_IN_CASE(MINT_SUB_R4
)
4609 MINT_IN_CASE(MINT_SUB_R8
)
4612 MINT_IN_CASE(MINT_SUB1_I4
)
4616 MINT_IN_CASE(MINT_SUB1_I8
)
4620 MINT_IN_CASE(MINT_LOCSUB1_I4
)
4621 *(gint32
*)(locals
+ ip
[1]) -= 1;
4624 MINT_IN_CASE(MINT_LOCSUB1_I8
)
4625 *(gint64
*)(locals
+ ip
[1]) -= 1;
4627 MINT_IN_CASE(MINT_MUL_I4
)
4630 MINT_IN_CASE(MINT_MUL_I8
)
4633 MINT_IN_CASE(MINT_MUL_R4
)
4636 MINT_IN_CASE(MINT_MUL_R8
)
4639 MINT_IN_CASE(MINT_DIV_I4
)
4640 if (sp
[-1].data
.i
== 0)
4641 goto div_zero_label
;
4642 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4643 goto overflow_label
;
4646 MINT_IN_CASE(MINT_DIV_I8
)
4647 if (sp
[-1].data
.l
== 0)
4648 goto div_zero_label
;
4649 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4650 goto overflow_label
;
4653 MINT_IN_CASE(MINT_DIV_R4
)
4656 MINT_IN_CASE(MINT_DIV_R8
)
4660 #define BINOP_CAST(datamem, op, type) \
4662 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4664 MINT_IN_CASE(MINT_DIV_UN_I4
)
4665 if (sp
[-1].data
.i
== 0)
4666 goto div_zero_label
;
4667 BINOP_CAST(i
, /, guint32
);
4669 MINT_IN_CASE(MINT_DIV_UN_I8
)
4670 if (sp
[-1].data
.l
== 0)
4671 goto div_zero_label
;
4672 BINOP_CAST(l
, /, guint64
);
4674 MINT_IN_CASE(MINT_REM_I4
)
4675 if (sp
[-1].data
.i
== 0)
4676 goto div_zero_label
;
4677 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4678 goto overflow_label
;
4681 MINT_IN_CASE(MINT_REM_I8
)
4682 if (sp
[-1].data
.l
== 0)
4683 goto div_zero_label
;
4684 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4685 goto overflow_label
;
4688 MINT_IN_CASE(MINT_REM_R4
)
4689 /* FIXME: what do we actually do here? */
4691 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4694 MINT_IN_CASE(MINT_REM_R8
)
4695 /* FIXME: what do we actually do here? */
4697 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4700 MINT_IN_CASE(MINT_REM_UN_I4
)
4701 if (sp
[-1].data
.i
== 0)
4702 goto div_zero_label
;
4703 BINOP_CAST(i
, %, guint32
);
4705 MINT_IN_CASE(MINT_REM_UN_I8
)
4706 if (sp
[-1].data
.l
== 0)
4707 goto div_zero_label
;
4708 BINOP_CAST(l
, %, guint64
);
4710 MINT_IN_CASE(MINT_AND_I4
)
4713 MINT_IN_CASE(MINT_AND_I8
)
4716 MINT_IN_CASE(MINT_OR_I4
)
4719 MINT_IN_CASE(MINT_OR_I8
)
4722 MINT_IN_CASE(MINT_XOR_I4
)
4725 MINT_IN_CASE(MINT_XOR_I8
)
4729 #define SHIFTOP(datamem, op) \
4731 sp [-1].data.datamem op ## = sp [0].data.i; \
4734 MINT_IN_CASE(MINT_SHL_I4
)
4737 MINT_IN_CASE(MINT_SHL_I8
)
4740 MINT_IN_CASE(MINT_SHR_I4
)
4743 MINT_IN_CASE(MINT_SHR_I8
)
4746 MINT_IN_CASE(MINT_SHR_UN_I4
)
4748 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4751 MINT_IN_CASE(MINT_SHR_UN_I8
)
4753 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4756 MINT_IN_CASE(MINT_NEG_I4
)
4757 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4760 MINT_IN_CASE(MINT_NEG_I8
)
4761 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4764 MINT_IN_CASE(MINT_NEG_R4
)
4765 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4768 MINT_IN_CASE(MINT_NEG_R8
)
4769 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4772 MINT_IN_CASE(MINT_NOT_I4
)
4773 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4776 MINT_IN_CASE(MINT_NOT_I8
)
4777 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4780 MINT_IN_CASE(MINT_CONV_I1_I4
)
4781 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4784 MINT_IN_CASE(MINT_CONV_I1_I8
)
4785 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4788 MINT_IN_CASE(MINT_CONV_I1_R4
)
4789 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4792 MINT_IN_CASE(MINT_CONV_I1_R8
)
4793 /* without gint32 cast, C compiler is allowed to use undefined
4794 * behaviour if data.f is bigger than >255. See conv.fpint section
4796 * > The conversion truncates; that is, the fractional part
4797 * > is discarded. The behavior is undefined if the truncated
4798 * > value cannot be represented in the destination type.
4800 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4803 MINT_IN_CASE(MINT_CONV_U1_I4
)
4804 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4807 MINT_IN_CASE(MINT_CONV_U1_I8
)
4808 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4811 MINT_IN_CASE(MINT_CONV_U1_R4
)
4812 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4815 MINT_IN_CASE(MINT_CONV_U1_R8
)
4816 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4819 MINT_IN_CASE(MINT_CONV_I2_I4
)
4820 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4823 MINT_IN_CASE(MINT_CONV_I2_I8
)
4824 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4827 MINT_IN_CASE(MINT_CONV_I2_R4
)
4828 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4831 MINT_IN_CASE(MINT_CONV_I2_R8
)
4832 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4835 MINT_IN_CASE(MINT_CONV_U2_I4
)
4836 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4839 MINT_IN_CASE(MINT_CONV_U2_I8
)
4840 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4843 MINT_IN_CASE(MINT_CONV_U2_R4
)
4844 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4847 MINT_IN_CASE(MINT_CONV_U2_R8
)
4848 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4851 MINT_IN_CASE(MINT_CONV_I4_R4
)
4852 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4855 MINT_IN_CASE(MINT_CONV_I4_R8
)
4856 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4859 MINT_IN_CASE(MINT_CONV_U4_I8
)
4860 MINT_IN_CASE(MINT_CONV_I4_I8
)
4861 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4864 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4865 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4868 MINT_IN_CASE(MINT_CONV_U4_R4
)
4869 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4870 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4872 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4876 MINT_IN_CASE(MINT_CONV_U4_R8
)
4877 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4878 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
4880 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4884 MINT_IN_CASE(MINT_CONV_I8_I4
)
4885 sp
[-1].data
.l
= sp
[-1].data
.i
;
4888 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4889 sp
[-2].data
.l
= sp
[-2].data
.i
;
4892 MINT_IN_CASE(MINT_CONV_I8_U4
)
4893 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4896 MINT_IN_CASE(MINT_CONV_I8_R4
)
4897 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4900 MINT_IN_CASE(MINT_CONV_I8_R8
)
4901 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4904 MINT_IN_CASE(MINT_CONV_R4_I4
)
4905 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4908 MINT_IN_CASE(MINT_CONV_R4_I8
)
4909 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4912 MINT_IN_CASE(MINT_CONV_R4_R8
)
4913 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4916 MINT_IN_CASE(MINT_CONV_R8_I4
)
4917 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4920 MINT_IN_CASE(MINT_CONV_R8_I8
)
4921 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4924 MINT_IN_CASE(MINT_CONV_R8_R4
)
4925 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4928 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4929 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4932 MINT_IN_CASE(MINT_CONV_U8_R4
)
4933 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4934 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
4936 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4940 MINT_IN_CASE(MINT_CONV_U8_R8
)
4941 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4942 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
4944 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4948 MINT_IN_CASE(MINT_CPOBJ
) {
4949 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4950 g_assert (m_class_is_valuetype (c
));
4951 /* if this assertion fails, we need to add a write barrier */
4952 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4953 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4958 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4959 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4960 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4965 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4966 int size
= READ32(ip
+ 1);
4968 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4969 sp
[-1].data
.p
= vt_sp
;
4970 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4973 MINT_IN_CASE(MINT_LDSTR
)
4974 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
4978 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4979 MonoString
*s
= NULL
;
4980 guint32 strtoken
= (guint32
)(gsize
)frame
->imethod
->data_items
[ip
[1]];
4982 MonoMethod
*method
= frame
->imethod
->method
;
4983 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4984 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4985 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4986 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4988 g_assert_not_reached ();
4995 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4996 MonoClass
*newobj_class
;
4997 guint32 token
= ip
[1];
4998 guint16 param_count
= ip
[2];
5000 newobj_class
= (MonoClass
*) frame
->imethod
->data_items
[token
];
5003 sp
->data
.o
= ves_array_create (frame
->imethod
->domain
, newobj_class
, param_count
, sp
, error
);
5005 goto throw_error_label
;
5011 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
5012 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[3]];
5013 INIT_VTABLE (vtable
);
5014 MonoObject
*o
; // See the comment about GC safety.
5015 guint16 param_count
;
5016 guint16 imethod_index
= ip
[1];
5018 const gboolean is_inlined
= imethod_index
== INLINED_METHOD_FLAG
;
5020 param_count
= ip
[2];
5022 // Make room for two copies of o -- this parameter and return value.
5023 if (param_count
|| !is_inlined
) {
5025 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
5028 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5029 if (G_UNLIKELY (!o
)) {
5030 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
5031 goto throw_error_label
;
5034 // Store o next to and before the parameters on the stack so GC will see it,
5035 // and where it is needed when the call returns.
5040 sp
+= param_count
+ 2;
5042 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[imethod_index
];
5050 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
5051 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
5054 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
5055 guint16
const param_count
= ip
[2];
5057 // Make room for extra parameter and result.
5060 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
5063 gboolean
const vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
5065 memset (vt_sp
, 0, ip
[3]);
5067 // Put extra parameter and result on stack, before other parameters,
5068 // and point stack to extra parameter, after result.
5069 // This pattern occurs for newobj_vt_fast and newobj_fast.
5070 sp
[1].data
.p
= vt_sp
;
5071 sp
[0].data
.p
= vt_sp
;
5074 // Like newobj_fast, add valuetype_this parameter
5075 // and result and point stack to this after result.
5076 memset (sp
, 0, sizeof (*sp
));
5077 sp
[1].data
.p
= &sp
[0].data
; // valuetype_this == result
5080 // call_newobj captures the pattern where the return value is placed
5081 // on the stack before the call, instead of the call forming it.
5083 ++sp
; // Point sp at added extra param, after return value.
5088 MINT_IN_CASE(MINT_NEWOBJ
) {
5090 // This is split up to:
5092 // - keep exception handling and resume mostly in the main function
5096 guint32
const token
= ip
[1];
5097 ip
+= 2; // FIXME: Do this after throw?
5099 child_frame
= alloc_frame (context
, &dummy
, frame
, (InterpMethod
*)frame
->imethod
->data_items
[token
], NULL
, NULL
);
5100 MonoMethodSignature
* const csig
= mono_method_signature_internal (child_frame
->imethod
->method
);
5102 g_assert (csig
->hasthis
);
5103 if (csig
->param_count
) {
5104 sp
-= csig
->param_count
;
5105 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
5108 child_frame
->stack_args
= sp
;
5110 // FIXME remove recursion
5111 MonoException
* const exc
= mono_interp_newobj (child_frame
, context
, error
, vt_sp
);
5114 CHECK_RESUME_STATE (context
);
5118 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
5124 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
5125 MonoMethodSignature
*csig
;
5132 InterpMethod
*cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
5133 csig
= mono_method_signature_internal (cmethod
->method
);
5135 g_assert (csig
->hasthis
);
5136 sp
-= csig
->param_count
;
5138 gpointer arg0
= sp
[0].data
.p
;
5140 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
5141 *byreference_this
= arg0
;
5143 /* Followed by a VTRESULT opcode which will push the result on the stack */
5147 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
5148 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
5149 sp
[-1].data
.p
= *byreference_this
;
5153 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
5155 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
5160 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
5162 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
5167 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
5168 MonoObject
*obj
= sp
[-1].data
.o
;
5169 sp
[-1].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
5173 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
5174 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
5175 MonoObject
* const o
= sp
[-1].data
.o
;
5177 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5179 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
5181 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
5183 isinst
= mono_interp_isinst (o
, c
); // FIXME: do not swallow the error
5189 gboolean
const isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
5191 sp
[-1].data
.p
= NULL
;
5193 goto invalid_cast_label
;
5199 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
5200 MINT_IN_CASE(MINT_ISINST_COMMON
) {
5201 MonoObject
* const o
= sp
[-1].data
.o
;
5203 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5204 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
5207 gboolean
const isinst_instr
= *ip
== MINT_ISINST_COMMON
;
5209 sp
[-1].data
.p
= NULL
;
5211 goto invalid_cast_label
;
5217 MINT_IN_CASE(MINT_CASTCLASS
)
5218 MINT_IN_CASE(MINT_ISINST
) {
5219 MonoObject
* const o
= sp
[-1].data
.o
;
5221 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5222 if (!mono_interp_isinst (o
, c
)) { // FIXME: do not swallow the error
5223 gboolean
const isinst_instr
= *ip
== MINT_ISINST
;
5225 sp
[-1].data
.p
= NULL
;
5227 goto invalid_cast_label
;
5233 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
5234 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
5237 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
5238 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
5241 MINT_IN_CASE(MINT_UNBOX
) {
5242 MonoObject
* const o
= sp
[-1].data
.o
;
5244 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5246 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
5247 goto invalid_cast_label
;
5249 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
5253 MINT_IN_CASE(MINT_THROW
)
5256 sp
->data
.p
= mono_get_exception_null_reference ();
5258 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
5260 MINT_IN_CASE(MINT_CHECKPOINT
)
5261 /* Do synchronous checking of abort requests */
5262 EXCEPTION_CHECKPOINT
;
5265 MINT_IN_CASE(MINT_SAFEPOINT
)
5266 /* Do synchronous checking of abort requests */
5267 EXCEPTION_CHECKPOINT
;
5268 /* Poll safepoint */
5269 mono_threads_safepoint ();
5272 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
) {
5273 sp
[-1].data
.p
= (char*)sp
[-1].data
.o
+ ip
[1];
5277 MINT_IN_CASE(MINT_LDFLDA
) {
5278 MonoObject
* const o
= sp
[-1].data
.o
;
5280 sp
[-1].data
.p
= (char *)o
+ ip
[1];
5284 MINT_IN_CASE(MINT_CKNULL_N
) {
5285 /* Same as CKNULL, but further down the stack */
5286 int const n
= ip
[1];
5287 MonoObject
* const o
= sp
[-n
].data
.o
;
5293 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5294 MonoObject* const o = sp [-1].data.o; \
5297 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
5299 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
5303 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
5305 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
5306 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
5307 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
5308 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
5309 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
5310 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
5311 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
5312 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
5313 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
5314 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
5315 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5316 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5318 MINT_IN_CASE(MINT_LDFLD_VT
) {
5319 MonoObject
* const o
= sp
[-1].data
.o
;
5322 int size
= READ32(ip
+ 2);
5323 sp
[-1].data
.p
= vt_sp
;
5324 memcpy (sp
[-1].data
.p
, (char *)o
+ ip
[1], size
);
5325 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5330 MINT_IN_CASE(MINT_LDRMFLD
) {
5331 MonoObject
* const o
= sp
[-1].data
.o
;
5333 mono_interp_load_remote_field (frame
->imethod
, o
, ip
, sp
);
5337 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
5338 MonoObject
* const o
= sp
[-1].data
.o
;
5340 vt_sp
= mono_interp_load_remote_field_vt (frame
->imethod
, o
, ip
, sp
, vt_sp
);
5346 #define LDARGFLD(datamem, fieldtype) do { \
5347 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5349 sp [0].data.datamem = *(fieldtype *)((char *)o + ip [2]) ; \
5353 MINT_IN_CASE(MINT_LDARGFLD_I1
) LDARGFLD(i
, gint8
); MINT_IN_BREAK
;
5354 MINT_IN_CASE(MINT_LDARGFLD_U1
) LDARGFLD(i
, guint8
); MINT_IN_BREAK
;
5355 MINT_IN_CASE(MINT_LDARGFLD_I2
) LDARGFLD(i
, gint16
); MINT_IN_BREAK
;
5356 MINT_IN_CASE(MINT_LDARGFLD_U2
) LDARGFLD(i
, guint16
); MINT_IN_BREAK
;
5357 MINT_IN_CASE(MINT_LDARGFLD_I4
) LDARGFLD(i
, gint32
); MINT_IN_BREAK
;
5358 MINT_IN_CASE(MINT_LDARGFLD_I8
) LDARGFLD(l
, gint64
); MINT_IN_BREAK
;
5359 MINT_IN_CASE(MINT_LDARGFLD_R4
) LDARGFLD(f_r4
, float); MINT_IN_BREAK
;
5360 MINT_IN_CASE(MINT_LDARGFLD_R8
) LDARGFLD(f
, double); MINT_IN_BREAK
;
5361 MINT_IN_CASE(MINT_LDARGFLD_O
) LDARGFLD(p
, gpointer
); MINT_IN_BREAK
;
5362 MINT_IN_CASE(MINT_LDARGFLD_P
) LDARGFLD(p
, gpointer
); MINT_IN_BREAK
;
5364 #define LDLOCFLD(datamem, fieldtype) do { \
5365 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5367 sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \
5371 MINT_IN_CASE(MINT_LDLOCFLD_I1
) LDLOCFLD(i
, gint8
); MINT_IN_BREAK
;
5372 MINT_IN_CASE(MINT_LDLOCFLD_U1
) LDLOCFLD(i
, guint8
); MINT_IN_BREAK
;
5373 MINT_IN_CASE(MINT_LDLOCFLD_I2
) LDLOCFLD(i
, gint16
); MINT_IN_BREAK
;
5374 MINT_IN_CASE(MINT_LDLOCFLD_U2
) LDLOCFLD(i
, guint16
); MINT_IN_BREAK
;
5375 MINT_IN_CASE(MINT_LDLOCFLD_I4
) LDLOCFLD(i
, gint32
); MINT_IN_BREAK
;
5376 MINT_IN_CASE(MINT_LDLOCFLD_I8
) LDLOCFLD(l
, gint64
); MINT_IN_BREAK
;
5377 MINT_IN_CASE(MINT_LDLOCFLD_R4
) LDLOCFLD(f_r4
, float); MINT_IN_BREAK
;
5378 MINT_IN_CASE(MINT_LDLOCFLD_R8
) LDLOCFLD(f
, double); MINT_IN_BREAK
;
5379 MINT_IN_CASE(MINT_LDLOCFLD_O
) LDLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5380 MINT_IN_CASE(MINT_LDLOCFLD_P
) LDLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5382 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5383 MonoObject* const o = sp [-2].data.o; \
5387 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
5389 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
5393 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5395 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
5396 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
5397 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
5398 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
5399 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
5400 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
5401 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
5402 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
5403 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
5404 MINT_IN_CASE(MINT_STFLD_O
) {
5405 MonoObject
* const o
= sp
[-2].data
.o
;
5408 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[1], sp
[1].data
.o
);
5412 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5413 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5415 MINT_IN_CASE(MINT_STFLD_VT
) {
5416 MonoObject
* const o
= sp
[-2].data
.o
;
5420 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[2]];
5421 int const i32
= mono_class_value_size (klass
, NULL
);
5423 guint16 offset
= ip
[1];
5424 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
5426 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5430 MINT_IN_CASE(MINT_STRMFLD
) {
5431 MonoClassField
*field
;
5433 MonoObject
* const o
= sp
[-2].data
.o
;
5436 field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5439 #ifndef DISABLE_REMOTING
5440 if (mono_object_is_transparent_proxy (o
)) {
5441 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
5442 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
5443 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
5446 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
5451 MINT_IN_CASE(MINT_STRMFLD_VT
)
5453 NULL_CHECK (sp
[-2].data
.o
);
5454 vt_sp
-= mono_interp_store_remote_field_vt (frame
, ip
, sp
, error
);
5459 #define STARGFLD(datamem, fieldtype) do { \
5460 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5463 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5466 MINT_IN_CASE(MINT_STARGFLD_I1
) STARGFLD(i
, gint8
); MINT_IN_BREAK
;
5467 MINT_IN_CASE(MINT_STARGFLD_U1
) STARGFLD(i
, guint8
); MINT_IN_BREAK
;
5468 MINT_IN_CASE(MINT_STARGFLD_I2
) STARGFLD(i
, gint16
); MINT_IN_BREAK
;
5469 MINT_IN_CASE(MINT_STARGFLD_U2
) STARGFLD(i
, guint16
); MINT_IN_BREAK
;
5470 MINT_IN_CASE(MINT_STARGFLD_I4
) STARGFLD(i
, gint32
); MINT_IN_BREAK
;
5471 MINT_IN_CASE(MINT_STARGFLD_I8
) STARGFLD(l
, gint64
); MINT_IN_BREAK
;
5472 MINT_IN_CASE(MINT_STARGFLD_R4
) STARGFLD(f_r4
, float); MINT_IN_BREAK
;
5473 MINT_IN_CASE(MINT_STARGFLD_R8
) STARGFLD(f
, double); MINT_IN_BREAK
;
5474 MINT_IN_CASE(MINT_STARGFLD_P
) STARGFLD(p
, gpointer
); MINT_IN_BREAK
;
5475 MINT_IN_CASE(MINT_STARGFLD_O
) {
5476 MonoObject
*o
= frame
->stack_args
[ip
[1]].data
.o
;
5479 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[2], sp
[0].data
.o
);
5484 #define STLOCFLD(datamem, fieldtype) do { \
5485 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5488 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5491 MINT_IN_CASE(MINT_STLOCFLD_I1
) STLOCFLD(i
, gint8
); MINT_IN_BREAK
;
5492 MINT_IN_CASE(MINT_STLOCFLD_U1
) STLOCFLD(i
, guint8
); MINT_IN_BREAK
;
5493 MINT_IN_CASE(MINT_STLOCFLD_I2
) STLOCFLD(i
, gint16
); MINT_IN_BREAK
;
5494 MINT_IN_CASE(MINT_STLOCFLD_U2
) STLOCFLD(i
, guint16
); MINT_IN_BREAK
;
5495 MINT_IN_CASE(MINT_STLOCFLD_I4
) STLOCFLD(i
, gint32
); MINT_IN_BREAK
;
5496 MINT_IN_CASE(MINT_STLOCFLD_I8
) STLOCFLD(l
, gint64
); MINT_IN_BREAK
;
5497 MINT_IN_CASE(MINT_STLOCFLD_R4
) STLOCFLD(f_r4
, float); MINT_IN_BREAK
;
5498 MINT_IN_CASE(MINT_STLOCFLD_R8
) STLOCFLD(f
, double); MINT_IN_BREAK
;
5499 MINT_IN_CASE(MINT_STLOCFLD_P
) STLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5500 MINT_IN_CASE(MINT_STLOCFLD_O
) {
5501 MonoObject
*o
= *(MonoObject
**)(locals
+ ip
[1]);
5504 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[2], sp
[0].data
.o
);
5509 MINT_IN_CASE(MINT_LDSFLDA
) {
5510 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5511 INIT_VTABLE (vtable
);
5512 sp
->data
.p
= frame
->imethod
->data_items
[ip
[2]];
5518 MINT_IN_CASE(MINT_LDSSFLDA
) {
5519 guint32 offset
= READ32(ip
+ 1);
5520 sp
->data
.p
= mono_get_special_static_data (offset
);
5526 /* We init class here to preserve cctor order */
5527 #define LDSFLD(datamem, fieldtype) { \
5528 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5529 INIT_VTABLE (vtable); \
5530 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5535 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
5536 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
5537 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
5538 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
5539 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
5540 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
5541 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
5542 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
5543 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5544 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5546 MINT_IN_CASE(MINT_LDSFLD_VT
) {
5547 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5548 INIT_VTABLE (vtable
);
5551 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5552 int const i32
= READ32 (ip
+ 3);
5553 memcpy (vt_sp
, addr
, i32
);
5554 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5560 #define LDTSFLD(datamem, fieldtype) { \
5561 MonoInternalThread *thread = mono_thread_internal_current (); \
5562 guint32 offset = READ32 (ip + 1); \
5563 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5564 sp[0].data.datamem = *(fieldtype*)addr; \
5568 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
5569 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
5570 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
5571 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
5572 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
5573 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
5574 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
5575 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
5576 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5577 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5579 MINT_IN_CASE(MINT_LDSSFLD
) {
5580 guint32 offset
= READ32(ip
+ 2);
5581 gpointer addr
= mono_get_special_static_data (offset
);
5582 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5583 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
5588 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
5589 guint32 offset
= READ32(ip
+ 1);
5590 gpointer addr
= mono_get_special_static_data (offset
);
5592 int size
= READ32 (ip
+ 3);
5593 memcpy (vt_sp
, addr
, size
);
5595 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5600 #define STSFLD(datamem, fieldtype) { \
5601 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5602 INIT_VTABLE (vtable); \
5604 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5608 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5609 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5610 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5611 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5612 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5613 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5614 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5615 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5616 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5617 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5619 MINT_IN_CASE(MINT_STSFLD_VT
) {
5620 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5621 INIT_VTABLE (vtable
);
5622 int const i32
= READ32 (ip
+ 3);
5623 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5625 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5626 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5632 #define STTSFLD(datamem, fieldtype) { \
5633 MonoInternalThread *thread = mono_thread_internal_current (); \
5634 guint32 offset = READ32 (ip + 1); \
5635 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5637 *(fieldtype*)addr = sp[0].data.datamem; \
5641 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5642 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5643 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5644 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5645 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5646 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5647 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5648 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5649 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5650 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5652 MINT_IN_CASE(MINT_STSSFLD
) {
5653 guint32 offset
= READ32(ip
+ 2);
5654 gpointer addr
= mono_get_special_static_data (offset
);
5655 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5657 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5661 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5662 guint32 offset
= READ32(ip
+ 1);
5663 gpointer addr
= mono_get_special_static_data (offset
);
5665 int size
= READ32 (ip
+ 3);
5666 memcpy (addr
, sp
->data
.vt
, size
);
5667 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5672 MINT_IN_CASE(MINT_STOBJ_VT
) {
5674 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5676 size
= mono_class_value_size (c
, NULL
);
5677 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5678 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5682 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5683 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5684 goto overflow_label
;
5685 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5688 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5689 if (sp
[-1].data
.i
< 0)
5690 goto overflow_label
;
5691 sp
[-1].data
.l
= sp
[-1].data
.i
;
5694 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5695 if (sp
[-1].data
.l
< 0)
5696 goto overflow_label
;
5699 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5700 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5701 goto overflow_label
;
5704 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5705 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5706 goto overflow_label
;
5707 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5710 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5711 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5712 goto overflow_label
;
5713 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5716 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5717 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5718 goto overflow_label
;
5719 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5722 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
)
5723 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5724 goto overflow_label
;
5725 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5728 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5729 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5730 goto overflow_label
;
5731 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5734 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5735 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5736 goto overflow_label
;
5737 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5740 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5741 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5742 goto overflow_label
;
5743 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5746 MINT_IN_CASE(MINT_BOX
) {
5747 mono_interp_box (frame
, ip
, sp
);
5751 MINT_IN_CASE(MINT_BOX_VT
) {
5752 vt_sp
-= mono_interp_box_vt (frame
, ip
, sp
);
5756 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5757 vt_sp
-= mono_interp_box_nullable (frame
, ip
, sp
, error
);
5761 MINT_IN_CASE(MINT_NEWARR
) {
5762 MonoVTable
*vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
5763 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5764 if (!is_ok (error
)) {
5765 goto throw_error_label
;
5768 /*if (profiling_classes) {
5769 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5771 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5776 MINT_IN_CASE(MINT_LDLEN
) {
5777 MonoObject
* const o
= sp
[-1].data
.o
;
5779 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5783 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5784 MonoObject
* const o
= sp
[-1].data
.o
;
5786 gsize offset_length
= (gsize
)(gint16
)ip
[1];
5787 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5791 MINT_IN_CASE(MINT_GETCHR
) {
5793 s
= (MonoString
*)sp
[-2].data
.p
;
5795 int const i32
= sp
[-1].data
.i
;
5796 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5797 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5799 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5803 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5804 guint8
* const span
= (guint8
*) sp
[-2].data
.p
;
5805 const int index
= sp
[-1].data
.i
;
5810 const gsize offset_length
= (gsize
)(gint16
)ip
[2];
5812 const gint32 length
= *(gint32
*) (span
+ offset_length
);
5813 if (index
< 0 || index
>= length
)
5814 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5816 const gsize element_size
= (gsize
)(gint16
)ip
[1];
5817 const gsize offset_pointer
= (gsize
)(gint16
)ip
[3];
5819 const gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5820 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5825 MINT_IN_CASE(MINT_STRLEN
) {
5827 MonoObject
* const o
= sp
[-1].data
.o
;
5829 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5832 MINT_IN_CASE(MINT_ARRAY_RANK
) {
5833 MonoObject
* const o
= sp
[-1].data
.o
;
5835 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (o
));
5839 MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE
) {
5840 MonoObject
* const o
= sp
[-1].data
.o
;
5842 sp
[-1].data
.i
= mono_array_element_size (mono_object_class (o
));
5846 MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE
) {
5847 MonoObject
* const o
= sp
[-1].data
.o
;
5849 sp
[-1].data
.i
= m_class_is_primitive (m_class_get_element_class (mono_object_class (o
)));
5853 MINT_IN_CASE(MINT_LDELEMA1
) {
5854 /* No bounds, one direction */
5855 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
5857 gint32
const index
= sp
[-1].data
.i
;
5858 if (index
>= ao
->max_length
)
5859 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5860 gint32
const size
= READ32 (ip
+ 1);
5861 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
5867 MINT_IN_CASE(MINT_LDELEMA
) {
5868 guint16 rank
= ip
[1];
5869 gint32
const esize
= READ32 (ip
+ 2);
5873 MonoArray
* const ao
= (MonoArray
*) sp
[-1].data
.o
;
5876 g_assert (ao
->bounds
);
5878 for (int i
= 0; i
< rank
; i
++) {
5879 guint32 idx
= sp
[i
].data
.i
;
5880 guint32 lower
= ao
->bounds
[i
].lower_bound
;
5881 guint32 len
= ao
->bounds
[i
].length
;
5882 if (idx
< lower
|| (idx
- lower
) >= len
)
5883 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5884 pos
= (pos
* len
) + idx
- lower
;
5887 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
5890 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5891 guint16 rank
= ip
[1];
5895 MonoObject
* const o
= sp
[-1].data
.o
;
5898 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[-3 + 2]];
5899 const gboolean needs_typecheck
= ip
[-3] == MINT_LDELEMA_TC
;
5900 MonoException
*ex
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, sp
, needs_typecheck
);
5906 #define LDELEM(datamem,elemtype) do { \
5908 MonoArray *o = (MonoArray*)sp [-1].data.p; \
5910 gint32 aindex = sp [0].data.i; \
5911 if (aindex >= mono_array_length_internal (o)) \
5912 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5913 sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \
5916 MINT_IN_CASE(MINT_LDELEM_I1
) LDELEM(i
, gint8
); MINT_IN_BREAK
;
5917 MINT_IN_CASE(MINT_LDELEM_U1
) LDELEM(i
, guint8
); MINT_IN_BREAK
;
5918 MINT_IN_CASE(MINT_LDELEM_I2
) LDELEM(i
, gint16
); MINT_IN_BREAK
;
5919 MINT_IN_CASE(MINT_LDELEM_U2
) LDELEM(i
, guint16
); MINT_IN_BREAK
;
5920 MINT_IN_CASE(MINT_LDELEM_I4
) LDELEM(i
, gint32
); MINT_IN_BREAK
;
5921 MINT_IN_CASE(MINT_LDELEM_U4
) LDELEM(i
, guint32
); MINT_IN_BREAK
;
5922 MINT_IN_CASE(MINT_LDELEM_I8
) LDELEM(l
, guint64
); MINT_IN_BREAK
;
5923 MINT_IN_CASE(MINT_LDELEM_I
) LDELEM(nati
, mono_i
); MINT_IN_BREAK
;
5924 MINT_IN_CASE(MINT_LDELEM_R4
) LDELEM(f_r4
, float); MINT_IN_BREAK
;
5925 MINT_IN_CASE(MINT_LDELEM_R8
) LDELEM(f
, double); MINT_IN_BREAK
;
5926 MINT_IN_CASE(MINT_LDELEM_REF
) LDELEM(p
, gpointer
); MINT_IN_BREAK
;
5927 MINT_IN_CASE(MINT_LDELEM_VT
) {
5929 MonoArray
*o
= (MonoArray
*)sp
[-1].data
.p
;
5931 mono_u aindex
= sp
[0].data
.i
;
5932 if (aindex
>= mono_array_length_internal (o
))
5933 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5935 int i32
= READ32 (ip
+ 1);
5936 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5937 sp
[-1].data
.vt
= vt_sp
;
5938 // Copying to vtstack. No wbarrier needed
5939 memcpy (sp
[-1].data
.vt
, src_addr
, i32
);
5940 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5945 #define STELEM_PROLOG(o, aindex) do { \
5947 o = (MonoArray*)sp [0].data.p; \
5949 aindex = sp [1].data.i; \
5950 if (aindex >= mono_array_length_internal (o)) \
5951 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5954 #define STELEM(datamem,elemtype) do { \
5957 STELEM_PROLOG(o, aindex); \
5958 mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \
5961 MINT_IN_CASE(MINT_STELEM_I1
) STELEM(i
, gint8
); MINT_IN_BREAK
;
5962 MINT_IN_CASE(MINT_STELEM_U1
) STELEM(i
, guint8
); MINT_IN_BREAK
;
5963 MINT_IN_CASE(MINT_STELEM_I2
) STELEM(i
, gint16
); MINT_IN_BREAK
;
5964 MINT_IN_CASE(MINT_STELEM_U2
) STELEM(i
, guint16
); MINT_IN_BREAK
;
5965 MINT_IN_CASE(MINT_STELEM_I4
) STELEM(i
, gint32
); MINT_IN_BREAK
;
5966 MINT_IN_CASE(MINT_STELEM_I8
) STELEM(l
, gint64
); MINT_IN_BREAK
;
5967 MINT_IN_CASE(MINT_STELEM_I
) STELEM(nati
, mono_i
); MINT_IN_BREAK
;
5968 MINT_IN_CASE(MINT_STELEM_R4
) STELEM(f_r4
, float); MINT_IN_BREAK
;
5969 MINT_IN_CASE(MINT_STELEM_R8
) STELEM(f
, double); MINT_IN_BREAK
;
5970 MINT_IN_CASE(MINT_STELEM_REF
) {
5973 STELEM_PROLOG(o
, aindex
);
5975 if (sp
[2].data
.o
) {
5976 gboolean isinst
= mono_interp_isinst (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)));
5978 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5980 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5985 MINT_IN_CASE(MINT_STELEM_VT
) {
5988 STELEM_PROLOG(o
, aindex
);
5990 MonoClass
*klass_vt
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5991 int const i32
= READ32 (ip
+ 2);
5992 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5994 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5995 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5999 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
6000 if (sp
[-1].data
.i
< 0)
6001 goto overflow_label
;
6004 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
6005 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
6006 goto overflow_label
;
6007 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
6010 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
6011 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
6012 goto overflow_label
;
6013 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
6016 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
6017 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
|| isnan (sp
[-1].data
.f_r4
))
6018 goto overflow_label
;
6019 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
6022 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
6023 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
|| isnan (sp
[-1].data
.f
))
6024 goto overflow_label
;
6025 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
6028 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
6029 if (sp
[-1].data
.i
< 0)
6030 goto overflow_label
;
6033 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
6034 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
6035 goto overflow_label
;
6036 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
6039 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
6040 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
|| isnan (sp
[-1].data
.f_r4
))
6041 goto overflow_label
;
6042 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
6045 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
6046 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
|| isnan (sp
[-1].data
.f
))
6047 goto overflow_label
;
6048 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
6051 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
6052 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
6053 goto overflow_label
;
6056 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
6057 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
6058 goto overflow_label
;
6061 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
6062 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
6063 goto overflow_label
;
6064 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
6067 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
6068 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
6069 goto overflow_label
;
6070 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
6073 MINT_IN_CASE(MINT_CONV_OVF_I2_R4
)
6074 if (sp
[-1].data
.f_r4
< G_MININT16
|| sp
[-1].data
.f_r4
> G_MAXINT16
|| isnan (sp
[-1].data
.f_r4
))
6075 goto overflow_label
;
6076 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f_r4
;
6079 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
6080 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
|| isnan (sp
[-1].data
.f
))
6081 goto overflow_label
;
6082 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
6085 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4
)
6086 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT16
|| isnan (sp
[-1].data
.f_r4
))
6087 goto overflow_label
;
6088 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f_r4
;
6091 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
6092 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
|| isnan (sp
[-1].data
.f
))
6093 goto overflow_label
;
6094 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
6097 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
6098 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
6099 goto overflow_label
;
6102 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
6103 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
6104 goto overflow_label
;
6105 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
6108 MINT_IN_CASE(MINT_CONV_OVF_U2_R4
)
6109 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT16
|| isnan (sp
[-1].data
.f_r4
))
6110 goto overflow_label
;
6111 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f_r4
;
6114 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
6115 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
|| isnan (sp
[-1].data
.f
))
6116 goto overflow_label
;
6117 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
6120 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
6121 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
6122 goto overflow_label
;
6125 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
6126 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
6127 goto overflow_label
;
6130 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
6131 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
6132 goto overflow_label
;
6133 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
6136 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
6137 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
6138 goto overflow_label
;
6139 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
6142 MINT_IN_CASE(MINT_CONV_OVF_I1_R4
)
6143 if (sp
[-1].data
.f_r4
< G_MININT8
|| sp
[-1].data
.f_r4
> G_MAXINT8
|| isnan (sp
[-1].data
.f_r4
))
6144 goto overflow_label
;
6145 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f_r4
;
6148 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
6149 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
|| isnan (sp
[-1].data
.f
))
6150 goto overflow_label
;
6151 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
6154 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4
)
6155 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT8
|| isnan (sp
[-1].data
.f_r4
))
6156 goto overflow_label
;
6157 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f_r4
;
6160 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
6161 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
|| isnan (sp
[-1].data
.f
))
6162 goto overflow_label
;
6163 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
6166 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
6167 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
6168 goto overflow_label
;
6171 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
6172 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
6173 goto overflow_label
;
6174 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
6177 MINT_IN_CASE(MINT_CONV_OVF_U1_R4
)
6178 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT8
|| isnan (sp
[-1].data
.f_r4
))
6179 goto overflow_label
;
6180 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f_r4
;
6183 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
6184 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
|| isnan (sp
[-1].data
.f
))
6185 goto overflow_label
;
6186 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
6189 MINT_IN_CASE(MINT_CKFINITE
)
6190 if (!mono_isfinite (sp
[-1].data
.f
))
6191 THROW_EX (mono_get_exception_arithmetic (), ip
);
6194 MINT_IN_CASE(MINT_MKREFANY
) {
6195 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6197 /* The value address is on the stack */
6198 gpointer addr
= sp
[-1].data
.p
;
6199 /* Push the typedref value on the stack */
6200 sp
[-1].data
.p
= vt_sp
;
6201 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6203 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6205 tref
->type
= m_class_get_byval_arg (c
);
6211 MINT_IN_CASE(MINT_REFANYTYPE
) {
6212 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6213 MonoType
*type
= tref
->type
;
6215 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6216 sp
[-1].data
.p
= vt_sp
;
6218 *(gpointer
*)sp
[-1].data
.p
= type
;
6222 MINT_IN_CASE(MINT_REFANYVAL
) {
6223 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6224 gpointer addr
= tref
->value
;
6226 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6227 if (c
!= tref
->klass
)
6228 goto invalid_cast_label
;
6230 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6232 sp
[-1].data
.p
= addr
;
6236 MINT_IN_CASE(MINT_LDTOKEN
)
6239 * (gpointer
*)sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6243 MINT_IN_CASE(MINT_ADD_OVF_I4
)
6244 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6245 goto overflow_label
;
6248 MINT_IN_CASE(MINT_ADD_OVF_I8
)
6249 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6250 goto overflow_label
;
6253 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
6254 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6255 goto overflow_label
;
6256 BINOP_CAST(i
, +, guint32
);
6258 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
6259 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6260 goto overflow_label
;
6261 BINOP_CAST(l
, +, guint64
);
6263 MINT_IN_CASE(MINT_MUL_OVF_I4
)
6264 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6265 goto overflow_label
;
6268 MINT_IN_CASE(MINT_MUL_OVF_I8
)
6269 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6270 goto overflow_label
;
6273 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
6274 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6275 goto overflow_label
;
6276 BINOP_CAST(i
, *, guint32
);
6278 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
6279 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6280 goto overflow_label
;
6281 BINOP_CAST(l
, *, guint64
);
6283 MINT_IN_CASE(MINT_SUB_OVF_I4
)
6284 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6285 goto overflow_label
;
6288 MINT_IN_CASE(MINT_SUB_OVF_I8
)
6289 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6290 goto overflow_label
;
6293 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
6294 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6295 goto overflow_label
;
6296 BINOP_CAST(i
, -, guint32
);
6298 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
6299 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6300 goto overflow_label
;
6301 BINOP_CAST(l
, -, guint64
);
6303 MINT_IN_CASE(MINT_START_ABORT_PROT
)
6304 mono_threads_begin_abort_protected_block ();
6307 MINT_IN_CASE(MINT_ENDFINALLY
) {
6308 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
6311 // After mono_threads_end_abort_protected_block to conserve stack.
6312 const int clause_index
= *ip
;
6314 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
6317 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
6318 g_assert (sp
>= frame
->stack
);
6323 ip
= (const guint16
*)finally_ips
->data
;
6324 finally_ips
= g_slist_remove (finally_ips
, ip
);
6325 /* Throw abort after the last finally block to avoid confusing EH */
6326 if (pending_abort
&& !finally_ips
)
6327 EXCEPTION_CHECKPOINT
;
6328 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6329 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6336 MINT_IN_CASE(MINT_LEAVE
)
6337 MINT_IN_CASE(MINT_LEAVE_S
)
6338 MINT_IN_CASE(MINT_LEAVE_CHECK
)
6339 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
6341 // Leave is split into pieces in order to consume less stack,
6342 // but not have to change how exception handling macros access labels and locals.
6344 g_assert (sp
>= frame
->stack
);
6345 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
6350 gboolean
const check
= opcode
== MINT_LEAVE_CHECK
|| opcode
== MINT_LEAVE_S_CHECK
;
6352 if (check
&& frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
6353 child_frame
= alloc_frame (context
, &dummy
, frame
, NULL
, NULL
, NULL
);
6354 MonoException
*abort_exc
= mono_interp_leave (child_frame
);
6356 THROW_EX (abort_exc
, frame
->ip
);
6359 opcode
= *ip
; // Refetch to avoid register/stack pressure.
6360 gboolean
const short_offset
= opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
;
6361 ip
+= short_offset
? (short)*(ip
+ 1) : (gint32
)READ32 (ip
+ 1);
6362 const guint16
*endfinally_ip
= ip
;
6363 GSList
*old_list
= finally_ips
;
6364 MonoMethod
*method
= frame
->imethod
->method
;
6367 g_print ("* Handle finally IL_%04x\n", endfinally_ip
- frame
->imethod
->code
);
6369 // FIXME Null check for frame->imethod follows deref.
6370 if (frame
->imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
6371 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))
6373 guint32
const ip_offset
= frame
->ip
- frame
->imethod
->code
;
6375 finally_ips
= g_slist_prepend (finally_ips
, (void *)endfinally_ip
);
6377 for (int i
= frame
->imethod
->num_clauses
- 1; i
>= 0; i
--) {
6378 MonoExceptionClause
* const clause
= &frame
->imethod
->clauses
[i
];
6379 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- frame
->imethod
->code
))) {
6380 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6381 ip
= frame
->imethod
->code
+ clause
->handler_offset
;
6382 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
6385 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, context
->has_resume_state
? "yes": "no");
6391 if (old_list
!= finally_ips
&& finally_ips
) {
6392 ip
= (const guint16
*)finally_ips
->data
;
6393 finally_ips
= g_slist_remove (finally_ips
, ip
);
6394 // we set vt_sp later here so we relieve stack pressure
6395 vt_sp
= (unsigned char*)sp
+ frame
->imethod
->stack_size
;
6396 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6397 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6404 MINT_IN_CASE(MINT_ICALL_V_V
)
6405 MINT_IN_CASE(MINT_ICALL_V_P
)
6406 MINT_IN_CASE(MINT_ICALL_P_V
)
6407 MINT_IN_CASE(MINT_ICALL_P_P
)
6408 MINT_IN_CASE(MINT_ICALL_PP_V
)
6409 MINT_IN_CASE(MINT_ICALL_PP_P
)
6410 MINT_IN_CASE(MINT_ICALL_PPP_V
)
6411 MINT_IN_CASE(MINT_ICALL_PPP_P
)
6412 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
6413 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
6414 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
6415 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
6416 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
6417 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
6419 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, frame
->imethod
->data_items
[ip
[1]], FALSE
);
6420 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
6421 CHECK_RESUME_STATE (context
);
6424 MINT_IN_CASE(MINT_MONO_LDPTR
)
6425 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6429 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
6430 sp
->data
.o
= mono_interp_new (frame
->imethod
->domain
, (MonoClass
*)frame
->imethod
->data_items
[ip
[1]]); // FIXME: do not swallow the error
6434 MINT_IN_CASE(MINT_MONO_RETOBJ
)
6437 stackval_from_data (mono_method_signature_internal (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
6438 mono_method_signature_internal (frame
->imethod
->method
)->pinvoke
);
6439 if (sp
> frame
->stack
)
6440 g_warning_d ("retobj: more values on stack: %d", sp
- frame
->stack
);
6442 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
6443 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
6447 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
6449 mono_memory_barrier ();
6452 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
6453 sp
->data
.p
= mono_domain_get ();
6457 MINT_IN_CASE(MINT_MONO_GET_SP
)
6458 sp
->data
.p
= &frame
;
6462 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
6463 if (G_UNLIKELY (ss_enabled
)) {
6464 typedef void (*T
) (void);
6468 void *tramp
= mini_get_single_step_trampoline ();
6469 mono_memory_barrier ();
6470 ss_tramp
= (T
)tramp
;
6474 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6475 * the address of that instruction is stored as the seq point address.
6480 * Use the same trampoline as the JIT. This ensures that
6481 * the debugger has the context for the last interpreter
6484 do_debugger_tramp (ss_tramp
, frame
);
6486 CHECK_RESUME_STATE (context
);
6490 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
6491 /* Just a placeholder for a breakpoint */
6494 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
6495 typedef void (*T
) (void);
6498 void *tramp
= mini_get_breakpoint_trampoline ();
6499 mono_memory_barrier ();
6500 bp_tramp
= (T
)tramp
;
6505 /* Use the same trampoline as the JIT */
6506 do_debugger_tramp (bp_tramp
, frame
);
6508 CHECK_RESUME_STATE (context
);
6514 #define RELOP(datamem, op) \
6516 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6519 #define RELOP_FP(datamem, op, noorder) \
6521 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6522 sp [-1].data.i = noorder; \
6524 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6527 MINT_IN_CASE(MINT_CEQ_I4
)
6530 MINT_IN_CASE(MINT_CEQ0_I4
)
6531 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
6534 MINT_IN_CASE(MINT_CEQ_I8
)
6537 MINT_IN_CASE(MINT_CEQ_R4
)
6538 RELOP_FP(f_r4
, ==, 0);
6540 MINT_IN_CASE(MINT_CEQ_R8
)
6543 MINT_IN_CASE(MINT_CNE_I4
)
6546 MINT_IN_CASE(MINT_CNE_I8
)
6549 MINT_IN_CASE(MINT_CNE_R4
)
6550 RELOP_FP(f_r4
, !=, 1);
6552 MINT_IN_CASE(MINT_CNE_R8
)
6555 MINT_IN_CASE(MINT_CGT_I4
)
6558 MINT_IN_CASE(MINT_CGT_I8
)
6561 MINT_IN_CASE(MINT_CGT_R4
)
6562 RELOP_FP(f_r4
, >, 0);
6564 MINT_IN_CASE(MINT_CGT_R8
)
6567 MINT_IN_CASE(MINT_CGE_I4
)
6570 MINT_IN_CASE(MINT_CGE_I8
)
6573 MINT_IN_CASE(MINT_CGE_R4
)
6574 RELOP_FP(f_r4
, >=, 0);
6576 MINT_IN_CASE(MINT_CGE_R8
)
6580 #define RELOP_CAST(datamem, op, type) \
6582 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6585 MINT_IN_CASE(MINT_CGE_UN_I4
)
6586 RELOP_CAST(l
, >=, guint32
);
6588 MINT_IN_CASE(MINT_CGE_UN_I8
)
6589 RELOP_CAST(l
, >=, guint64
);
6592 MINT_IN_CASE(MINT_CGT_UN_I4
)
6593 RELOP_CAST(i
, >, guint32
);
6595 MINT_IN_CASE(MINT_CGT_UN_I8
)
6596 RELOP_CAST(l
, >, guint64
);
6598 MINT_IN_CASE(MINT_CGT_UN_R4
)
6599 RELOP_FP(f_r4
, >, 1);
6601 MINT_IN_CASE(MINT_CGT_UN_R8
)
6604 MINT_IN_CASE(MINT_CLT_I4
)
6607 MINT_IN_CASE(MINT_CLT_I8
)
6610 MINT_IN_CASE(MINT_CLT_R4
)
6611 RELOP_FP(f_r4
, <, 0);
6613 MINT_IN_CASE(MINT_CLT_R8
)
6616 MINT_IN_CASE(MINT_CLT_UN_I4
)
6617 RELOP_CAST(i
, <, guint32
);
6619 MINT_IN_CASE(MINT_CLT_UN_I8
)
6620 RELOP_CAST(l
, <, guint64
);
6622 MINT_IN_CASE(MINT_CLT_UN_R4
)
6623 RELOP_FP(f_r4
, <, 1);
6625 MINT_IN_CASE(MINT_CLT_UN_R8
)
6628 MINT_IN_CASE(MINT_CLE_I4
)
6631 MINT_IN_CASE(MINT_CLE_I8
)
6634 MINT_IN_CASE(MINT_CLE_UN_I4
)
6635 RELOP_CAST(l
, <=, guint32
);
6637 MINT_IN_CASE(MINT_CLE_UN_I8
)
6638 RELOP_CAST(l
, <=, guint64
);
6640 MINT_IN_CASE(MINT_CLE_R4
)
6641 RELOP_FP(f_r4
, <=, 0);
6643 MINT_IN_CASE(MINT_CLE_R8
)
6651 MINT_IN_CASE(MINT_LDFTN
) {
6652 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6657 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6658 InterpMethod
*m
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
6660 NULL_CHECK (sp
->data
.p
);
6662 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6667 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6668 error_init_reuse (error
);
6669 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6670 mono_error_assert_ok (error
);
6676 #define LDARG(datamem, argtype) \
6677 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6681 #define LDARGn(datamem, argtype, n) \
6682 sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \
6686 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
6687 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
6688 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
6689 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
6690 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
6691 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
6692 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
6693 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
6694 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6695 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6697 MINT_IN_CASE(MINT_LDARG_P0
) LDARGn(p
, gpointer
, 0); MINT_IN_BREAK
;
6699 MINT_IN_CASE(MINT_LDARG_VT
) {
6701 int const i32
= READ32 (ip
+ 2);
6702 memcpy(sp
->data
.p
, frame
->stack_args
[ip
[1]].data
.p
, i32
);
6703 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6709 #define STARG(datamem, argtype) \
6711 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6714 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
6715 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
6716 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
6717 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
6718 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
6719 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
6720 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6721 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6722 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6723 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6725 MINT_IN_CASE(MINT_STARG_VT
) {
6726 int const i32
= READ32 (ip
+ 2);
6728 memcpy(frame
->stack_args
[ip
[1]].data
.p
, sp
->data
.p
, i32
);
6729 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6734 MINT_IN_CASE(MINT_PROF_ENTER
) {
6735 guint16 flag
= ip
[1];
6738 if ((flag
& TRACING_FLAG
) || ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
) &&
6739 (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
))) {
6740 MonoProfilerCallContext
*prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6741 prof_ctx
->interp_frame
= frame
;
6742 prof_ctx
->method
= frame
->imethod
->method
;
6743 if (flag
& TRACING_FLAG
)
6744 mono_trace_enter_method (frame
->imethod
->method
, frame
->imethod
->jinfo
, prof_ctx
);
6745 if (flag
& PROFILING_FLAG
)
6746 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
6748 } else if ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
)) {
6749 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, NULL
));
6754 MINT_IN_CASE(MINT_PROF_EXIT
)
6755 MINT_IN_CASE(MINT_PROF_EXIT_VOID
) {
6756 guint16 flag
= ip
[1];
6758 int const i32
= READ32 (ip
+ 2);
6762 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6765 *frame
->retval
= *sp
;
6768 if ((flag
& TRACING_FLAG
) || ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_leave
) &&
6769 (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
))) {
6770 MonoProfilerCallContext
*prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6771 prof_ctx
->interp_frame
= frame
;
6772 prof_ctx
->method
= frame
->imethod
->method
;
6775 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6777 prof_ctx
->return_value
= frame
->retval
;
6779 if (flag
& TRACING_FLAG
)
6780 mono_trace_leave_method (frame
->imethod
->method
, frame
->imethod
->jinfo
, prof_ctx
);
6781 if (flag
& PROFILING_FLAG
)
6782 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
6784 } else if ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
)) {
6785 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, NULL
));
6792 MINT_IN_CASE(MINT_LDARGA
)
6793 sp
->data
.p
= &frame
->stack_args
[ip
[1]];
6798 MINT_IN_CASE(MINT_LDARGA_VT
)
6799 sp
->data
.p
= frame
->stack_args
[ip
[1]].data
.p
;
6804 #define LDLOC(datamem, argtype) \
6805 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6809 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6810 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6811 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6812 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6813 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6814 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6815 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6816 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6817 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6818 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6820 MINT_IN_CASE(MINT_LDLOC_VT
) {
6822 int const i32
= READ32 (ip
+ 2);
6823 memcpy(sp
->data
.p
, locals
+ ip
[1], i32
);
6824 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6829 MINT_IN_CASE(MINT_LDLOCA_S
)
6830 sp
->data
.p
= locals
+ ip
[1];
6835 #define STLOC(datamem, argtype) \
6837 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6840 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6841 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6842 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6843 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6844 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6845 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6846 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6847 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6848 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6849 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6851 #define STLOC_NP(datamem, argtype) \
6852 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6855 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6856 MINT_IN_CASE(MINT_STLOC_NP_I8
) STLOC_NP(l
, gint64
); MINT_IN_BREAK
;
6857 MINT_IN_CASE(MINT_STLOC_NP_R4
) STLOC_NP(f_r4
, float); MINT_IN_BREAK
;
6858 MINT_IN_CASE(MINT_STLOC_NP_R8
) STLOC_NP(f
, double); MINT_IN_BREAK
;
6859 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6861 MINT_IN_CASE(MINT_STLOC_VT
) {
6862 int const i32
= READ32 (ip
+ 2);
6864 memcpy(locals
+ ip
[1], sp
->data
.p
, i32
);
6865 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6870 #define MOVLOC(argtype) \
6871 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6874 MINT_IN_CASE(MINT_MOVLOC_1
) MOVLOC(guint8
); MINT_IN_BREAK
;
6875 MINT_IN_CASE(MINT_MOVLOC_2
) MOVLOC(guint16
); MINT_IN_BREAK
;
6876 MINT_IN_CASE(MINT_MOVLOC_4
) MOVLOC(guint32
); MINT_IN_BREAK
;
6877 MINT_IN_CASE(MINT_MOVLOC_8
) MOVLOC(guint64
); MINT_IN_BREAK
;
6879 MINT_IN_CASE(MINT_MOVLOC_VT
) {
6880 int const i32
= READ32(ip
+ 3);
6881 memcpy (locals
+ ip
[2], locals
+ ip
[1], i32
);
6886 MINT_IN_CASE(MINT_LOCALLOC
) {
6887 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6890 int len
= sp
[-1].data
.i
;
6891 //sp [-1].data.p = alloca (len);
6892 sp
[-1].data
.p
= alloc_extra_stack_data (context
, ALIGN_TO (len
, 8));
6894 if (frame
->imethod
->init_locals
)
6895 memset (sp
[-1].data
.p
, 0, len
);
6899 MINT_IN_CASE(MINT_ENDFILTER
)
6900 /* top of stack is result of filter */
6901 frame
->retval
->data
.i
= sp
[-1].data
.i
;
6903 MINT_IN_CASE(MINT_INITOBJ
)
6905 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6908 MINT_IN_CASE(MINT_CPBLK
)
6910 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6911 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6913 /* FIXME: value and size may be int64... */
6914 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6917 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6919 /* FIXME: implement */
6921 token
= READ32 (ip
);
6926 MINT_IN_CASE(MINT_INITBLK
)
6928 NULL_CHECK (sp
[0].data
.p
);
6930 /* FIXME: value and size may be int64... */
6931 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6934 MINT_IN_CASE(MINT_NO_
)
6935 /* FIXME: implement */
6939 MINT_IN_CASE(MINT_RETHROW
) {
6940 int exvar_offset
= ip
[1];
6941 THROW_EX_GENERAL (*(MonoException
**)(frame_locals (frame
) + exvar_offset
), ip
, TRUE
);
6944 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6946 * need to clarify what this should actually do:
6948 * Takes an exception from the stack and rethrows it.
6949 * This is useful for wrappers that don't want to have to
6950 * use CEE_THROW and lose the exception stacktrace.
6955 sp
->data
.p
= mono_get_exception_null_reference ();
6957 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6960 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6964 del
= (MonoDelegate
*)sp
->data
.p
;
6965 if (!del
->interp_method
) {
6966 /* Not created from interpreted code */
6967 error_init_reuse (error
);
6968 g_assert (del
->method
);
6969 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6970 mono_error_assert_ok (error
);
6972 g_assert (del
->interp_method
);
6973 sp
->data
.p
= del
->interp_method
;
6978 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6981 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6982 if (!del
->interp_invoke_impl
) {
6984 * First time we are called. Set up the invoke wrapper. We might be able to do this
6985 * in ctor but we would need to handle AllocDelegateLike_internal separately
6987 error_init_reuse (error
);
6988 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6989 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6990 mono_error_assert_ok (error
);
6993 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6998 #define MATH_UNOP(mathfunc) \
6999 sp [-1].data.f = mathfunc (sp [-1].data.f); \
7002 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
7003 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
7004 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
7005 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
7006 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
7007 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
7008 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
7009 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
7010 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
7011 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
7012 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
7013 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
7014 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
7015 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
7016 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
7018 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
7019 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
7020 mono_interp_enum_hasflag (sp
, klass
);
7025 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
7026 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
7030 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
7031 NULL_CHECK (sp
[-1].data
.p
);
7032 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
7037 #if !USE_COMPUTED_GOTO
7039 g_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname (*ip
), ip
- frame
->imethod
->code
);
7044 g_assert_not_reached ();
7047 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
7049 THROW_EX (mono_get_exception_null_reference (), ip
);
7051 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
7053 THROW_EX (mono_get_exception_overflow (), ip
);
7055 THROW_EX (mono_error_convert_to_exception (error
), ip
);
7057 THROW_EX (mono_get_exception_invalid_cast (), ip
);
7059 g_assert (context
->has_resume_state
);
7060 g_assert (frame
->imethod
);
7062 if (frame
== context
->handler_frame
&& (!clause_args
|| context
->handler_ip
< clause_args
->end_at_ip
)) {
7063 /* Set the current execution state to the resume state in context */
7065 ip
= context
->handler_ip
;
7066 /* spec says stack should be empty at endfinally so it should be at the start too */
7068 vt_sp
= (guchar
*)sp
+ frame
->imethod
->stack_size
;
7069 g_assert (context
->exc_gchandle
);
7070 sp
->data
.p
= mono_gchandle_get_target_internal (context
->exc_gchandle
);
7073 finally_ips
= clear_resume_state (context
, finally_ips
);
7074 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
7075 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
7080 error_init_reuse (error
);
7082 g_assert (frame
->imethod
);
7084 if (clause_args
&& clause_args
->base_frame
) {
7085 // We finished executing a filter. The execution stack of the base frame
7086 // should remain unmodified, but we need to update the local space.
7087 char *locals_base
= (char*)clause_args
->base_frame
->stack
+ frame
->imethod
->stack_size
+ frame
->imethod
->vt_stack_size
;
7089 memcpy (locals_base
, locals
, frame
->imethod
->locals_size
);
7092 if (!clause_args
&& frame
->parent
&& frame
->parent
->state
.ip
) {
7093 /* Return to the main loop after a non-recursive interpreter call */
7094 //printf ("R: %s -> %s %p\n", mono_method_get_full_name (frame->imethod->method), mono_method_get_full_name (frame->parent->imethod->method), frame->parent->state.ip);
7095 stackval
*retval
= frame
->retval
;
7097 InterpFrame
*child_frame
= frame
;
7099 frame
= frame
->parent
;
7100 LOAD_INTERP_STATE (frame
);
7102 pop_frame (context
, child_frame
);
7104 CHECK_RESUME_STATE (context
);
7114 pop_frame (context
, frame
);
7120 interp_parse_options (const char *options
)
7127 args
= g_strsplit (options
, ",", -1);
7128 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
7131 if (strncmp (arg
, "jit=", 4) == 0)
7132 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
7133 else if (strncmp (arg
, "interp-only=", strlen ("interp-only=")) == 0)
7134 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
7135 else if (strncmp (arg
, "-inline", 7) == 0)
7136 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
7137 else if (strncmp (arg
, "-cprop", 6) == 0)
7138 mono_interp_opt
&= ~INTERP_OPT_CPROP
;
7139 else if (strncmp (arg
, "-super", 6) == 0)
7140 mono_interp_opt
&= ~INTERP_OPT_SUPER_INSTRUCTIONS
;
7141 else if (strncmp (arg
, "-all", 4) == 0)
7142 mono_interp_opt
= INTERP_OPT_NONE
;
7147 * interp_set_resume_state:
7149 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
7152 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoObject
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
7154 ThreadContext
*context
;
7157 context
= (ThreadContext
*)jit_tls
->interp_context
;
7160 context
->has_resume_state
= TRUE
;
7161 context
->handler_frame
= (InterpFrame
*)interp_frame
;
7162 context
->handler_ei
= ei
;
7163 if (context
->exc_gchandle
)
7164 mono_gchandle_free_internal (context
->exc_gchandle
);
7165 context
->exc_gchandle
= mono_gchandle_new_internal ((MonoObject
*)ex
, FALSE
);
7168 *(MonoObject
**)(frame_locals (context
->handler_frame
) + ei
->exvar_offset
) = ex
;
7169 context
->handler_ip
= (const guint16
*)handler_ip
;
7173 interp_get_resume_state (const MonoJitTlsData
*jit_tls
, gboolean
*has_resume_state
, MonoInterpFrameHandle
*interp_frame
, gpointer
*handler_ip
)
7176 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
7178 *has_resume_state
= context
? context
->has_resume_state
: FALSE
;
7179 if (!*has_resume_state
)
7182 *interp_frame
= context
->handler_frame
;
7183 *handler_ip
= (gpointer
)context
->handler_ip
;
7187 * interp_run_finally:
7189 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
7190 * frame->interp_frame.
7191 * Return TRUE if the finally clause threw an exception.
7194 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
7196 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
7197 ThreadContext
*context
= get_context ();
7198 const unsigned short *old_ip
= iframe
->ip
;
7199 FrameClauseArgs clause_args
;
7200 const guint16
*saved_ip
;
7202 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
7203 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
7204 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
7205 clause_args
.exit_clause
= clause_index
;
7207 saved_ip
= iframe
->state
.ip
;
7208 iframe
->state
.ip
= NULL
;
7211 interp_exec_method_full (iframe
, context
, &clause_args
, error
);
7212 iframe
->state
.ip
= saved_ip
;
7213 iframe
->state
.clause_args
= NULL
;
7214 if (context
->has_resume_state
) {
7217 iframe
->ip
= old_ip
;
7223 * interp_run_filter:
7225 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
7226 * frame->interp_frame.
7229 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
7231 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
7232 ThreadContext
*context
= get_context ();
7233 InterpFrame
*child_frame
;
7235 FrameClauseArgs clause_args
;
7238 * Have to run the clause in a new frame which is a copy of IFRAME, since
7239 * during debugging, there are two copies of the frame on the stack.
7241 child_frame
= alloc_frame (context
, &retval
, iframe
, iframe
->imethod
, iframe
->stack_args
, &retval
);
7243 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
7244 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
7245 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
7246 clause_args
.filter_exception
= ex
;
7247 clause_args
.base_frame
= iframe
;
7250 interp_exec_method_full (child_frame
, context
, &clause_args
, error
);
7251 /* ENDFILTER stores the result into child_frame->retval */
7252 return retval
.data
.i
? TRUE
: FALSE
;
7256 InterpFrame
*current
;
7260 * interp_frame_iter_init:
7262 * Initialize an iterator for iterating through interpreted frames.
7265 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
7267 StackIter
*stack_iter
= (StackIter
*)iter
;
7269 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
7273 * interp_frame_iter_next:
7275 * Fill out FRAME with date for the next interpreter frame.
7278 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
7280 StackIter
*stack_iter
= (StackIter
*)iter
;
7281 InterpFrame
*iframe
= stack_iter
->current
;
7283 memset (frame
, 0, sizeof (StackFrameInfo
));
7284 /* pinvoke frames doesn't have imethod set */
7285 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
7286 iframe
= iframe
->parent
;
7290 MonoMethod
*method
= iframe
->imethod
->method
;
7291 frame
->domain
= iframe
->imethod
->domain
;
7292 frame
->interp_frame
= iframe
;
7293 frame
->method
= method
;
7294 frame
->actual_method
= method
;
7295 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
7296 frame
->native_offset
= -1;
7297 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
7299 frame
->type
= FRAME_TYPE_INTERP
;
7300 /* This is the offset in the interpreter IR */
7301 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
7302 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
7303 frame
->managed
= TRUE
;
7305 frame
->ji
= iframe
->imethod
->jinfo
;
7306 frame
->frame_addr
= iframe
->native_stack_addr
;
7308 stack_iter
->current
= iframe
->parent
;
7314 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
7316 InterpMethod
* imethod
;
7318 imethod
= lookup_imethod (domain
, method
);
7320 return imethod
->jinfo
;
7326 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
7328 guint16
*code
= (guint16
*)ip
;
7329 g_assert (*code
== MINT_SDB_SEQ_POINT
);
7330 *code
= MINT_SDB_BREAKPOINT
;
7334 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
7336 guint16
*code
= (guint16
*)ip
;
7337 g_assert (*code
== MINT_SDB_BREAKPOINT
);
7338 *code
= MINT_SDB_SEQ_POINT
;
7342 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
7344 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7346 g_assert (iframe
->imethod
);
7347 return iframe
->imethod
->jinfo
;
7351 interp_frame_get_ip (MonoInterpFrameHandle frame
)
7353 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7355 g_assert (iframe
->imethod
);
7356 return (gpointer
)iframe
->ip
;
7360 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
7362 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7363 MonoMethodSignature
*sig
;
7365 g_assert (iframe
->imethod
);
7367 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
7368 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
7372 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
7374 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7376 g_assert (iframe
->imethod
);
7378 return frame_locals (iframe
) + iframe
->imethod
->local_offsets
[pos
];
7382 interp_frame_get_this (MonoInterpFrameHandle frame
)
7384 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7386 g_assert (iframe
->imethod
);
7387 g_assert (iframe
->imethod
->hasthis
);
7388 return &iframe
->stack_args
[0].data
.p
;
7391 static MonoInterpFrameHandle
7392 interp_frame_get_parent (MonoInterpFrameHandle frame
)
7394 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7396 return iframe
->parent
;
7400 interp_frame_get_res (MonoInterpFrameHandle frame
)
7402 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7403 MonoMethodSignature
*sig
;
7405 g_assert (iframe
->imethod
);
7406 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
7407 if (sig
->ret
->type
== MONO_TYPE_VOID
)
7410 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
7414 interp_frame_get_native_stack_addr (MonoInterpFrameHandle frame
)
7416 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7418 return iframe
->native_stack_addr
;
7422 interp_start_single_stepping (void)
7428 interp_stop_single_stepping (void)
7434 * interp_mark_stack:
7436 * Mark the interpreter stack frames for a thread.
7440 interp_mark_stack (gpointer thread_data
, GcScanFunc func
, gpointer gc_data
, gboolean precise
)
7442 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread_data
;
7444 if (!mono_use_interpreter
)
7450 * We explicitly mark the frames instead of registering the stack fragments as GC roots, so
7451 * we have to process less data and avoid false pinning from data which is above 'pos'.
7453 * The stack frame handling code uses compiler write barriers only, but the calling code
7454 * in sgen-mono.c already did a mono_memory_barrier_process_wide () so we can
7455 * process these data structures normally.
7457 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)info
->tls
[TLS_KEY_JIT_TLS
];
7461 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
7462 if (!context
|| !context
->data_stack
.inited
)
7465 StackFragment
*frag
;
7466 for (frag
= context
->data_stack
.first
; frag
; frag
= frag
->next
) {
7467 // FIXME: Scan the whole area with 1 call
7468 for (gpointer
*p
= (gpointer
*)&frag
->data
; p
< (gpointer
*)frag
->pos
; ++p
)
7470 if (frag
== context
->data_stack
.current
)
7478 opcode_count_comparer (const void * pa
, const void * pb
)
7480 long counta
= opcode_counts
[*(int*)pa
];
7481 long countb
= opcode_counts
[*(int*)pb
];
7483 if (counta
< countb
)
7485 else if (counta
> countb
)
7492 interp_print_op_count (void)
7494 int ordered_ops
[MINT_LASTOP
];
7498 for (i
= 0; i
< MINT_LASTOP
; i
++) {
7499 ordered_ops
[i
] = i
;
7500 total_ops
+= opcode_counts
[i
];
7502 qsort (ordered_ops
, MINT_LASTOP
, sizeof (int), opcode_count_comparer
);
7504 for (i
= 0; i
< MINT_LASTOP
; i
++) {
7505 long count
= opcode_counts
[ordered_ops
[i
]];
7506 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops
[i
]), count
, (double)count
/ total_ops
* 100);
7512 interp_set_optimizations (guint32 opts
)
7514 mono_interp_opt
= opts
;
7518 invalidate_transform (gpointer imethod_
)
7520 InterpMethod
*imethod
= (InterpMethod
*) imethod_
;
7521 imethod
->transformed
= FALSE
;
7525 interp_invalidate_transformed (MonoDomain
*domain
)
7527 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
7528 mono_domain_jit_code_hash_lock (domain
);
7529 mono_internal_hash_table_apply (&info
->interp_code_hash
, invalidate_transform
);
7530 mono_domain_jit_code_hash_unlock (domain
);
7534 interp_cleanup (void)
7537 interp_print_op_count ();
7542 register_interp_stats (void)
7544 mono_counters_init ();
7545 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
7546 mono_counters_register ("Methods transformed", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
, &mono_interp_stats
.methods_transformed
);
7547 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.cprop_time
);
7548 mono_counters_register ("Total super instructions time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.super_instructions_time
);
7549 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.stloc_nps
);
7550 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.movlocs
);
7551 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.copy_propagations
);
7552 mono_counters_register ("Added pop count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.added_pop_count
);
7553 mono_counters_register ("Constant folds", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.constant_folds
);
7554 mono_counters_register ("Super instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.super_instructions
);
7555 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.killed_instructions
);
7556 mono_counters_register ("Emitted instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.emitted_instructions
);
7557 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
7558 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
7561 #undef MONO_EE_CALLBACK
7562 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
7564 static const MonoEECallbacks mono_interp_callbacks
= {
7569 mono_ee_interp_init (const char *opts
)
7571 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
7572 g_assert (!interp_init_done
);
7573 interp_init_done
= TRUE
;
7575 mono_native_tls_alloc (&thread_context_id
, NULL
);
7578 interp_parse_options (opts
);
7579 /* Don't do any optimizations if running under debugger */
7580 if (mini_get_debug_options ()->mdb_optimizations
)
7581 mono_interp_opt
= 0;
7582 mono_interp_transform_init ();
7584 mini_install_interp_callbacks (&mono_interp_callbacks
);
7586 register_interp_stats ();