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.
228 alloc_frame (ThreadContext
*ctx
, gpointer native_stack_addr
, InterpFrame
*parent
, InterpMethod
*imethod
, stackval
*stack_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
= stack_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
);
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 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); \
1164 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
1167 intptr_t *lower_bounds
;
1170 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
1171 for (i
= 0; i
< param_count
; ++i
) {
1172 lengths
[i
] = values
->data
.i
;
1175 if (m_class_get_rank (klass
) == param_count
) {
1176 /* Only lengths provided. */
1177 lower_bounds
= NULL
;
1179 /* lower bounds are first. */
1180 lower_bounds
= (intptr_t *) lengths
;
1181 lengths
+= m_class_get_rank (klass
);
1183 return (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
1187 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, gboolean safe
)
1189 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1193 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
1194 guint32 idx
= sp
[i
].data
.i
;
1195 guint32 lower
= ao
->bounds
[i
].lower_bound
;
1196 guint32 len
= ao
->bounds
[i
].length
;
1197 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
))
1199 pos
= (pos
* len
) + idx
- lower
;
1202 pos
= sp
[0].data
.i
;
1203 if (safe
&& pos
>= ao
->max_length
)
1209 static MonoException
*
1210 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1212 MonoObject
*o
= sp
->data
.o
;
1213 MonoArray
*ao
= (MonoArray
*) o
;
1214 MonoClass
*ac
= o
->vtable
->klass
;
1216 g_assert (m_class_get_rank (ac
) >= 1);
1218 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, safe
);
1220 return mono_get_exception_index_out_of_range ();
1222 gint32 esize
= mono_array_element_size (ac
);
1223 gconstpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1225 MonoType
*mt
= sig
->ret
;
1226 stackval_from_data (mt
, retval
, ea
, FALSE
);
1230 static MonoException
*
1231 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1233 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1235 g_assert (m_class_get_rank (ac
) >= 1);
1237 gint32 pos
= ves_array_calculate_index (ao
, sp
, TRUE
);
1239 return mono_get_exception_index_out_of_range ();
1241 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
))
1242 return mono_get_exception_array_type_mismatch ();
1243 gint32 esize
= mono_array_element_size (ac
);
1244 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1248 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1249 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1252 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1253 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1255 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1258 g_assert (mono_arm_eabi_supported ());
1259 int i8_align
= mono_arm_i8_align ();
1269 for (int i
= 0; i
< sig
->param_count
; i
++) {
1270 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1272 case MONO_TYPE_BOOLEAN
:
1273 case MONO_TYPE_CHAR
:
1283 case MONO_TYPE_SZARRAY
:
1284 case MONO_TYPE_CLASS
:
1285 case MONO_TYPE_OBJECT
:
1286 case MONO_TYPE_STRING
:
1287 case MONO_TYPE_VALUETYPE
:
1288 case MONO_TYPE_GENERICINST
:
1289 #if SIZEOF_VOID_P == 8
1295 #if SIZEOF_VOID_P == 4
1299 /* pairs begin at even registers */
1300 if (i8_align
== 8 && margs
->ilen
& 1)
1307 #if SIZEOF_VOID_P == 8
1312 #if SIZEOF_VOID_P == 4
1318 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1322 if (margs
->ilen
> 0)
1323 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1325 if (margs
->flen
> 0)
1326 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1328 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1329 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1331 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1332 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1339 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1343 for (int i
= 0; i
< sig
->param_count
; i
++) {
1344 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1346 case MONO_TYPE_BOOLEAN
:
1347 case MONO_TYPE_CHAR
:
1357 case MONO_TYPE_SZARRAY
:
1358 case MONO_TYPE_CLASS
:
1359 case MONO_TYPE_OBJECT
:
1360 case MONO_TYPE_STRING
:
1361 case MONO_TYPE_VALUETYPE
:
1362 case MONO_TYPE_GENERICINST
:
1363 #if SIZEOF_VOID_P == 8
1367 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1369 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1373 #if SIZEOF_VOID_P == 4
1375 case MONO_TYPE_U8
: {
1376 stackval
*sarg
= &frame
->stack_args
[i
];
1378 /* pairs begin at even registers */
1379 if (i8_align
== 8 && int_i
& 1)
1382 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1384 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1386 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
);
1394 if (ptype
== MONO_TYPE_R4
)
1395 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1397 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1399 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
);
1401 #if SIZEOF_VOID_P == 4
1408 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1412 switch (sig
->ret
->type
) {
1413 case MONO_TYPE_BOOLEAN
:
1414 case MONO_TYPE_CHAR
:
1424 case MONO_TYPE_SZARRAY
:
1425 case MONO_TYPE_CLASS
:
1426 case MONO_TYPE_OBJECT
:
1427 case MONO_TYPE_STRING
:
1430 case MONO_TYPE_VALUETYPE
:
1431 case MONO_TYPE_GENERICINST
:
1432 margs
->retval
= &frame
->retval
->data
.p
;
1433 margs
->is_float_ret
= 0;
1437 margs
->retval
= &frame
->retval
->data
.p
;
1438 margs
->is_float_ret
= 1;
1440 case MONO_TYPE_VOID
:
1441 margs
->retval
= NULL
;
1444 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1452 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1454 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1457 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1459 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1463 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gconstpointer data
)
1465 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1468 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1469 else if (sig
->hasthis
&& index
== 0)
1470 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1472 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1476 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1478 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1481 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1483 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1487 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1489 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1490 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1491 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1493 switch (type
->type
) {
1494 case MONO_TYPE_GENERICINST
:
1495 if (!MONO_TYPE_IS_REFERENCE (type
))
1496 val
->data
.vt
= storage
;
1498 case MONO_TYPE_VALUETYPE
:
1499 val
->data
.vt
= storage
;
1502 g_assert_not_reached ();
1507 get_interp_to_native_trampoline (void)
1509 static MonoPIFunc trampoline
= NULL
;
1512 if (mono_ee_features
.use_aot_trampolines
) {
1513 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1515 MonoTrampInfo
*info
;
1516 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1517 mono_tramp_info_register (info
, NULL
);
1519 mono_memory_barrier ();
1525 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1527 get_interp_to_native_trampoline () (addr
, ccontext
);
1530 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1532 #pragma optimize ("", off)
1534 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1535 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, ThreadContext
*context
, gboolean save_last_error
)
1540 g_assert (!frame
->imethod
);
1542 static MonoPIFunc entry_func
= NULL
;
1544 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1546 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
);
1547 mono_error_assert_ok (error
);
1549 entry_func
= get_interp_to_native_trampoline ();
1551 mono_memory_barrier ();
1554 #ifdef ENABLE_NETCORE
1555 if (save_last_error
) {
1556 mono_marshal_clear_last_error ();
1560 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1561 CallContext ccontext
;
1562 MONO_ENTER_GC_UNSAFE
;
1563 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1564 MONO_EXIT_GC_UNSAFE
;
1567 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1571 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_pinvoke
);
1572 entry_func ((gpointer
) addr
, args
);
1573 if (save_last_error
)
1574 mono_marshal_set_last_error ();
1575 interp_pop_lmf (&ext
);
1577 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1578 if (!context
->has_resume_state
) {
1579 MONO_ENTER_GC_UNSAFE
;
1580 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1581 MONO_EXIT_GC_UNSAFE
;
1584 if (ccontext
.stack
!= NULL
)
1585 g_free (ccontext
.stack
);
1587 if (!context
->has_resume_state
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1588 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1590 g_free (margs
->iargs
);
1591 g_free (margs
->fargs
);
1594 goto exit_pinvoke
; // prevent unused label warning in some configurations
1599 #pragma optimize ("", on)
1603 * interp_init_delegate:
1605 * Initialize del->interp_method.
1608 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1612 if (del
->interp_method
) {
1613 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1614 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1615 } else if (del
->method
) {
1616 /* Delegate created dynamically */
1617 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1619 /* Created from JITted code */
1620 g_assert_not_reached ();
1623 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1626 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1627 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1628 mono_class_is_abstract (method
->klass
))
1629 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1631 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1632 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1633 const char *name
= method
->name
;
1634 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1636 * When invoking the delegate interp_method is executed directly. If it's an
1637 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1639 * FIXME We should do this later, when we also know the delegate on which the
1640 * target method is called.
1642 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1643 mono_error_assert_ok (error
);
1647 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1648 /* Return any errors from method compilation */
1649 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1650 return_if_nok (error
);
1655 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1658 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1660 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1662 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1663 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1664 /* virtual invoke delegates must not have null check */
1665 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1666 && MONO_HANDLE_IS_NULL (target
)) {
1667 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1672 g_assert (imethod
->method
);
1673 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1674 return_if_nok (error
);
1676 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1678 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1683 * runtime specifies that the implementation of the method is automatically
1684 * provided by the runtime and is primarily used for the methods of delegates.
1686 #ifndef ENABLE_NETCORE
1687 static MONO_NEVER_INLINE MonoException
*
1688 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1690 const char *name
= method
->name
;
1691 mono_class_init_internal (method
->klass
);
1693 if (method
->klass
== mono_defaults
.array_class
) {
1694 if (!strcmp (name
, "UnsafeMov")) {
1695 /* TODO: layout checks */
1696 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1699 if (!strcmp (name
, "UnsafeLoad"))
1700 return ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1703 g_error ("Don't know how to exec runtime method %s.%s::%s",
1704 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1711 dump_stack (stackval
*stack
, stackval
*sp
)
1713 stackval
*s
= stack
;
1714 GString
*str
= g_string_new ("");
1717 return g_string_free (str
, FALSE
);
1720 g_string_append_printf (str
, "[%p (%" PRId64
")] ", s
->data
.l
, (gint64
)s
->data
.l
);
1723 return g_string_free (str
, FALSE
);
1727 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1729 switch (type
->type
) {
1736 case MONO_TYPE_CHAR
:
1737 case MONO_TYPE_BOOLEAN
:
1738 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1740 case MONO_TYPE_STRING
:
1741 case MONO_TYPE_SZARRAY
:
1742 case MONO_TYPE_CLASS
:
1743 case MONO_TYPE_OBJECT
:
1744 case MONO_TYPE_ARRAY
:
1748 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1750 case MONO_TYPE_VALUETYPE
:
1751 if (m_class_is_enumtype (type
->data
.klass
))
1752 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1754 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1757 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1760 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1765 GString
*res
= g_string_new ("");
1766 mono_type_get_desc (res
, type
, TRUE
);
1767 g_string_append_printf (str
, "[{%s} %" PRId64
"/0x%0" PRIx64
"] ", res
->str
, (gint64
)s
->data
.l
, (guint64
)s
->data
.l
);
1768 g_string_free (res
, TRUE
);
1775 dump_retval (InterpFrame
*inv
)
1777 GString
*str
= g_string_new ("");
1778 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1780 if (ret
->type
!= MONO_TYPE_VOID
)
1781 dump_stackval (str
, inv
->retval
, ret
);
1783 return g_string_free (str
, FALSE
);
1787 dump_args (InterpFrame
*inv
)
1789 GString
*str
= g_string_new ("");
1791 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1793 if (signature
->param_count
== 0 && !signature
->hasthis
)
1794 return g_string_free (str
, FALSE
);
1796 if (signature
->hasthis
) {
1797 MonoMethod
*method
= inv
->imethod
->method
;
1798 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1801 for (i
= 0; i
< signature
->param_count
; ++i
)
1802 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1804 return g_string_free (str
, FALSE
);
1808 #define CHECK_ADD_OVERFLOW(a,b) \
1809 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1810 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1812 #define CHECK_SUB_OVERFLOW(a,b) \
1813 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1814 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1816 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1817 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1819 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1820 (guint32)(a) < (guint32)(b) ? -1 : 0
1822 #define CHECK_ADD_OVERFLOW64(a,b) \
1823 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1824 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1826 #define CHECK_SUB_OVERFLOW64(a,b) \
1827 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1828 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1830 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1831 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1833 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1834 (guint64)(a) < (guint64)(b) ? -1 : 0
1836 #if SIZEOF_VOID_P == 4
1837 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1838 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1840 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1841 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1844 /* Resolves to TRUE if the operands would overflow */
1845 #define CHECK_MUL_OVERFLOW(a,b) \
1846 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1847 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1848 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1849 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1850 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1851 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1852 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1854 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1855 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1856 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1858 #define CHECK_MUL_OVERFLOW64(a,b) \
1859 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1860 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1861 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1862 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1863 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1864 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1865 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1867 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1868 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1869 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1871 #if SIZEOF_VOID_P == 4
1872 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1873 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1875 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1876 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1880 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1883 ThreadContext
*context
= get_context ();
1884 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1885 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1887 MonoMethod
*target_method
= method
;
1893 MonoDomain
*domain
= mono_domain_get ();
1895 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1896 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1897 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1899 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1901 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1905 args
[0].data
.p
= obj
;
1907 args
[0].data
.p
= NULL
;
1908 args
[1].data
.p
= params
;
1909 args
[2].data
.p
= exc
;
1910 args
[3].data
.p
= target_method
;
1912 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1913 mono_error_assert_ok (error
);
1914 frame
= alloc_frame (context
, &result
, NULL
, imethod
, args
, &result
);
1916 interp_exec_method (frame
, context
, error
);
1918 if (context
->has_resume_state
) {
1919 // This can happen on wasm !?
1920 MonoException
*thrown_exc
= (MonoException
*) mono_gchandle_get_target_internal (context
->exc_gchandle
);
1922 *exc
= (MonoObject
*)thrown_exc
;
1924 mono_error_set_exception_instance (error
, thrown_exc
);
1927 return (MonoObject
*)result
.data
.p
;
1931 InterpMethod
*rmethod
;
1935 gpointer
*many_args
;
1938 /* Main function for entering the interpreter from compiled code */
1940 interp_entry (InterpEntryData
*data
)
1943 InterpMethod
*rmethod
;
1944 ThreadContext
*context
;
1948 MonoMethodSignature
*sig
;
1950 gpointer orig_domain
= NULL
, attach_cookie
;
1953 if ((gsize
)data
->rmethod
& 1) {
1955 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1956 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1958 rmethod
= data
->rmethod
;
1960 if (rmethod
->needs_thread_attach
)
1961 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1963 context
= get_context ();
1965 method
= rmethod
->method
;
1966 sig
= mono_method_signature_internal (method
);
1968 // FIXME: Optimize this
1970 //printf ("%s\n", mono_method_full_name (method, 1));
1972 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1974 args
[0].data
.p
= data
->this_arg
;
1977 if (data
->many_args
)
1978 params
= data
->many_args
;
1980 params
= data
->args
;
1981 for (i
= 0; i
< sig
->param_count
; ++i
) {
1982 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1983 if (sig
->params
[i
]->byref
) {
1984 args
[a_index
].data
.p
= params
[i
];
1987 type
= rmethod
->param_types
[i
];
1988 switch (type
->type
) {
1989 case MONO_TYPE_VALUETYPE
:
1990 args
[a_index
].data
.p
= params
[i
];
1992 case MONO_TYPE_GENERICINST
:
1993 if (MONO_TYPE_IS_REFERENCE (type
))
1994 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1996 args
[a_index
].data
.vt
= params
[i
];
1999 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
2004 memset (&result
, 0, sizeof (result
));
2005 frame
= alloc_frame (context
, &result
, NULL
, data
->rmethod
, args
, &result
);
2007 type
= rmethod
->rtype
;
2008 switch (type
->type
) {
2009 case MONO_TYPE_GENERICINST
:
2010 if (!MONO_TYPE_IS_REFERENCE (type
))
2011 result
.data
.vt
= data
->res
;
2013 case MONO_TYPE_VALUETYPE
:
2014 result
.data
.vt
= data
->res
;
2021 interp_exec_method (frame
, context
, error
);
2023 g_assert (!context
->has_resume_state
);
2025 if (rmethod
->needs_thread_attach
)
2026 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2028 if (mono_llvm_only
) {
2029 if (context
->has_resume_state
)
2030 mono_llvm_reraise_exception ((MonoException
*)mono_gchandle_get_target_internal (context
->exc_gchandle
));
2032 g_assert (!context
->has_resume_state
);
2035 type
= rmethod
->rtype
;
2036 switch (type
->type
) {
2037 case MONO_TYPE_VOID
:
2039 case MONO_TYPE_OBJECT
:
2040 /* No need for a write barrier */
2041 *(MonoObject
**)data
->res
= (MonoObject
*)result
.data
.p
;
2043 case MONO_TYPE_GENERICINST
:
2044 if (MONO_TYPE_IS_REFERENCE (type
)) {
2045 *(MonoObject
**)data
->res
= (MonoObject
*)result
.data
.p
;
2047 /* Already set before the call */
2050 case MONO_TYPE_VALUETYPE
:
2051 /* Already set before the call */
2054 stackval_to_data (type
, &result
, data
->res
, FALSE
);
2060 do_icall (MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2062 #ifdef ENABLE_NETCORE
2063 if (save_last_error
)
2064 mono_marshal_clear_last_error ();
2068 case MINT_ICALL_V_V
: {
2069 typedef void (*T
)(void);
2074 case MINT_ICALL_V_P
: {
2075 typedef gpointer (*T
)(void);
2078 sp
[-1].data
.p
= func ();
2081 case MINT_ICALL_P_V
: {
2082 typedef void (*T
)(gpointer
);
2084 func (sp
[-1].data
.p
);
2088 case MINT_ICALL_P_P
: {
2089 typedef gpointer (*T
)(gpointer
);
2091 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
2094 case MINT_ICALL_PP_V
: {
2095 typedef void (*T
)(gpointer
,gpointer
);
2098 func (sp
[0].data
.p
, sp
[1].data
.p
);
2101 case MINT_ICALL_PP_P
: {
2102 typedef gpointer (*T
)(gpointer
,gpointer
);
2105 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
2108 case MINT_ICALL_PPP_V
: {
2109 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
2112 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2115 case MINT_ICALL_PPP_P
: {
2116 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
2119 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
2122 case MINT_ICALL_PPPP_V
: {
2123 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2126 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
2129 case MINT_ICALL_PPPP_P
: {
2130 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2133 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2136 case MINT_ICALL_PPPPP_V
: {
2137 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2140 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
2143 case MINT_ICALL_PPPPP_P
: {
2144 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2147 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
);
2150 case MINT_ICALL_PPPPPP_V
: {
2151 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2154 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
);
2157 case MINT_ICALL_PPPPPP_P
: {
2158 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2161 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
);
2165 g_assert_not_reached ();
2168 if (save_last_error
)
2169 mono_marshal_set_last_error ();
2171 /* convert the native representation to the stackval representation */
2173 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2178 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2180 #pragma optimize ("", off)
2182 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
2183 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2186 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
2188 sp
= do_icall (sig
, op
, sp
, ptr
, save_last_error
);
2190 interp_pop_lmf (&ext
);
2192 goto exit_icall
; // prevent unused label warning in some configurations
2197 #pragma optimize ("", on)
2202 gpointer jit_wrapper
;
2204 MonoFtnDesc
*ftndesc
;
2208 jit_call_cb (gpointer arg
)
2210 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2211 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2212 int pindex
= cb_data
->pindex
;
2213 gpointer
*args
= cb_data
->args
;
2214 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2218 typedef void (*T
)(gpointer
);
2219 T func
= (T
)jit_wrapper
;
2225 typedef void (*T
)(gpointer
, gpointer
);
2226 T func
= (T
)jit_wrapper
;
2228 func (args
[0], &ftndesc
);
2232 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2233 T func
= (T
)jit_wrapper
;
2235 func (args
[0], args
[1], &ftndesc
);
2239 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2240 T func
= (T
)jit_wrapper
;
2242 func (args
[0], args
[1], args
[2], &ftndesc
);
2246 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2247 T func
= (T
)jit_wrapper
;
2249 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2253 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2254 T func
= (T
)jit_wrapper
;
2256 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2260 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2261 T func
= (T
)jit_wrapper
;
2263 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2267 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2268 T func
= (T
)jit_wrapper
;
2270 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2274 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2275 T func
= (T
)jit_wrapper
;
2277 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2281 g_assert_not_reached ();
2286 static MONO_NEVER_INLINE
void
2287 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2289 MonoMethodSignature
*sig
;
2290 MonoFtnDesc ftndesc
;
2291 guint8 res_buf
[256];
2295 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2298 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2299 * by ref and return a return value using an explicit return value argument.
2301 if (G_UNLIKELY (!rmethod
->jit_wrapper
)) {
2302 MonoMethod
*method
= rmethod
->method
;
2304 sig
= mono_method_signature_internal (method
);
2307 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2308 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2310 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2311 mono_error_assert_ok (error
);
2313 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2314 return_if_nok (error
);
2317 rmethod
->jit_addr
= addr
;
2318 rmethod
->jit_sig
= sig
;
2319 mono_memory_barrier ();
2320 rmethod
->jit_wrapper
= jit_wrapper
;
2323 sig
= rmethod
->jit_sig
;
2326 ftndesc
.addr
= rmethod
->jit_addr
;
2329 // FIXME: Optimize this
2333 int stack_index
= 0;
2334 if (rmethod
->hasthis
) {
2335 args
[pindex
++] = sp
[0].data
.p
;
2338 type
= rmethod
->rtype
;
2339 if (type
->type
!= MONO_TYPE_VOID
) {
2340 if (MONO_TYPE_ISSTRUCT (type
))
2341 args
[pindex
++] = vt_sp
;
2343 args
[pindex
++] = res_buf
;
2345 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2346 MonoType
*t
= rmethod
->param_types
[i
];
2347 stackval
*sval
= &sp
[stack_index
+ i
];
2348 if (sig
->params
[i
]->byref
) {
2349 args
[pindex
++] = sval
->data
.p
;
2350 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2351 args
[pindex
++] = sval
->data
.p
;
2352 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2353 args
[pindex
++] = &sval
->data
.p
;
2362 case MONO_TYPE_VALUETYPE
:
2363 args
[pindex
++] = &sval
->data
.i
;
2366 case MONO_TYPE_FNPTR
:
2369 case MONO_TYPE_OBJECT
:
2370 args
[pindex
++] = &sval
->data
.p
;
2374 args
[pindex
++] = &sval
->data
.l
;
2377 args
[pindex
++] = &sval
->data
.f_r4
;
2380 args
[pindex
++] = &sval
->data
.f
;
2383 printf ("%s\n", mono_type_full_name (t
));
2384 g_assert_not_reached ();
2389 interp_push_lmf (&ext
, frame
);
2391 JitCallCbData cb_data
;
2392 memset (&cb_data
, 0, sizeof (cb_data
));
2393 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2394 cb_data
.pindex
= pindex
;
2395 cb_data
.args
= args
;
2396 cb_data
.ftndesc
= &ftndesc
;
2398 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2399 /* Catch the exception thrown by the native code using a try-catch */
2400 gboolean thrown
= FALSE
;
2401 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2402 interp_pop_lmf (&ext
);
2404 MonoObject
*obj
= mono_llvm_load_exception ();
2406 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2410 jit_call_cb (&cb_data
);
2411 interp_pop_lmf (&ext
);
2414 MonoType
*rtype
= rmethod
->rtype
;
2415 switch (rtype
->type
) {
2416 case MONO_TYPE_VOID
:
2417 case MONO_TYPE_OBJECT
:
2418 case MONO_TYPE_STRING
:
2419 case MONO_TYPE_CLASS
:
2420 case MONO_TYPE_ARRAY
:
2421 case MONO_TYPE_SZARRAY
:
2425 sp
->data
.p
= *(gpointer
*)res_buf
;
2428 sp
->data
.i
= *(gint8
*)res_buf
;
2431 sp
->data
.i
= *(guint8
*)res_buf
;
2434 sp
->data
.i
= *(gint16
*)res_buf
;
2437 sp
->data
.i
= *(guint16
*)res_buf
;
2440 sp
->data
.i
= *(gint32
*)res_buf
;
2443 sp
->data
.i
= *(guint32
*)res_buf
;
2446 sp
->data
.l
= *(gint64
*)res_buf
;
2449 sp
->data
.l
= *(guint64
*)res_buf
;
2452 sp
->data
.f_r4
= *(float*)res_buf
;
2455 sp
->data
.f
= *(double*)res_buf
;
2457 case MONO_TYPE_TYPEDBYREF
:
2458 case MONO_TYPE_VALUETYPE
:
2459 /* The result was written to vt_sp */
2462 case MONO_TYPE_GENERICINST
:
2463 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2464 sp
->data
.p
= *(gpointer
*)res_buf
;
2466 /* The result was written to vt_sp */
2471 g_print ("%s\n", mono_type_full_name (rtype
));
2472 g_assert_not_reached ();
2477 static MONO_NEVER_INLINE
void
2478 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2481 interp_push_lmf (&ext
, frame
);
2483 interp_pop_lmf (&ext
);
2486 static MONO_NEVER_INLINE MonoException
*
2487 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2490 /* Don't push lmf if we have no interp data */
2491 gboolean push_lmf
= frame
->parent
!= NULL
;
2494 /* Use the parent frame as the current frame is not complete yet */
2496 interp_push_lmf (&ext
, frame
->parent
);
2498 mono_interp_transform_method (frame
->imethod
, context
, error
);
2501 interp_pop_lmf (&ext
);
2503 return mono_error_convert_to_exception (error
);
2507 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, guchar
*vt_sp_start
)
2509 stackval
*first_arg
= sp
- csig
->param_count
;
2510 guchar
*vt_sp
= vt_sp_start
;
2513 * We need to have the varargs linearly on the stack so the ArgIterator
2514 * can iterate over them. We pass the signature first and then copy them
2515 * one by one on the vtstack. At the end we pass the original vt_stack
2516 * so the callee (MINT_ARGLIST) can find the varargs space.
2518 *(gpointer
*)vt_sp
= csig
;
2519 vt_sp
+= sizeof (gpointer
);
2521 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2522 int align
, arg_size
;
2523 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2524 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, align
);
2526 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt_sp
, FALSE
);
2530 vt_sp
+= sizeof (gpointer
);
2531 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, MINT_VT_ALIGNMENT
);
2533 ((gpointer
*)vt_sp
) [-1] = vt_sp_start
;
2539 * These functions are the entry points into the interpreter from compiled code.
2540 * They are called by the interp_in wrappers. They have the following signature:
2541 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2542 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2543 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2544 * more wrappers then these functions.
2545 * this/static * ret/void * 16 arguments -> 64 functions.
2548 #define MAX_INTERP_ENTRY_ARGS 8
2550 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2551 InterpEntryData data; \
2552 (data).rmethod = (_method); \
2553 (data).res = (_res); \
2554 (data).this_arg = (_this_arg); \
2555 (data).many_args = NULL;
2557 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2558 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2559 interp_entry (&data); \
2561 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2562 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2563 (data).args [0] = arg1; \
2564 interp_entry (&data); \
2566 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2567 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2568 (data).args [0] = arg1; \
2569 (data).args [1] = arg2; \
2570 interp_entry (&data); \
2572 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2573 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2574 (data).args [0] = arg1; \
2575 (data).args [1] = arg2; \
2576 (data).args [2] = arg3; \
2577 interp_entry (&data); \
2579 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2580 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2581 (data).args [0] = arg1; \
2582 (data).args [1] = arg2; \
2583 (data).args [2] = arg3; \
2584 (data).args [3] = arg4; \
2585 interp_entry (&data); \
2587 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2588 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2589 (data).args [0] = arg1; \
2590 (data).args [1] = arg2; \
2591 (data).args [2] = arg3; \
2592 (data).args [3] = arg4; \
2593 (data).args [4] = arg5; \
2594 interp_entry (&data); \
2596 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2597 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2598 (data).args [0] = arg1; \
2599 (data).args [1] = arg2; \
2600 (data).args [2] = arg3; \
2601 (data).args [3] = arg4; \
2602 (data).args [4] = arg5; \
2603 (data).args [5] = arg6; \
2604 interp_entry (&data); \
2606 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2607 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2608 (data).args [0] = arg1; \
2609 (data).args [1] = arg2; \
2610 (data).args [2] = arg3; \
2611 (data).args [3] = arg4; \
2612 (data).args [4] = arg5; \
2613 (data).args [5] = arg6; \
2614 (data).args [6] = arg7; \
2615 interp_entry (&data); \
2617 #define INTERP_ENTRY8(_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 (data).args [7] = arg8; \
2627 interp_entry (&data); \
2630 #define ARGLIST0 InterpMethod *rmethod
2631 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2632 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2633 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2634 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2635 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2636 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2637 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2638 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2640 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2641 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2642 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2643 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2644 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2645 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2646 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2647 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2648 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2649 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2650 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2651 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2652 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2653 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2654 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2655 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2656 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2657 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2658 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2659 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2660 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2661 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2662 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2663 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2664 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2665 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2666 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2667 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2668 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2669 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2670 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2671 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2672 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2673 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2674 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2675 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2677 #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
2679 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2680 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2681 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2682 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2684 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2686 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2688 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2689 data
.many_args
= args
;
2690 interp_entry (&data
);
2693 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2695 // inline so we can alloc on stack
2696 #define alloc_storage_for_stackval(s, t, p) do { \
2697 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2698 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2699 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2701 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2703 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2708 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2711 ThreadContext
*context
;
2715 MonoMethodSignature
*sig
;
2716 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2717 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2718 gpointer orig_domain
= NULL
, attach_cookie
;
2721 if (rmethod
->needs_thread_attach
)
2722 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2724 context
= get_context ();
2726 method
= rmethod
->method
;
2727 sig
= mono_method_signature_internal (method
);
2728 if (method
->string_ctor
) {
2729 MonoMethodSignature
*newsig
= g_alloca (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
2730 memcpy (newsig
, sig
, mono_metadata_signature_size (sig
));
2731 newsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2735 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2737 frame
= alloc_frame (context
, &result
, NULL
, rmethod
, args
, &result
);
2739 /* Allocate storage for value types */
2740 for (i
= 0; i
< sig
->param_count
; i
++) {
2741 MonoType
*type
= sig
->params
[i
];
2742 alloc_storage_for_stackval (&frame
->stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2745 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2746 alloc_storage_for_stackval (frame
->retval
, sig
->ret
, sig
->pinvoke
);
2748 /* Copy the args saved in the trampoline to the frame stack */
2749 mono_arch_get_native_call_context_args (ccontext
, frame
, sig
);
2752 interp_exec_method (frame
, context
, error
);
2754 g_assert (!context
->has_resume_state
);
2756 if (rmethod
->needs_thread_attach
)
2757 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2759 /* Write back the return value */
2760 /* 'frame' is still valid */
2761 mono_arch_set_native_call_context_ret (ccontext
, frame
, sig
);
2767 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2769 g_assert_not_reached ();
2772 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2774 static InterpMethod
*
2775 lookup_method_pointer (gpointer addr
)
2777 MonoDomain
*domain
= mono_domain_get ();
2778 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2779 InterpMethod
*res
= NULL
;
2781 mono_domain_lock (domain
);
2782 if (info
->interp_method_pointer_hash
)
2783 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2784 mono_domain_unlock (domain
);
2789 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2791 interp_no_native_to_managed (void)
2793 g_error ("interpreter: native-to-managed transition not available on this platform");
2798 no_llvmonly_interp_method_pointer (void)
2800 g_assert_not_reached ();
2804 * interp_create_method_pointer_llvmonly:
2806 * Return an ftndesc for entering the interpreter and executing METHOD.
2809 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2811 MonoDomain
*domain
= mono_domain_get ();
2812 gpointer addr
, entry_func
, entry_wrapper
;
2813 MonoMethodSignature
*sig
;
2814 MonoMethod
*wrapper
;
2815 MonoJitDomainInfo
*info
;
2816 InterpMethod
*imethod
;
2818 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2819 return_val_if_nok (error
, NULL
);
2822 if (imethod
->llvmonly_unbox_entry
)
2823 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2825 if (imethod
->jit_entry
)
2826 return (MonoFtnDesc
*)imethod
->jit_entry
;
2829 sig
= mono_method_signature_internal (method
);
2832 * The entry functions need access to the method to call, so we have
2833 * to use a ftndesc. The caller uses a normal signature, while the
2834 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2835 * a gsharedvt_in_sig wrapper.
2837 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2839 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2840 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2841 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2842 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2844 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2845 g_assert_not_reached ();
2846 //entry_func = (gpointer)interp_entry_general;
2847 } else if (sig
->hasthis
) {
2848 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2849 entry_func
= entry_funcs_instance
[sig
->param_count
];
2851 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2853 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2854 entry_func
= entry_funcs_static
[sig
->param_count
];
2856 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2858 g_assert (entry_func
);
2860 /* Encode unbox in the lower bit of imethod */
2861 gpointer entry_arg
= imethod
;
2863 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2864 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2866 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2868 info
= domain_jit_info (domain
);
2869 mono_domain_lock (domain
);
2870 if (!info
->interp_method_pointer_hash
)
2871 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2872 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2873 mono_domain_unlock (domain
);
2875 mono_memory_barrier ();
2877 imethod
->llvmonly_unbox_entry
= addr
;
2879 imethod
->jit_entry
= addr
;
2881 return (MonoFtnDesc
*)addr
;
2885 * interp_create_method_pointer:
2887 * Return a function pointer which can be used to call METHOD using the
2888 * interpreter. Return NULL for methods which are not supported.
2891 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2893 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2895 return (gpointer
)no_llvmonly_interp_method_pointer
;
2896 return (gpointer
)interp_no_native_to_managed
;
2898 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2899 MonoDomain
*domain
= mono_domain_get ();
2900 MonoJitDomainInfo
*info
;
2901 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2904 return (gpointer
)no_llvmonly_interp_method_pointer
;
2906 if (imethod
->jit_entry
)
2907 return imethod
->jit_entry
;
2909 if (compile
&& !imethod
->transformed
) {
2910 /* Return any errors from method compilation */
2911 mono_interp_transform_method (imethod
, get_context (), error
);
2912 return_val_if_nok (error
, NULL
);
2915 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2916 if (method
->string_ctor
) {
2917 MonoMethodSignature
*newsig
= g_alloca (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
2918 memcpy (newsig
, sig
, mono_metadata_signature_size (sig
));
2919 newsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2924 /* The caller should call interp_create_method_pointer_llvmonly */
2925 g_assert_not_reached ();
2927 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2930 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2932 * Interp in wrappers get the argument in the rgctx register. If
2933 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2934 * on that arch the rgctx register is not scratch, so we use a
2935 * separate temp register. We should update the wrappers for this
2936 * if we really care about those architectures (arm).
2938 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2940 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2942 if (entry_wrapper
) {
2943 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2944 entry_func
= (gpointer
)interp_entry_general
;
2945 } else if (sig
->hasthis
) {
2946 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2947 entry_func
= entry_funcs_instance
[sig
->param_count
];
2949 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2951 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2952 entry_func
= entry_funcs_static
[sig
->param_count
];
2954 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2957 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2958 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2959 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2960 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2962 mono_error_cleanup (error
);
2963 error_init_reuse (error
);
2964 if (!mono_native_to_interp_trampoline
) {
2965 if (mono_aot_only
) {
2966 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2968 MonoTrampInfo
*info
;
2969 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2970 mono_tramp_info_register (info
, NULL
);
2973 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2974 /* We need the lmf wrapper only when being called from mixed mode */
2976 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2978 static gpointer cached_func
= NULL
;
2980 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
);
2981 mono_memory_barrier ();
2983 entry_func
= cached_func
;
2988 g_assert (entry_func
);
2989 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2990 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2991 ftndesc
->addr
= entry_func
;
2992 ftndesc
->arg
= imethod
;
2993 mono_error_assert_ok (error
);
2996 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2997 * rgctx register using a trampoline.
3000 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
3002 info
= domain_jit_info (domain
);
3003 mono_domain_lock (domain
);
3004 if (!info
->interp_method_pointer_hash
)
3005 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
3006 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
3007 mono_domain_unlock (domain
);
3009 mono_memory_barrier ();
3010 imethod
->jit_entry
= addr
;
3017 interp_free_method (MonoDomain
*domain
, MonoMethod
*method
)
3019 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3021 mono_domain_jit_code_hash_lock (domain
);
3022 /* InterpMethod is allocated in the domain mempool. We might haven't
3023 * allocated an InterpMethod for this instance yet */
3024 mono_internal_hash_table_remove (&info
->interp_code_hash
, method
);
3025 mono_domain_jit_code_hash_unlock (domain
);
3029 static long opcode_counts
[MINT_LASTOP
];
3031 #define COUNT_OP(op) opcode_counts[op]++
3033 #define COUNT_OP(op)
3037 #define DUMP_INSTR() \
3038 if (tracing > 1) { \
3040 if (sp > frame->stack) { \
3041 ins = dump_stack (frame->stack, sp); \
3043 ins = g_strdup (""); \
3047 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
3048 char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
3049 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
3055 #define DUMP_INSTR()
3058 #define INIT_VTABLE(vtable) do { \
3059 if (G_UNLIKELY (!(vtable)->initialized)) { \
3060 mono_runtime_class_init_full ((vtable), error); \
3061 if (!is_ok (error)) \
3062 goto throw_error_label; \
3067 mono_interp_new (MonoDomain
* domain
, MonoClass
* klass
)
3070 MonoObject
* const object
= mono_object_new_checked (domain
, klass
, error
);
3071 mono_error_cleanup (error
); // FIXME: do not swallow the error
3076 mono_interp_load_remote_field (
3077 InterpMethod
* imethod
,
3082 g_assert (o
); // Caller checks and throws exception properly.
3085 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3087 #ifndef DISABLE_REMOTING
3089 if (mono_object_is_transparent_proxy (o
)) {
3090 MonoClass
* const klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3092 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3093 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3096 addr
= (char*)o
+ field
->offset
;
3097 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
3101 guchar
* // Return new vt_sp instead of take-address.
3102 mono_interp_load_remote_field_vt (
3103 InterpMethod
* imethod
,
3109 g_assert (o
); // Caller checks and throws exception properly.
3112 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3113 MonoClass
* klass
= mono_class_from_mono_type_internal (field
->type
);
3114 int const i32
= mono_class_value_size (klass
, NULL
);
3116 #ifndef DISABLE_REMOTING
3118 if (mono_object_is_transparent_proxy (o
)) {
3119 klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3121 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3122 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3125 addr
= (char*)o
+ field
->offset
;
3126 sp
[-1].data
.p
= vt_sp
;
3127 memcpy (vt_sp
, addr
, i32
);
3128 return vt_sp
+ ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3132 mono_interp_isinst (MonoObject
* object
, MonoClass
* klass
)
3136 MonoClass
*obj_class
= mono_object_class (object
);
3137 // mono_class_is_assignable_from_checked can't handle remoting casts
3138 if (mono_class_is_transparent_proxy (obj_class
))
3139 isinst
= mono_object_isinst_checked (object
, klass
, error
) != NULL
;
3141 mono_class_is_assignable_from_checked (klass
, obj_class
, &isinst
, error
);
3142 mono_error_cleanup (error
); // FIXME: do not swallow the error
3146 // Do not inline use of alloca.
3147 static MONO_NEVER_INLINE
void
3148 mono_interp_calli_nat_dynamic_pinvoke (
3149 // Parameters are sorted by name.
3150 InterpFrame
* child_frame
,
3152 ThreadContext
* context
,
3153 MonoMethodSignature
* csignature
,
3156 // Recompute to limit parameters, which can also contribute to caller stack.
3157 InterpMethod
* const imethod
= child_frame
->parent
->imethod
;
3159 g_assert (imethod
->method
->dynamic
&& csignature
->pinvoke
);
3161 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3162 MonoMarshalSpec
** mspecs
= g_newa (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3163 memset (mspecs
, 0, sizeof (MonoMarshalSpec
*) * (csignature
->param_count
+ 1));
3165 MonoMethodPInvoke iinfo
;
3166 memset (&iinfo
, 0, sizeof (iinfo
));
3168 MonoMethod
* m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &iinfo
, mspecs
, code
);
3170 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3172 mono_metadata_free_marshal_spec (mspecs
[i
]);
3176 child_frame
->imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
3177 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3180 interp_exec_method (child_frame
, context
, error
);
3183 static MonoException
*
3184 mono_interp_leave (InterpFrame
* child_frame
)
3188 * We need for mono_thread_get_undeniable_exception to be able to unwind
3189 * to check the abort threshold. For this to work we use child_frame as a
3190 * dummy frame that is stored in the lmf and serves as the transition frame
3192 do_icall_wrapper (child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
3194 return (MonoException
*)tmp_sp
.data
.p
;
3198 mono_interp_enum_hasflag (stackval
* sp
, MonoClass
* klass
)
3200 guint64 a_val
= 0, b_val
= 0;
3202 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &b_val
, FALSE
);
3203 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &a_val
, FALSE
);
3204 sp
->data
.i
= (a_val
& b_val
) == b_val
;
3208 mono_interp_box_nullable (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3210 InterpMethod
* const imethod
= frame
->imethod
;
3211 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[ip
[1]];
3213 int const size
= mono_class_value_size (c
, NULL
);
3215 guint16 offset
= ip
[2];
3216 guint16 pop_vt_sp
= !ip
[3];
3218 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
3219 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3221 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3225 mono_interp_box_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3227 InterpMethod
* const imethod
= frame
->imethod
;
3229 MonoObject
* o
; // See the comment about GC safety.
3230 MonoVTable
* const vtable
= (MonoVTable
*)imethod
->data_items
[ip
[1]];
3231 MonoClass
* const c
= vtable
->klass
;
3233 int const size
= mono_class_value_size (c
, NULL
);
3235 guint16 offset
= ip
[2];
3236 guint16 pop_vt_sp
= !ip
[3];
3238 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3239 mono_value_copy_internal (mono_object_get_data (o
), sp
[-1 - offset
].data
.p
, c
);
3241 sp
[-1 - offset
].data
.p
= o
;
3242 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3246 mono_interp_box (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
)
3248 MonoObject
*o
; // See the comment about GC safety.
3249 MonoVTable
* const vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
3251 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3253 guint16
const offset
= ip
[2];
3255 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (o
), FALSE
);
3257 sp
[-1 - offset
].data
.p
= o
;
3261 mono_interp_store_remote_field_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3263 InterpMethod
* const imethod
= frame
->imethod
;
3264 MonoClassField
*field
;
3266 MonoObject
* const o
= sp
[-2].data
.o
;
3268 field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3269 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
3270 int const i32
= mono_class_value_size (klass
, NULL
);
3272 #ifndef DISABLE_REMOTING
3273 if (mono_object_is_transparent_proxy (o
)) {
3274 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3275 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
3276 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3279 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3281 return ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3284 // varargs in wasm consumes extra linear stack per call-site.
3285 // These g_warning/g_error wrappers fix that. It is not the
3286 // small wasm stack, but conserving it is still desirable.
3288 g_warning_d (const char *format
, int d
)
3290 g_warning (format
, d
);
3294 g_warning_ds (const char *format
, int d
, const char *s
)
3296 g_warning (format
, d
, s
);
3299 #if !USE_COMPUTED_GOTO
3301 g_error_xsx (const char *format
, int x1
, const char *s
, int x2
)
3303 g_error (format
, x1
, s
, x2
);
3307 static MONO_ALWAYS_INLINE gboolean
3308 method_entry (ThreadContext
*context
, InterpFrame
*frame
,
3312 MonoException
**out_ex
, FrameClauseArgs
*clause_args
)
3314 gboolean slow
= FALSE
;
3317 debug_enter (frame
, out_tracing
);
3321 if (!G_UNLIKELY (frame
->imethod
->transformed
)) {
3324 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
3325 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
3329 MonoException
*ex
= do_transform_method (frame
, context
);
3336 if (!clause_args
|| clause_args
->base_frame
)
3337 alloc_stack_data (context
, frame
, frame
->imethod
->alloca_size
);
3342 /* Save the state of the interpeter main loop into FRAME */
3343 #define SAVE_INTERP_STATE(frame) do { \
3344 frame->state.ip = ip; \
3345 frame->state.sp = sp; \
3346 frame->state.vt_sp = vt_sp; \
3347 frame->state.is_void = is_void; \
3348 frame->state.finally_ips = finally_ips; \
3349 frame->state.clause_args = clause_args; \
3352 /* Load and clear state from FRAME */
3353 #define LOAD_INTERP_STATE(frame) do { \
3354 ip = frame->state.ip; \
3355 sp = frame->state.sp; \
3356 is_void = frame->state.is_void; \
3357 vt_sp = frame->state.vt_sp; \
3358 finally_ips = frame->state.finally_ips; \
3359 clause_args = frame->state.clause_args; \
3360 locals = (unsigned char *)frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size; \
3361 frame->state.ip = NULL; \
3364 /* Initialize interpreter state for executing FRAME */
3365 #define INIT_INTERP_STATE(frame, _clause_args) do { \
3366 ip = _clause_args ? (_clause_args)->start_with_ip : (frame)->imethod->code; \
3367 sp = (frame)->stack; \
3368 vt_sp = (unsigned char *) sp + (frame)->imethod->stack_size; \
3369 locals = (unsigned char *) vt_sp + (frame)->imethod->vt_stack_size; \
3370 finally_ips = NULL; \
3374 * If CLAUSE_ARGS is non-null, start executing from it.
3375 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3376 * to return error information.
3377 * FRAME is only valid until the next call to alloc_frame ().
3379 static MONO_NEVER_INLINE
void
3380 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
)
3382 InterpMethod
*cmethod
;
3387 /* Interpreter main loop state (InterpState) */
3388 const guint16
*ip
= NULL
;
3390 unsigned char *vt_sp
;
3391 unsigned char *locals
= NULL
;
3392 GSList
*finally_ips
= NULL
;
3395 int tracing
= global_tracing
;
3396 unsigned char *vtalloc
;
3398 #if USE_COMPUTED_GOTO
3399 static void * const in_labels
[] = {
3400 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3401 #include "mintops.def"
3405 if (method_entry (context
, frame
,
3409 &ex
, clause_args
)) {
3411 THROW_EX (ex
, NULL
);
3412 EXCEPTION_CHECKPOINT
;
3415 if (clause_args
&& clause_args
->base_frame
)
3416 memcpy (frame
->stack
, clause_args
->base_frame
->stack
, frame
->imethod
->alloca_size
);
3418 INIT_INTERP_STATE (frame
, clause_args
);
3424 if (clause_args
&& clause_args
->filter_exception
) {
3425 sp
->data
.p
= clause_args
->filter_exception
;
3429 #ifdef ENABLE_EXPERIMENT_TIERED
3430 mini_tiered_inc (frame
->imethod
->domain
, frame
->imethod
->method
, &frame
->imethod
->tiered_counter
, 0);
3432 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3434 #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND)
3435 mono_threads_safepoint ();
3438 * using while (ip < end) may result in a 15% performance drop,
3439 * but it may be useful for debug
3444 /* g_assert (sp >= frame->stack); */
3445 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3447 MINT_IN_SWITCH (*ip
) {
3448 MINT_IN_CASE(MINT_INITLOCALS
)
3449 memset (locals
, 0, frame
->imethod
->locals_size
);
3452 MINT_IN_CASE(MINT_NOP
)
3453 MINT_IN_CASE(MINT_NIY
)
3454 g_assert_not_reached ();
3456 MINT_IN_CASE(MINT_BREAK
)
3458 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3460 MINT_IN_CASE(MINT_BREAKPOINT
)
3464 MINT_IN_CASE(MINT_LDNULL
)
3469 MINT_IN_CASE(MINT_ARGLIST
)
3471 *(gpointer
*)sp
->data
.p
= ((gpointer
*)frame
->retval
->data
.p
) [-1];
3472 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3476 MINT_IN_CASE(MINT_VTRESULT
) {
3477 int ret_size
= ip
[1];
3478 unsigned char *ret_vt_sp
= vt_sp
;
3479 vt_sp
-= READ32(ip
+ 2);
3481 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3482 sp
[-1].data
.p
= vt_sp
;
3483 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3488 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3489 MINT_IN_CASE(MINT_LDC_I4_M1
)
3492 MINT_IN_CASE(MINT_LDC_I4_0
)
3495 MINT_IN_CASE(MINT_LDC_I4_1
)
3498 MINT_IN_CASE(MINT_LDC_I4_2
)
3501 MINT_IN_CASE(MINT_LDC_I4_3
)
3504 MINT_IN_CASE(MINT_LDC_I4_4
)
3507 MINT_IN_CASE(MINT_LDC_I4_5
)
3510 MINT_IN_CASE(MINT_LDC_I4_6
)
3513 MINT_IN_CASE(MINT_LDC_I4_7
)
3516 MINT_IN_CASE(MINT_LDC_I4_8
)
3519 MINT_IN_CASE(MINT_LDC_I4_S
)
3520 sp
->data
.i
= (short)ip
[1];
3524 MINT_IN_CASE(MINT_LDC_I4
)
3526 sp
->data
.i
= READ32 (ip
);
3530 MINT_IN_CASE(MINT_LDC_I8
)
3532 sp
->data
.l
= READ64 (ip
);
3536 MINT_IN_CASE(MINT_LDC_I8_S
)
3537 sp
->data
.l
= (short)ip
[1];
3541 MINT_IN_CASE(MINT_LDC_R4
) {
3545 sp
->data
.f_r4
= * (float *)&val
;
3550 MINT_IN_CASE(MINT_LDC_R8
)
3551 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3555 MINT_IN_CASE(MINT_DUP
)
3560 MINT_IN_CASE(MINT_DUP_VT
) {
3561 int const i32
= READ32 (ip
+ 1);
3563 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3564 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3569 MINT_IN_CASE(MINT_POP
) {
3574 MINT_IN_CASE(MINT_POP1
) {
3580 MINT_IN_CASE(MINT_JMP
) {
3581 g_assert (sp
== frame
->stack
);
3582 InterpMethod
*new_method
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3584 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3585 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
3587 if (!new_method
->transformed
) {
3588 error_init_reuse (error
);
3591 mono_interp_transform_method (new_method
, context
, error
);
3592 MonoException
*ex
= mono_error_convert_to_exception (error
);
3597 const gboolean realloc_frame
= new_method
->alloca_size
> frame
->imethod
->alloca_size
;
3598 frame
->imethod
= new_method
;
3600 * We allocate the stack frame from scratch and store the arguments in the
3601 * locals again since it's possible for the caller stack frame to be smaller
3602 * than the callee stack frame (at the interp level)
3604 if (realloc_frame
) {
3605 alloc_stack_data (context
, frame
, frame
->imethod
->alloca_size
);
3606 memset (frame
->stack
, 0, frame
->imethod
->alloca_size
);
3609 vt_sp
= (unsigned char *) sp
+ frame
->imethod
->stack_size
;
3613 locals
= vt_sp
+ frame
->imethod
->vt_stack_size
;
3614 ip
= frame
->imethod
->code
;
3617 MINT_IN_CASE(MINT_CALLI
) {
3618 MonoMethodSignature
*csignature
;
3622 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3626 cmethod
= (InterpMethod
*)sp
->data
.p
;
3627 if (cmethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3628 cmethod
= mono_interp_get_imethod (frame
->imethod
->domain
, mono_marshal_get_native_wrapper (cmethod
->method
, FALSE
, FALSE
), error
);
3629 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3632 is_void
= csignature
->ret
->type
== MONO_TYPE_VOID
;
3633 retval
= is_void
? NULL
: sp
;
3636 /* decrement by the actual number of args */
3637 sp
-= csignature
->param_count
;
3638 if (csignature
->hasthis
)
3641 if (csignature
->hasthis
) {
3642 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3644 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3645 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3646 sp
[0].data
.p
= unboxed
;
3652 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3653 gpointer target_ip
= sp
[-1].data
.p
;
3654 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3655 int opcode
= ip
[2];
3656 gboolean save_last_error
= ip
[3];
3661 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3662 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
3663 CHECK_RESUME_STATE (context
);
3667 MINT_IN_CASE(MINT_CALLI_NAT
) {
3668 MonoMethodSignature
* csignature
;
3672 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3676 guchar
* const code
= (guchar
*)sp
->data
.p
;
3680 /* decrement by the actual number of args */
3681 sp
-= csignature
->param_count
;
3682 if (csignature
->hasthis
)
3685 // FIXME Free this frame earlier?
3686 InterpFrame
* const child_frame
= alloc_frame (context
, &retval
, frame
, NULL
, sp
, retval
);
3688 if (frame
->imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3689 mono_interp_calli_nat_dynamic_pinvoke (child_frame
, code
, context
, csignature
, error
);
3691 const gboolean save_last_error
= ip
[-3 + 2];
3692 ves_pinvoke_method (child_frame
, csignature
, (MonoFuncV
) code
, context
, save_last_error
);
3694 CHECK_RESUME_STATE (context
);
3696 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3702 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3703 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3704 MonoObject
*this_arg
;
3705 is_void
= *ip
== MINT_VCALLVIRT_FAST
;
3710 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3711 slot
= (gint16
)ip
[2];
3715 retval
= is_void
? NULL
: sp
;
3717 /* decrement by the actual number of args */
3718 sp
-= cmethod
->param_count
+ cmethod
->hasthis
;
3720 this_arg
= (MonoObject
*)sp
->data
.p
;
3722 cmethod
= get_virtual_method_fast (cmethod
, this_arg
->vtable
, slot
);
3723 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (cmethod
->method
->klass
)) {
3725 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3726 sp
[0].data
.p
= unboxed
;
3729 InterpMethodCodeType code_type
= cmethod
->code_type
;
3731 g_assert (code_type
== IMETHOD_CODE_UNKNOWN
||
3732 code_type
== IMETHOD_CODE_INTERP
||
3733 code_type
== IMETHOD_CODE_COMPILED
);
3735 if (G_UNLIKELY (code_type
== IMETHOD_CODE_UNKNOWN
)) {
3736 MonoMethodSignature
*sig
= mono_method_signature_internal (cmethod
->method
);
3737 if (mono_interp_jit_call_supported (cmethod
->method
, sig
))
3738 code_type
= IMETHOD_CODE_COMPILED
;
3740 code_type
= IMETHOD_CODE_INTERP
;
3741 cmethod
->code_type
= code_type
;
3744 if (code_type
== IMETHOD_CODE_INTERP
) {
3748 } else if (code_type
== IMETHOD_CODE_COMPILED
) {
3749 error_init_reuse (error
);
3750 do_jit_call (sp
, vt_sp
, context
, frame
, cmethod
, error
);
3751 if (!is_ok (error
)) {
3752 MonoException
*ex
= mono_error_convert_to_exception (error
);
3756 CHECK_RESUME_STATE (context
);
3758 if (cmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3764 MINT_IN_CASE(MINT_CALL_VARARG
) {
3765 MonoMethodSignature
*csig
;
3767 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3769 /* The real signature for vararg calls */
3770 csig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3774 // Retval must be set unconditionally due to MINT_ARGLIST.
3775 // is_void guides exit_frame instead of retval nullness.
3777 is_void
= csig
->ret
->type
== MONO_TYPE_VOID
;
3779 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3780 vt_sp
= copy_varargs_vtstack (csig
, sp
, vt_sp
);
3785 /* decrement by the actual number of args */
3786 // FIXME This seems excessive: frame and csig param_count.
3787 sp
-= cmethod
->param_count
+ cmethod
->hasthis
+ csig
->param_count
- csig
->sentinelpos
;
3791 MINT_IN_CASE(MINT_VCALL
)
3792 MINT_IN_CASE(MINT_CALL
)
3793 MINT_IN_CASE(MINT_CALLVIRT
)
3794 MINT_IN_CASE(MINT_VCALLVIRT
) {
3795 // FIXME CALLVIRT opcodes are not used on netcore. We should kill them.
3796 // FIXME braces from here until call: label.
3797 is_void
= *ip
== MINT_VCALL
|| *ip
== MINT_VCALLVIRT
;
3798 gboolean is_virtual
;
3799 is_virtual
= *ip
== MINT_CALLVIRT
|| *ip
== MINT_VCALLVIRT
;
3801 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3803 retval
= is_void
? NULL
: sp
;
3805 /* decrement by the actual number of args */
3809 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3811 cmethod
= get_virtual_method (cmethod
, this_arg
->vtable
);
3812 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (cmethod
->method
->klass
)) {
3814 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3815 sp
[0].data
.p
= unboxed
;
3820 #ifdef ENABLE_EXPERIMENT_TIERED
3826 // FIXME This assumes a grow-down stack.
3827 gpointer native_stack_addr
= frame
->native_stack_addr
? (gpointer
)((guint8
*)frame
->native_stack_addr
- 1) : (gpointer
)&retval
;
3830 * Make a non-recursive call by loading the new interpreter state based on child frame,
3831 * and going back to the main loop.
3833 SAVE_INTERP_STATE (frame
);
3835 frame
= alloc_frame (context
, native_stack_addr
, frame
, cmethod
, sp
, retval
);
3840 if (method_entry (context
, frame
,
3846 THROW_EX (ex
, NULL
);
3847 EXCEPTION_CHECKPOINT
;
3851 INIT_INTERP_STATE (frame
, clause_args
);
3855 MINT_IN_CASE(MINT_JIT_CALL
) {
3856 InterpMethod
*rmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3857 error_init_reuse (error
);
3859 sp
-= rmethod
->param_count
+ rmethod
->hasthis
;
3860 do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3861 if (!is_ok (error
)) {
3862 MonoException
*ex
= mono_error_convert_to_exception (error
);
3867 CHECK_RESUME_STATE (context
);
3869 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3874 MINT_IN_CASE(MINT_JIT_CALL2
) {
3875 #ifdef ENABLE_EXPERIMENT_TIERED
3876 InterpMethod
*rmethod
= (InterpMethod
*) READ64 (ip
+ 1);
3878 error_init_reuse (error
);
3881 sp
-= rmethod
->param_count
+ rmethod
->hasthis
;
3882 do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3883 if (!is_ok (error
)) {
3884 MonoException
*ex
= mono_error_convert_to_exception (error
);
3889 CHECK_RESUME_STATE (context
);
3891 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3894 g_error ("MINT_JIT_ICALL2 shouldn't be used");
3898 MINT_IN_CASE(MINT_CALLRUN
) {
3899 #ifndef ENABLE_NETCORE
3900 MonoMethod
*target_method
= (MonoMethod
*) frame
->imethod
->data_items
[ip
[1]];
3901 MonoMethodSignature
*sig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3906 sp
-= sig
->param_count
;
3910 MonoException
*ex
= ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3914 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3920 g_assert_not_reached ();
3924 MINT_IN_CASE(MINT_RET
)
3926 *frame
->retval
= *sp
;
3927 if (sp
> frame
->stack
)
3928 g_warning_d ("ret: more values on stack: %d", sp
- frame
->stack
);
3930 MINT_IN_CASE(MINT_RET_VOID
)
3931 if (sp
> frame
->stack
)
3932 g_warning_ds ("ret.void: more values on stack: %d %s", sp
- frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
3934 MINT_IN_CASE(MINT_RET_VT
) {
3935 int const i32
= READ32 (ip
+ 1);
3937 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3938 if (sp
> frame
->stack
)
3939 g_warning_d ("ret.vt: more values on stack: %d", sp
- frame
->stack
);
3943 #ifdef ENABLE_EXPERIMENT_TIERED
3944 #define BACK_BRANCH_PROFILE(offset) do { \
3946 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0); \
3949 #define BACK_BRANCH_PROFILE(offset)
3952 MINT_IN_CASE(MINT_BR_S
) {
3953 short br_offset
= (short) *(ip
+ 1);
3954 BACK_BRANCH_PROFILE (br_offset
);
3958 MINT_IN_CASE(MINT_BR
) {
3959 gint32 br_offset
= (gint32
) READ32(ip
+ 1);
3960 BACK_BRANCH_PROFILE (br_offset
);
3965 #define ZEROP_S(datamem, op) \
3967 if (sp->data.datamem op 0) { \
3968 gint16 br_offset = (gint16) ip [1]; \
3969 BACK_BRANCH_PROFILE (br_offset); \
3974 #define ZEROP(datamem, op) \
3976 if (sp->data.datamem op 0) { \
3977 gint32 br_offset = (gint32)READ32(ip + 1); \
3978 BACK_BRANCH_PROFILE (br_offset); \
3983 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3986 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3989 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3992 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3995 MINT_IN_CASE(MINT_BRFALSE_I4
)
3998 MINT_IN_CASE(MINT_BRFALSE_I8
)
4001 MINT_IN_CASE(MINT_BRFALSE_R4
)
4004 MINT_IN_CASE(MINT_BRFALSE_R8
)
4007 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
4010 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
4013 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
4016 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
4019 MINT_IN_CASE(MINT_BRTRUE_I4
)
4022 MINT_IN_CASE(MINT_BRTRUE_I8
)
4025 MINT_IN_CASE(MINT_BRTRUE_R4
)
4028 MINT_IN_CASE(MINT_BRTRUE_R8
)
4031 #define CONDBR_S(cond) \
4034 gint16 br_offset = (gint16) ip [1]; \
4035 BACK_BRANCH_PROFILE (br_offset); \
4039 #define BRELOP_S(datamem, op) \
4040 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
4042 #define CONDBR(cond) \
4045 gint32 br_offset = (gint32) READ32 (ip + 1); \
4046 BACK_BRANCH_PROFILE (br_offset); \
4051 #define BRELOP(datamem, op) \
4052 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
4054 MINT_IN_CASE(MINT_BEQ_I4_S
)
4057 MINT_IN_CASE(MINT_BEQ_I8_S
)
4060 MINT_IN_CASE(MINT_BEQ_R4_S
)
4061 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
4063 MINT_IN_CASE(MINT_BEQ_R8_S
)
4064 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
4066 MINT_IN_CASE(MINT_BEQ_I4
)
4069 MINT_IN_CASE(MINT_BEQ_I8
)
4072 MINT_IN_CASE(MINT_BEQ_R4
)
4073 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
4075 MINT_IN_CASE(MINT_BEQ_R8
)
4076 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
4078 MINT_IN_CASE(MINT_BGE_I4_S
)
4081 MINT_IN_CASE(MINT_BGE_I8_S
)
4084 MINT_IN_CASE(MINT_BGE_R4_S
)
4085 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4087 MINT_IN_CASE(MINT_BGE_R8_S
)
4088 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
4090 MINT_IN_CASE(MINT_BGE_I4
)
4093 MINT_IN_CASE(MINT_BGE_I8
)
4096 MINT_IN_CASE(MINT_BGE_R4
)
4097 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4099 MINT_IN_CASE(MINT_BGE_R8
)
4100 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
4102 MINT_IN_CASE(MINT_BGT_I4_S
)
4105 MINT_IN_CASE(MINT_BGT_I8_S
)
4108 MINT_IN_CASE(MINT_BGT_R4_S
)
4109 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4111 MINT_IN_CASE(MINT_BGT_R8_S
)
4112 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
4114 MINT_IN_CASE(MINT_BGT_I4
)
4117 MINT_IN_CASE(MINT_BGT_I8
)
4120 MINT_IN_CASE(MINT_BGT_R4
)
4121 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4123 MINT_IN_CASE(MINT_BGT_R8
)
4124 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
4126 MINT_IN_CASE(MINT_BLT_I4_S
)
4129 MINT_IN_CASE(MINT_BLT_I8_S
)
4132 MINT_IN_CASE(MINT_BLT_R4_S
)
4133 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4135 MINT_IN_CASE(MINT_BLT_R8_S
)
4136 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
4138 MINT_IN_CASE(MINT_BLT_I4
)
4141 MINT_IN_CASE(MINT_BLT_I8
)
4144 MINT_IN_CASE(MINT_BLT_R4
)
4145 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4147 MINT_IN_CASE(MINT_BLT_R8
)
4148 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
4150 MINT_IN_CASE(MINT_BLE_I4_S
)
4153 MINT_IN_CASE(MINT_BLE_I8_S
)
4156 MINT_IN_CASE(MINT_BLE_R4_S
)
4157 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4159 MINT_IN_CASE(MINT_BLE_R8_S
)
4160 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
4162 MINT_IN_CASE(MINT_BLE_I4
)
4165 MINT_IN_CASE(MINT_BLE_I8
)
4168 MINT_IN_CASE(MINT_BLE_R4
)
4169 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4171 MINT_IN_CASE(MINT_BLE_R8
)
4172 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
4174 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
4177 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
4180 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
4181 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
4183 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
4184 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
4186 MINT_IN_CASE(MINT_BNE_UN_I4
)
4189 MINT_IN_CASE(MINT_BNE_UN_I8
)
4192 MINT_IN_CASE(MINT_BNE_UN_R4
)
4193 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
4195 MINT_IN_CASE(MINT_BNE_UN_R8
)
4196 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
4199 #define BRELOP_S_CAST(datamem, op, type) \
4201 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4202 gint16 br_offset = (gint16) ip [1]; \
4203 BACK_BRANCH_PROFILE (br_offset); \
4208 #define BRELOP_CAST(datamem, op, type) \
4210 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4211 gint32 br_offset = (gint32) ip [1]; \
4212 BACK_BRANCH_PROFILE (br_offset); \
4217 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
4218 BRELOP_S_CAST(i
, >=, guint32
);
4220 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
4221 BRELOP_S_CAST(l
, >=, guint64
);
4223 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
4224 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4226 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
4227 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4229 MINT_IN_CASE(MINT_BGE_UN_I4
)
4230 BRELOP_CAST(i
, >=, guint32
);
4232 MINT_IN_CASE(MINT_BGE_UN_I8
)
4233 BRELOP_CAST(l
, >=, guint64
);
4235 MINT_IN_CASE(MINT_BGE_UN_R4
)
4236 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4238 MINT_IN_CASE(MINT_BGE_UN_R8
)
4239 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4241 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
4242 BRELOP_S_CAST(i
, >, guint32
);
4244 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
4245 BRELOP_S_CAST(l
, >, guint64
);
4247 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
4248 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4250 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
4251 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4253 MINT_IN_CASE(MINT_BGT_UN_I4
)
4254 BRELOP_CAST(i
, >, guint32
);
4256 MINT_IN_CASE(MINT_BGT_UN_I8
)
4257 BRELOP_CAST(l
, >, guint64
);
4259 MINT_IN_CASE(MINT_BGT_UN_R4
)
4260 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4262 MINT_IN_CASE(MINT_BGT_UN_R8
)
4263 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4265 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
4266 BRELOP_S_CAST(i
, <=, guint32
);
4268 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
4269 BRELOP_S_CAST(l
, <=, guint64
);
4271 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
4272 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4274 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
4275 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4277 MINT_IN_CASE(MINT_BLE_UN_I4
)
4278 BRELOP_CAST(i
, <=, guint32
);
4280 MINT_IN_CASE(MINT_BLE_UN_I8
)
4281 BRELOP_CAST(l
, <=, guint64
);
4283 MINT_IN_CASE(MINT_BLE_UN_R4
)
4284 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4286 MINT_IN_CASE(MINT_BLE_UN_R8
)
4287 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4289 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
4290 BRELOP_S_CAST(i
, <, guint32
);
4292 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
4293 BRELOP_S_CAST(l
, <, guint64
);
4295 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
4296 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4298 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
4299 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4301 MINT_IN_CASE(MINT_BLT_UN_I4
)
4302 BRELOP_CAST(i
, <, guint32
);
4304 MINT_IN_CASE(MINT_BLT_UN_I8
)
4305 BRELOP_CAST(l
, <, guint64
);
4307 MINT_IN_CASE(MINT_BLT_UN_R4
)
4308 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4310 MINT_IN_CASE(MINT_BLT_UN_R8
)
4311 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4313 MINT_IN_CASE(MINT_SWITCH
) {
4315 const unsigned short *st
;
4321 if ((guint32
)sp
->data
.i
< n
) {
4323 ip
+= 2 * (guint32
)sp
->data
.i
;
4324 offset
= READ32 (ip
);
4331 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
4332 NULL_CHECK (sp
[-1].data
.p
);
4334 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
4336 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
4337 NULL_CHECK (sp
[-1].data
.p
);
4339 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
4341 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
4342 NULL_CHECK (sp
[-1].data
.p
);
4344 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
4346 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
4347 NULL_CHECK (sp
[-1].data
.p
);
4349 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
4351 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
4352 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
4353 NULL_CHECK (sp
[-1].data
.p
);
4355 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
4357 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
4358 NULL_CHECK (sp
[-1].data
.p
);
4360 #ifdef NO_UNALIGNED_ACCESS
4361 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4362 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
4365 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
4367 MINT_IN_CASE(MINT_LDIND_I
) {
4368 guint16 offset
= ip
[1];
4369 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
4373 MINT_IN_CASE(MINT_LDIND_I8
) {
4374 guint16 offset
= ip
[1];
4375 #ifdef NO_UNALIGNED_ACCESS
4376 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
4377 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
4380 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
4384 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
4385 NULL_CHECK (sp
[-1].data
.p
);
4387 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
4389 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
4390 NULL_CHECK (sp
[-1].data
.p
);
4392 #ifdef NO_UNALIGNED_ACCESS
4393 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4394 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
4397 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
4399 MINT_IN_CASE(MINT_LDIND_REF
)
4401 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4403 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
4404 NULL_CHECK (sp
[-1].data
.p
);
4406 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4409 MINT_IN_CASE(MINT_STIND_REF
)
4412 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
4414 MINT_IN_CASE(MINT_STIND_I1
)
4417 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
4419 MINT_IN_CASE(MINT_STIND_I2
)
4422 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
4424 MINT_IN_CASE(MINT_STIND_I4
)
4427 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
4429 MINT_IN_CASE(MINT_STIND_I
)
4432 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
4434 MINT_IN_CASE(MINT_STIND_I8
)
4437 #ifdef NO_UNALIGNED_ACCESS
4438 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4439 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
4442 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
4444 MINT_IN_CASE(MINT_STIND_R4
)
4447 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
4449 MINT_IN_CASE(MINT_STIND_R8
)
4452 #ifdef NO_UNALIGNED_ACCESS
4453 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4454 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
4457 * (double *) sp
->data
.p
= sp
[1].data
.f
;
4459 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
4462 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
4464 #define BINOP(datamem, op) \
4466 sp [-1].data.datamem op ## = sp [0].data.datamem; \
4468 MINT_IN_CASE(MINT_ADD_I4
)
4471 MINT_IN_CASE(MINT_ADD_I8
)
4474 MINT_IN_CASE(MINT_ADD_R4
)
4477 MINT_IN_CASE(MINT_ADD_R8
)
4480 MINT_IN_CASE(MINT_ADD1_I4
)
4484 MINT_IN_CASE(MINT_ADD1_I8
)
4488 MINT_IN_CASE(MINT_LOCADD1_I4
)
4489 *(gint32
*)(locals
+ ip
[1]) += 1;
4492 MINT_IN_CASE(MINT_LOCADD1_I8
)
4493 *(gint64
*)(locals
+ ip
[1]) += 1;
4496 MINT_IN_CASE(MINT_SUB_I4
)
4499 MINT_IN_CASE(MINT_SUB_I8
)
4502 MINT_IN_CASE(MINT_SUB_R4
)
4505 MINT_IN_CASE(MINT_SUB_R8
)
4508 MINT_IN_CASE(MINT_SUB1_I4
)
4512 MINT_IN_CASE(MINT_SUB1_I8
)
4516 MINT_IN_CASE(MINT_LOCSUB1_I4
)
4517 *(gint32
*)(locals
+ ip
[1]) -= 1;
4520 MINT_IN_CASE(MINT_LOCSUB1_I8
)
4521 *(gint64
*)(locals
+ ip
[1]) -= 1;
4523 MINT_IN_CASE(MINT_MUL_I4
)
4526 MINT_IN_CASE(MINT_MUL_I8
)
4529 MINT_IN_CASE(MINT_MUL_R4
)
4532 MINT_IN_CASE(MINT_MUL_R8
)
4535 MINT_IN_CASE(MINT_DIV_I4
)
4536 if (sp
[-1].data
.i
== 0)
4537 goto div_zero_label
;
4538 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4539 goto overflow_label
;
4542 MINT_IN_CASE(MINT_DIV_I8
)
4543 if (sp
[-1].data
.l
== 0)
4544 goto div_zero_label
;
4545 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4546 goto overflow_label
;
4549 MINT_IN_CASE(MINT_DIV_R4
)
4552 MINT_IN_CASE(MINT_DIV_R8
)
4556 #define BINOP_CAST(datamem, op, type) \
4558 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4560 MINT_IN_CASE(MINT_DIV_UN_I4
)
4561 if (sp
[-1].data
.i
== 0)
4562 goto div_zero_label
;
4563 BINOP_CAST(i
, /, guint32
);
4565 MINT_IN_CASE(MINT_DIV_UN_I8
)
4566 if (sp
[-1].data
.l
== 0)
4567 goto div_zero_label
;
4568 BINOP_CAST(l
, /, guint64
);
4570 MINT_IN_CASE(MINT_REM_I4
)
4571 if (sp
[-1].data
.i
== 0)
4572 goto div_zero_label
;
4573 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4574 goto overflow_label
;
4577 MINT_IN_CASE(MINT_REM_I8
)
4578 if (sp
[-1].data
.l
== 0)
4579 goto div_zero_label
;
4580 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4581 goto overflow_label
;
4584 MINT_IN_CASE(MINT_REM_R4
)
4585 /* FIXME: what do we actually do here? */
4587 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4590 MINT_IN_CASE(MINT_REM_R8
)
4591 /* FIXME: what do we actually do here? */
4593 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4596 MINT_IN_CASE(MINT_REM_UN_I4
)
4597 if (sp
[-1].data
.i
== 0)
4598 goto div_zero_label
;
4599 BINOP_CAST(i
, %, guint32
);
4601 MINT_IN_CASE(MINT_REM_UN_I8
)
4602 if (sp
[-1].data
.l
== 0)
4603 goto div_zero_label
;
4604 BINOP_CAST(l
, %, guint64
);
4606 MINT_IN_CASE(MINT_AND_I4
)
4609 MINT_IN_CASE(MINT_AND_I8
)
4612 MINT_IN_CASE(MINT_OR_I4
)
4615 MINT_IN_CASE(MINT_OR_I8
)
4618 MINT_IN_CASE(MINT_XOR_I4
)
4621 MINT_IN_CASE(MINT_XOR_I8
)
4625 #define SHIFTOP(datamem, op) \
4627 sp [-1].data.datamem op ## = sp [0].data.i; \
4630 MINT_IN_CASE(MINT_SHL_I4
)
4633 MINT_IN_CASE(MINT_SHL_I8
)
4636 MINT_IN_CASE(MINT_SHR_I4
)
4639 MINT_IN_CASE(MINT_SHR_I8
)
4642 MINT_IN_CASE(MINT_SHR_UN_I4
)
4644 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4647 MINT_IN_CASE(MINT_SHR_UN_I8
)
4649 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4652 MINT_IN_CASE(MINT_NEG_I4
)
4653 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4656 MINT_IN_CASE(MINT_NEG_I8
)
4657 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4660 MINT_IN_CASE(MINT_NEG_R4
)
4661 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4664 MINT_IN_CASE(MINT_NEG_R8
)
4665 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4668 MINT_IN_CASE(MINT_NOT_I4
)
4669 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4672 MINT_IN_CASE(MINT_NOT_I8
)
4673 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4676 MINT_IN_CASE(MINT_CONV_I1_I4
)
4677 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4680 MINT_IN_CASE(MINT_CONV_I1_I8
)
4681 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4684 MINT_IN_CASE(MINT_CONV_I1_R4
)
4685 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4688 MINT_IN_CASE(MINT_CONV_I1_R8
)
4689 /* without gint32 cast, C compiler is allowed to use undefined
4690 * behaviour if data.f is bigger than >255. See conv.fpint section
4692 * > The conversion truncates; that is, the fractional part
4693 * > is discarded. The behavior is undefined if the truncated
4694 * > value cannot be represented in the destination type.
4696 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4699 MINT_IN_CASE(MINT_CONV_U1_I4
)
4700 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4703 MINT_IN_CASE(MINT_CONV_U1_I8
)
4704 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4707 MINT_IN_CASE(MINT_CONV_U1_R4
)
4708 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4711 MINT_IN_CASE(MINT_CONV_U1_R8
)
4712 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4715 MINT_IN_CASE(MINT_CONV_I2_I4
)
4716 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4719 MINT_IN_CASE(MINT_CONV_I2_I8
)
4720 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4723 MINT_IN_CASE(MINT_CONV_I2_R4
)
4724 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4727 MINT_IN_CASE(MINT_CONV_I2_R8
)
4728 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4731 MINT_IN_CASE(MINT_CONV_U2_I4
)
4732 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4735 MINT_IN_CASE(MINT_CONV_U2_I8
)
4736 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4739 MINT_IN_CASE(MINT_CONV_U2_R4
)
4740 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4743 MINT_IN_CASE(MINT_CONV_U2_R8
)
4744 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4747 MINT_IN_CASE(MINT_CONV_I4_R4
)
4748 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4751 MINT_IN_CASE(MINT_CONV_I4_R8
)
4752 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4755 MINT_IN_CASE(MINT_CONV_U4_I8
)
4756 MINT_IN_CASE(MINT_CONV_I4_I8
)
4757 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4760 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4761 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4764 MINT_IN_CASE(MINT_CONV_U4_R4
)
4765 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4766 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4768 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4772 MINT_IN_CASE(MINT_CONV_U4_R8
)
4773 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4774 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
4776 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4780 MINT_IN_CASE(MINT_CONV_I8_I4
)
4781 sp
[-1].data
.l
= sp
[-1].data
.i
;
4784 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4785 sp
[-2].data
.l
= sp
[-2].data
.i
;
4788 MINT_IN_CASE(MINT_CONV_I8_U4
)
4789 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4792 MINT_IN_CASE(MINT_CONV_I8_R4
)
4793 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4796 MINT_IN_CASE(MINT_CONV_I8_R8
)
4797 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4800 MINT_IN_CASE(MINT_CONV_R4_I4
)
4801 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4804 MINT_IN_CASE(MINT_CONV_R4_I8
)
4805 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4808 MINT_IN_CASE(MINT_CONV_R4_R8
)
4809 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4812 MINT_IN_CASE(MINT_CONV_R8_I4
)
4813 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4816 MINT_IN_CASE(MINT_CONV_R8_I8
)
4817 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4820 MINT_IN_CASE(MINT_CONV_R8_R4
)
4821 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4824 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4825 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4828 MINT_IN_CASE(MINT_CONV_U8_R4
)
4829 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4830 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
4832 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4836 MINT_IN_CASE(MINT_CONV_U8_R8
)
4837 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4838 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
4840 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4844 MINT_IN_CASE(MINT_CPOBJ
) {
4845 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4846 g_assert (m_class_is_valuetype (c
));
4847 /* if this assertion fails, we need to add a write barrier */
4848 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4849 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4854 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4855 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
4856 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4861 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4862 int size
= READ32(ip
+ 1);
4864 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4865 sp
[-1].data
.p
= vt_sp
;
4866 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4869 MINT_IN_CASE(MINT_LDSTR
)
4870 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
4874 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4875 MonoString
*s
= NULL
;
4876 guint32 strtoken
= (guint32
)(gsize
)frame
->imethod
->data_items
[ip
[1]];
4878 MonoMethod
*method
= frame
->imethod
->method
;
4879 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4880 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4881 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4882 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4884 g_assert_not_reached ();
4891 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4892 MonoClass
*newobj_class
;
4893 guint32 token
= ip
[1];
4894 guint16 param_count
= ip
[2];
4896 newobj_class
= (MonoClass
*) frame
->imethod
->data_items
[token
];
4899 sp
->data
.o
= ves_array_create (frame
->imethod
->domain
, newobj_class
, param_count
, sp
, error
);
4901 goto throw_error_label
;
4907 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
4908 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[3]];
4909 INIT_VTABLE (vtable
);
4910 MonoObject
*o
; // See the comment about GC safety.
4911 guint16 param_count
;
4912 guint16 imethod_index
= ip
[1];
4914 const gboolean is_inlined
= imethod_index
== INLINED_METHOD_FLAG
;
4916 param_count
= ip
[2];
4918 // Make room for two copies of o -- this parameter and return value.
4919 if (param_count
|| !is_inlined
) {
4921 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
4924 OBJREF (o
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4925 if (G_UNLIKELY (!o
)) {
4926 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4927 goto throw_error_label
;
4930 // Store o next to and before the parameters on the stack so GC will see it,
4931 // and where it is needed when the call returns.
4936 sp
+= param_count
+ 2;
4938 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[imethod_index
];
4946 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4947 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4950 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
4951 guint16
const param_count
= ip
[2];
4953 // Make room for extra parameter and result.
4956 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
4959 gboolean
const vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4961 memset (vt_sp
, 0, ip
[3]);
4963 // Put extra parameter and result on stack, before other parameters,
4964 // and point stack to extra parameter, after result.
4965 // This pattern occurs for newobj_vt_fast and newobj_fast.
4966 sp
[1].data
.p
= vt_sp
;
4967 sp
[0].data
.p
= vt_sp
;
4970 // Like newobj_fast, add valuetype_this parameter
4971 // and result and point stack to this after result.
4972 memset (sp
, 0, sizeof (*sp
));
4973 sp
[1].data
.p
= &sp
[0].data
; // valuetype_this == result
4976 // call_newobj captures the pattern where the return value is placed
4977 // on the stack before the call, instead of the call forming it.
4979 ++sp
; // Point sp at added extra param, after return value.
4984 MINT_IN_CASE(MINT_NEWOBJ
) {
4988 guint32
const token
= ip
[1];
4989 ip
+= 2; // FIXME: Do this after throw?
4991 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
4993 MonoMethodSignature
* const csig
= mono_method_signature_internal (cmethod
->method
);
4995 g_assert (csig
->hasthis
);
4997 // Make room for first parameter and return value.
4998 const int param_count
= csig
->param_count
;
5001 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
5004 InterpMethod
* const imethod
= frame
->imethod
;
5006 MonoClass
* const newobj_class
= cmethod
->method
->klass
;
5008 /*if (profiling_classes) {
5009 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
5011 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
5015 * First arg is the object.
5016 * a constructor returns void, but we need to return the object we created
5018 if (m_class_is_valuetype (newobj_class
)) {
5019 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
5020 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
5021 sp
[0].data
.p
= vt_sp
; // return value
5022 sp
[1].data
.p
= vt_sp
; // first parameter
5024 memset (sp
, 0, sizeof (*sp
));
5025 sp
[1].data
.p
= &sp
[0].data
; // first parameter is return value
5028 if (newobj_class
!= mono_defaults
.string_class
) {
5029 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
5030 if (!is_ok (error
) || !mono_runtime_class_init_full (vtable
, error
)) {
5031 MonoException
*exc
= mono_error_convert_to_exception (error
);
5035 error_init_reuse (error
);
5036 MonoObject
* o
= NULL
; // See the comment about GC safety.
5037 OBJREF (o
) = mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
5038 mono_error_cleanup (error
); // FIXME: do not swallow the error
5039 error_init_reuse (error
);
5040 EXCEPTION_CHECKPOINT
;
5041 sp
[0].data
.o
= o
; // return value
5042 sp
[1].data
.o
= o
; // first parameter
5043 #ifndef DISABLE_REMOTING
5044 if (mono_object_is_transparent_proxy (o
)) {
5045 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (cmethod
->method
, error
);
5046 mono_error_assert_ok (error
);
5047 cmethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
5048 mono_error_assert_ok (error
);
5054 sp
->data
.p
= NULL
; // first parameter
5061 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
5067 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
5068 MonoMethodSignature
*csig
;
5075 InterpMethod
*cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
5076 csig
= mono_method_signature_internal (cmethod
->method
);
5078 g_assert (csig
->hasthis
);
5079 sp
-= csig
->param_count
;
5081 gpointer arg0
= sp
[0].data
.p
;
5083 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
5084 *byreference_this
= arg0
;
5086 /* Followed by a VTRESULT opcode which will push the result on the stack */
5090 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
5091 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
5092 sp
[-1].data
.p
= *byreference_this
;
5096 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
5098 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
5103 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
5105 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
5110 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
5111 MonoObject
*obj
= sp
[-1].data
.o
;
5112 sp
[-1].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
5116 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
5117 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
5118 MonoObject
* const o
= sp
[-1].data
.o
;
5120 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5122 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
5124 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
5126 isinst
= mono_interp_isinst (o
, c
); // FIXME: do not swallow the error
5132 gboolean
const isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
5134 sp
[-1].data
.p
= NULL
;
5136 goto invalid_cast_label
;
5142 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
5143 MINT_IN_CASE(MINT_ISINST_COMMON
) {
5144 MonoObject
* const o
= sp
[-1].data
.o
;
5146 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5147 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
5150 gboolean
const isinst_instr
= *ip
== MINT_ISINST_COMMON
;
5152 sp
[-1].data
.p
= NULL
;
5154 goto invalid_cast_label
;
5160 MINT_IN_CASE(MINT_CASTCLASS
)
5161 MINT_IN_CASE(MINT_ISINST
) {
5162 MonoObject
* const o
= sp
[-1].data
.o
;
5164 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5165 if (!mono_interp_isinst (o
, c
)) { // FIXME: do not swallow the error
5166 gboolean
const isinst_instr
= *ip
== MINT_ISINST
;
5168 sp
[-1].data
.p
= NULL
;
5170 goto invalid_cast_label
;
5176 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
5177 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
5180 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
5181 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
5184 MINT_IN_CASE(MINT_UNBOX
) {
5185 MonoObject
* const o
= sp
[-1].data
.o
;
5187 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5189 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
5190 goto invalid_cast_label
;
5192 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
5196 MINT_IN_CASE(MINT_THROW
)
5199 sp
->data
.p
= mono_get_exception_null_reference ();
5201 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
5203 MINT_IN_CASE(MINT_CHECKPOINT
)
5204 /* Do synchronous checking of abort requests */
5205 EXCEPTION_CHECKPOINT
;
5208 MINT_IN_CASE(MINT_SAFEPOINT
)
5209 /* Do synchronous checking of abort requests */
5210 EXCEPTION_CHECKPOINT
;
5211 /* Poll safepoint */
5212 mono_threads_safepoint ();
5215 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
) {
5216 sp
[-1].data
.p
= (char*)sp
[-1].data
.o
+ ip
[1];
5220 MINT_IN_CASE(MINT_LDFLDA
) {
5221 MonoObject
* const o
= sp
[-1].data
.o
;
5223 sp
[-1].data
.p
= (char *)o
+ ip
[1];
5227 MINT_IN_CASE(MINT_CKNULL_N
) {
5228 /* Same as CKNULL, but further down the stack */
5229 int const n
= ip
[1];
5230 MonoObject
* const o
= sp
[-n
].data
.o
;
5236 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5237 MonoObject* const o = sp [-1].data.o; \
5240 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
5242 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
5246 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
5248 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
5249 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
5250 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
5251 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
5252 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
5253 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
5254 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
5255 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
5256 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
5257 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
5258 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5259 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5261 MINT_IN_CASE(MINT_LDFLD_VT
) {
5262 MonoObject
* const o
= sp
[-1].data
.o
;
5265 int size
= READ32(ip
+ 2);
5266 sp
[-1].data
.p
= vt_sp
;
5267 memcpy (sp
[-1].data
.p
, (char *)o
+ ip
[1], size
);
5268 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5273 MINT_IN_CASE(MINT_LDRMFLD
) {
5274 MonoObject
* const o
= sp
[-1].data
.o
;
5276 mono_interp_load_remote_field (frame
->imethod
, o
, ip
, sp
);
5280 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
5281 MonoObject
* const o
= sp
[-1].data
.o
;
5283 vt_sp
= mono_interp_load_remote_field_vt (frame
->imethod
, o
, ip
, sp
, vt_sp
);
5289 #define LDARGFLD(datamem, fieldtype) do { \
5290 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5292 sp [0].data.datamem = *(fieldtype *)((char *)o + ip [2]) ; \
5296 MINT_IN_CASE(MINT_LDARGFLD_I1
) LDARGFLD(i
, gint8
); MINT_IN_BREAK
;
5297 MINT_IN_CASE(MINT_LDARGFLD_U1
) LDARGFLD(i
, guint8
); MINT_IN_BREAK
;
5298 MINT_IN_CASE(MINT_LDARGFLD_I2
) LDARGFLD(i
, gint16
); MINT_IN_BREAK
;
5299 MINT_IN_CASE(MINT_LDARGFLD_U2
) LDARGFLD(i
, guint16
); MINT_IN_BREAK
;
5300 MINT_IN_CASE(MINT_LDARGFLD_I4
) LDARGFLD(i
, gint32
); MINT_IN_BREAK
;
5301 MINT_IN_CASE(MINT_LDARGFLD_I8
) LDARGFLD(l
, gint64
); MINT_IN_BREAK
;
5302 MINT_IN_CASE(MINT_LDARGFLD_R4
) LDARGFLD(f_r4
, float); MINT_IN_BREAK
;
5303 MINT_IN_CASE(MINT_LDARGFLD_R8
) LDARGFLD(f
, double); MINT_IN_BREAK
;
5304 MINT_IN_CASE(MINT_LDARGFLD_O
) LDARGFLD(p
, gpointer
); MINT_IN_BREAK
;
5305 MINT_IN_CASE(MINT_LDARGFLD_P
) LDARGFLD(p
, gpointer
); MINT_IN_BREAK
;
5307 #define LDLOCFLD(datamem, fieldtype) do { \
5308 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5310 sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \
5314 MINT_IN_CASE(MINT_LDLOCFLD_I1
) LDLOCFLD(i
, gint8
); MINT_IN_BREAK
;
5315 MINT_IN_CASE(MINT_LDLOCFLD_U1
) LDLOCFLD(i
, guint8
); MINT_IN_BREAK
;
5316 MINT_IN_CASE(MINT_LDLOCFLD_I2
) LDLOCFLD(i
, gint16
); MINT_IN_BREAK
;
5317 MINT_IN_CASE(MINT_LDLOCFLD_U2
) LDLOCFLD(i
, guint16
); MINT_IN_BREAK
;
5318 MINT_IN_CASE(MINT_LDLOCFLD_I4
) LDLOCFLD(i
, gint32
); MINT_IN_BREAK
;
5319 MINT_IN_CASE(MINT_LDLOCFLD_I8
) LDLOCFLD(l
, gint64
); MINT_IN_BREAK
;
5320 MINT_IN_CASE(MINT_LDLOCFLD_R4
) LDLOCFLD(f_r4
, float); MINT_IN_BREAK
;
5321 MINT_IN_CASE(MINT_LDLOCFLD_R8
) LDLOCFLD(f
, double); MINT_IN_BREAK
;
5322 MINT_IN_CASE(MINT_LDLOCFLD_O
) LDLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5323 MINT_IN_CASE(MINT_LDLOCFLD_P
) LDLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5325 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5326 MonoObject* const o = sp [-2].data.o; \
5330 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
5332 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
5336 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5338 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
5339 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
5340 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
5341 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
5342 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
5343 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
5344 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
5345 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
5346 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
5347 MINT_IN_CASE(MINT_STFLD_O
) {
5348 MonoObject
* const o
= sp
[-2].data
.o
;
5351 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[1], sp
[1].data
.o
);
5355 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5356 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5358 MINT_IN_CASE(MINT_STFLD_VT
) {
5359 MonoObject
* const o
= sp
[-2].data
.o
;
5363 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[2]];
5364 int const i32
= mono_class_value_size (klass
, NULL
);
5366 guint16 offset
= ip
[1];
5367 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
5369 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5373 MINT_IN_CASE(MINT_STRMFLD
) {
5374 MonoClassField
*field
;
5376 MonoObject
* const o
= sp
[-2].data
.o
;
5379 field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5382 #ifndef DISABLE_REMOTING
5383 if (mono_object_is_transparent_proxy (o
)) {
5384 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
5385 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
5386 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
5389 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
5394 MINT_IN_CASE(MINT_STRMFLD_VT
)
5396 NULL_CHECK (sp
[-2].data
.o
);
5397 vt_sp
-= mono_interp_store_remote_field_vt (frame
, ip
, sp
, error
);
5402 #define STARGFLD(datamem, fieldtype) do { \
5403 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5406 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5409 MINT_IN_CASE(MINT_STARGFLD_I1
) STARGFLD(i
, gint8
); MINT_IN_BREAK
;
5410 MINT_IN_CASE(MINT_STARGFLD_U1
) STARGFLD(i
, guint8
); MINT_IN_BREAK
;
5411 MINT_IN_CASE(MINT_STARGFLD_I2
) STARGFLD(i
, gint16
); MINT_IN_BREAK
;
5412 MINT_IN_CASE(MINT_STARGFLD_U2
) STARGFLD(i
, guint16
); MINT_IN_BREAK
;
5413 MINT_IN_CASE(MINT_STARGFLD_I4
) STARGFLD(i
, gint32
); MINT_IN_BREAK
;
5414 MINT_IN_CASE(MINT_STARGFLD_I8
) STARGFLD(l
, gint64
); MINT_IN_BREAK
;
5415 MINT_IN_CASE(MINT_STARGFLD_R4
) STARGFLD(f_r4
, float); MINT_IN_BREAK
;
5416 MINT_IN_CASE(MINT_STARGFLD_R8
) STARGFLD(f
, double); MINT_IN_BREAK
;
5417 MINT_IN_CASE(MINT_STARGFLD_P
) STARGFLD(p
, gpointer
); MINT_IN_BREAK
;
5418 MINT_IN_CASE(MINT_STARGFLD_O
) {
5419 MonoObject
*o
= frame
->stack_args
[ip
[1]].data
.o
;
5422 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[2], sp
[0].data
.o
);
5427 #define STLOCFLD(datamem, fieldtype) do { \
5428 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5431 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5434 MINT_IN_CASE(MINT_STLOCFLD_I1
) STLOCFLD(i
, gint8
); MINT_IN_BREAK
;
5435 MINT_IN_CASE(MINT_STLOCFLD_U1
) STLOCFLD(i
, guint8
); MINT_IN_BREAK
;
5436 MINT_IN_CASE(MINT_STLOCFLD_I2
) STLOCFLD(i
, gint16
); MINT_IN_BREAK
;
5437 MINT_IN_CASE(MINT_STLOCFLD_U2
) STLOCFLD(i
, guint16
); MINT_IN_BREAK
;
5438 MINT_IN_CASE(MINT_STLOCFLD_I4
) STLOCFLD(i
, gint32
); MINT_IN_BREAK
;
5439 MINT_IN_CASE(MINT_STLOCFLD_I8
) STLOCFLD(l
, gint64
); MINT_IN_BREAK
;
5440 MINT_IN_CASE(MINT_STLOCFLD_R4
) STLOCFLD(f_r4
, float); MINT_IN_BREAK
;
5441 MINT_IN_CASE(MINT_STLOCFLD_R8
) STLOCFLD(f
, double); MINT_IN_BREAK
;
5442 MINT_IN_CASE(MINT_STLOCFLD_P
) STLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5443 MINT_IN_CASE(MINT_STLOCFLD_O
) {
5444 MonoObject
*o
= *(MonoObject
**)(locals
+ ip
[1]);
5447 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[2], sp
[0].data
.o
);
5452 MINT_IN_CASE(MINT_LDSFLDA
) {
5453 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5454 INIT_VTABLE (vtable
);
5455 sp
->data
.p
= frame
->imethod
->data_items
[ip
[2]];
5461 MINT_IN_CASE(MINT_LDSSFLDA
) {
5462 guint32 offset
= READ32(ip
+ 1);
5463 sp
->data
.p
= mono_get_special_static_data (offset
);
5469 /* We init class here to preserve cctor order */
5470 #define LDSFLD(datamem, fieldtype) { \
5471 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5472 INIT_VTABLE (vtable); \
5473 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5478 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
5479 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
5480 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
5481 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
5482 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
5483 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
5484 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
5485 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
5486 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5487 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5489 MINT_IN_CASE(MINT_LDSFLD_VT
) {
5490 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5491 INIT_VTABLE (vtable
);
5494 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5495 int const i32
= READ32 (ip
+ 3);
5496 memcpy (vt_sp
, addr
, i32
);
5497 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5503 #define LDTSFLD(datamem, fieldtype) { \
5504 MonoInternalThread *thread = mono_thread_internal_current (); \
5505 guint32 offset = READ32 (ip + 1); \
5506 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5507 sp[0].data.datamem = *(fieldtype*)addr; \
5511 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
5512 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
5513 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
5514 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
5515 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
5516 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
5517 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
5518 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
5519 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5520 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5522 MINT_IN_CASE(MINT_LDSSFLD
) {
5523 guint32 offset
= READ32(ip
+ 2);
5524 gpointer addr
= mono_get_special_static_data (offset
);
5525 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5526 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
5531 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
5532 guint32 offset
= READ32(ip
+ 1);
5533 gpointer addr
= mono_get_special_static_data (offset
);
5535 int size
= READ32 (ip
+ 3);
5536 memcpy (vt_sp
, addr
, size
);
5538 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5543 #define STSFLD(datamem, fieldtype) { \
5544 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5545 INIT_VTABLE (vtable); \
5547 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5551 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5552 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5553 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5554 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5555 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5556 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5557 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5558 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5559 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5560 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5562 MINT_IN_CASE(MINT_STSFLD_VT
) {
5563 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5564 INIT_VTABLE (vtable
);
5565 int const i32
= READ32 (ip
+ 3);
5566 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5568 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5569 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5575 #define STTSFLD(datamem, fieldtype) { \
5576 MonoInternalThread *thread = mono_thread_internal_current (); \
5577 guint32 offset = READ32 (ip + 1); \
5578 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5580 *(fieldtype*)addr = sp[0].data.datamem; \
5584 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5585 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5586 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5587 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5588 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5589 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5590 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5591 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5592 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5593 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5595 MINT_IN_CASE(MINT_STSSFLD
) {
5596 guint32 offset
= READ32(ip
+ 2);
5597 gpointer addr
= mono_get_special_static_data (offset
);
5598 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5600 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5604 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5605 guint32 offset
= READ32(ip
+ 1);
5606 gpointer addr
= mono_get_special_static_data (offset
);
5608 int size
= READ32 (ip
+ 3);
5609 memcpy (addr
, sp
->data
.vt
, size
);
5610 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5615 MINT_IN_CASE(MINT_STOBJ_VT
) {
5617 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5619 size
= mono_class_value_size (c
, NULL
);
5620 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5621 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5625 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5626 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5627 goto overflow_label
;
5628 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5631 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5632 if (sp
[-1].data
.i
< 0)
5633 goto overflow_label
;
5634 sp
[-1].data
.l
= sp
[-1].data
.i
;
5637 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5638 if (sp
[-1].data
.l
< 0)
5639 goto overflow_label
;
5642 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5643 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5644 goto overflow_label
;
5647 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5648 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5649 goto overflow_label
;
5650 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5653 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5654 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5655 goto overflow_label
;
5656 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5659 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5660 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5661 goto overflow_label
;
5662 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5665 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
)
5666 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5667 goto overflow_label
;
5668 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5671 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5672 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5673 goto overflow_label
;
5674 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5677 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5678 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5679 goto overflow_label
;
5680 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5683 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5684 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5685 goto overflow_label
;
5686 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5689 MINT_IN_CASE(MINT_BOX
) {
5690 mono_interp_box (frame
, ip
, sp
);
5694 MINT_IN_CASE(MINT_BOX_VT
) {
5695 vt_sp
-= mono_interp_box_vt (frame
, ip
, sp
);
5699 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5700 vt_sp
-= mono_interp_box_nullable (frame
, ip
, sp
, error
);
5704 MINT_IN_CASE(MINT_NEWARR
) {
5705 MonoVTable
*vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
5706 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5707 if (!is_ok (error
)) {
5708 goto throw_error_label
;
5711 /*if (profiling_classes) {
5712 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5714 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5719 MINT_IN_CASE(MINT_LDLEN
) {
5720 MonoObject
* const o
= sp
[-1].data
.o
;
5722 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5726 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5727 MonoObject
* const o
= sp
[-1].data
.o
;
5729 gsize offset_length
= (gsize
)(gint16
)ip
[1];
5730 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5734 MINT_IN_CASE(MINT_GETCHR
) {
5736 s
= (MonoString
*)sp
[-2].data
.p
;
5738 int const i32
= sp
[-1].data
.i
;
5739 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5740 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5742 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5746 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5747 guint8
* const span
= (guint8
*) sp
[-2].data
.p
;
5748 const int index
= sp
[-1].data
.i
;
5753 const gsize offset_length
= (gsize
)(gint16
)ip
[2];
5755 const gint32 length
= *(gint32
*) (span
+ offset_length
);
5756 if (index
< 0 || index
>= length
)
5757 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5759 const gsize element_size
= (gsize
)(gint16
)ip
[1];
5760 const gsize offset_pointer
= (gsize
)(gint16
)ip
[3];
5762 const gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5763 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5768 MINT_IN_CASE(MINT_STRLEN
) {
5770 MonoObject
* const o
= sp
[-1].data
.o
;
5772 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5775 MINT_IN_CASE(MINT_ARRAY_RANK
) {
5776 MonoObject
* const o
= sp
[-1].data
.o
;
5778 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (o
));
5782 MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE
) {
5783 MonoObject
* const o
= sp
[-1].data
.o
;
5785 sp
[-1].data
.i
= mono_array_element_size (mono_object_class (o
));
5789 MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE
) {
5790 MonoObject
* const o
= sp
[-1].data
.o
;
5792 sp
[-1].data
.i
= m_class_is_primitive (m_class_get_element_class (mono_object_class (o
)));
5796 MINT_IN_CASE(MINT_LDELEMA1
) {
5797 /* No bounds, one direction */
5798 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
5800 gint32
const index
= sp
[-1].data
.i
;
5801 if (index
>= ao
->max_length
)
5802 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5803 gint32
const size
= READ32 (ip
+ 1);
5804 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
5810 MINT_IN_CASE(MINT_LDELEMA
) {
5811 guint16 rank
= ip
[1];
5812 gint32
const esize
= READ32 (ip
+ 2);
5816 MonoArray
* const ao
= (MonoArray
*) sp
[-1].data
.o
;
5819 g_assert (ao
->bounds
);
5821 for (int i
= 0; i
< rank
; i
++) {
5822 guint32 idx
= sp
[i
].data
.i
;
5823 guint32 lower
= ao
->bounds
[i
].lower_bound
;
5824 guint32 len
= ao
->bounds
[i
].length
;
5825 if (idx
< lower
|| (idx
- lower
) >= len
)
5826 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5827 pos
= (pos
* len
) + idx
- lower
;
5830 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
5833 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5834 guint16 rank
= ip
[1];
5838 MonoObject
* const o
= sp
[-1].data
.o
;
5841 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[-3 + 2]];
5842 const gboolean needs_typecheck
= ip
[-3] == MINT_LDELEMA_TC
;
5843 MonoException
*ex
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, sp
, needs_typecheck
);
5849 #define LDELEM(datamem,elemtype) do { \
5851 MonoArray *o = (MonoArray*)sp [-1].data.p; \
5853 gint32 aindex = sp [0].data.i; \
5854 if (aindex >= mono_array_length_internal (o)) \
5855 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5856 sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \
5859 MINT_IN_CASE(MINT_LDELEM_I1
) LDELEM(i
, gint8
); MINT_IN_BREAK
;
5860 MINT_IN_CASE(MINT_LDELEM_U1
) LDELEM(i
, guint8
); MINT_IN_BREAK
;
5861 MINT_IN_CASE(MINT_LDELEM_I2
) LDELEM(i
, gint16
); MINT_IN_BREAK
;
5862 MINT_IN_CASE(MINT_LDELEM_U2
) LDELEM(i
, guint16
); MINT_IN_BREAK
;
5863 MINT_IN_CASE(MINT_LDELEM_I4
) LDELEM(i
, gint32
); MINT_IN_BREAK
;
5864 MINT_IN_CASE(MINT_LDELEM_U4
) LDELEM(i
, guint32
); MINT_IN_BREAK
;
5865 MINT_IN_CASE(MINT_LDELEM_I8
) LDELEM(l
, guint64
); MINT_IN_BREAK
;
5866 MINT_IN_CASE(MINT_LDELEM_I
) LDELEM(nati
, mono_i
); MINT_IN_BREAK
;
5867 MINT_IN_CASE(MINT_LDELEM_R4
) LDELEM(f_r4
, float); MINT_IN_BREAK
;
5868 MINT_IN_CASE(MINT_LDELEM_R8
) LDELEM(f
, double); MINT_IN_BREAK
;
5869 MINT_IN_CASE(MINT_LDELEM_REF
) LDELEM(p
, gpointer
); MINT_IN_BREAK
;
5870 MINT_IN_CASE(MINT_LDELEM_VT
) {
5872 MonoArray
*o
= (MonoArray
*)sp
[-1].data
.p
;
5874 mono_u aindex
= sp
[0].data
.i
;
5875 if (aindex
>= mono_array_length_internal (o
))
5876 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5878 int i32
= READ32 (ip
+ 1);
5879 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5880 sp
[-1].data
.vt
= vt_sp
;
5881 // Copying to vtstack. No wbarrier needed
5882 memcpy (sp
[-1].data
.vt
, src_addr
, i32
);
5883 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5888 #define STELEM_PROLOG(o, aindex) do { \
5890 o = (MonoArray*)sp [0].data.p; \
5892 aindex = sp [1].data.i; \
5893 if (aindex >= mono_array_length_internal (o)) \
5894 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5897 #define STELEM(datamem,elemtype) do { \
5900 STELEM_PROLOG(o, aindex); \
5901 mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \
5904 MINT_IN_CASE(MINT_STELEM_I1
) STELEM(i
, gint8
); MINT_IN_BREAK
;
5905 MINT_IN_CASE(MINT_STELEM_U1
) STELEM(i
, guint8
); MINT_IN_BREAK
;
5906 MINT_IN_CASE(MINT_STELEM_I2
) STELEM(i
, gint16
); MINT_IN_BREAK
;
5907 MINT_IN_CASE(MINT_STELEM_U2
) STELEM(i
, guint16
); MINT_IN_BREAK
;
5908 MINT_IN_CASE(MINT_STELEM_I4
) STELEM(i
, gint32
); MINT_IN_BREAK
;
5909 MINT_IN_CASE(MINT_STELEM_I8
) STELEM(l
, gint64
); MINT_IN_BREAK
;
5910 MINT_IN_CASE(MINT_STELEM_I
) STELEM(nati
, mono_i
); MINT_IN_BREAK
;
5911 MINT_IN_CASE(MINT_STELEM_R4
) STELEM(f_r4
, float); MINT_IN_BREAK
;
5912 MINT_IN_CASE(MINT_STELEM_R8
) STELEM(f
, double); MINT_IN_BREAK
;
5913 MINT_IN_CASE(MINT_STELEM_REF
) {
5916 STELEM_PROLOG(o
, aindex
);
5918 if (sp
[2].data
.o
) {
5919 gboolean isinst
= mono_interp_isinst (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)));
5921 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5923 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5928 MINT_IN_CASE(MINT_STELEM_VT
) {
5931 STELEM_PROLOG(o
, aindex
);
5933 MonoClass
*klass_vt
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5934 int const i32
= READ32 (ip
+ 2);
5935 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5937 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5938 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5942 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5943 if (sp
[-1].data
.i
< 0)
5944 goto overflow_label
;
5947 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5948 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5949 goto overflow_label
;
5950 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5953 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5954 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5955 goto overflow_label
;
5956 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5959 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5960 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
|| isnan (sp
[-1].data
.f_r4
))
5961 goto overflow_label
;
5962 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5965 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5966 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
|| isnan (sp
[-1].data
.f
))
5967 goto overflow_label
;
5968 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5971 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5972 if (sp
[-1].data
.i
< 0)
5973 goto overflow_label
;
5976 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5977 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5978 goto overflow_label
;
5979 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5982 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5983 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
|| isnan (sp
[-1].data
.f_r4
))
5984 goto overflow_label
;
5985 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5988 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5989 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
|| isnan (sp
[-1].data
.f
))
5990 goto overflow_label
;
5991 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5994 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5995 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5996 goto overflow_label
;
5999 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
6000 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
6001 goto overflow_label
;
6004 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
6005 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
6006 goto overflow_label
;
6007 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
6010 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
6011 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
6012 goto overflow_label
;
6013 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
6016 MINT_IN_CASE(MINT_CONV_OVF_I2_R4
)
6017 if (sp
[-1].data
.f_r4
< G_MININT16
|| sp
[-1].data
.f_r4
> G_MAXINT16
|| isnan (sp
[-1].data
.f_r4
))
6018 goto overflow_label
;
6019 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f_r4
;
6022 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
6023 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
|| isnan (sp
[-1].data
.f
))
6024 goto overflow_label
;
6025 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
6028 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4
)
6029 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT16
|| isnan (sp
[-1].data
.f_r4
))
6030 goto overflow_label
;
6031 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f_r4
;
6034 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
6035 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
|| isnan (sp
[-1].data
.f
))
6036 goto overflow_label
;
6037 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
6040 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
6041 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
6042 goto overflow_label
;
6045 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
6046 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
6047 goto overflow_label
;
6048 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
6051 MINT_IN_CASE(MINT_CONV_OVF_U2_R4
)
6052 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT16
|| isnan (sp
[-1].data
.f_r4
))
6053 goto overflow_label
;
6054 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f_r4
;
6057 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
6058 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
|| isnan (sp
[-1].data
.f
))
6059 goto overflow_label
;
6060 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
6063 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
6064 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
6065 goto overflow_label
;
6068 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
6069 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
6070 goto overflow_label
;
6073 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
6074 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
6075 goto overflow_label
;
6076 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
6079 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
6080 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
6081 goto overflow_label
;
6082 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
6085 MINT_IN_CASE(MINT_CONV_OVF_I1_R4
)
6086 if (sp
[-1].data
.f_r4
< G_MININT8
|| sp
[-1].data
.f_r4
> G_MAXINT8
|| isnan (sp
[-1].data
.f_r4
))
6087 goto overflow_label
;
6088 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f_r4
;
6091 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
6092 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
|| isnan (sp
[-1].data
.f
))
6093 goto overflow_label
;
6094 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
6097 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4
)
6098 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT8
|| isnan (sp
[-1].data
.f_r4
))
6099 goto overflow_label
;
6100 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f_r4
;
6103 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
6104 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
|| isnan (sp
[-1].data
.f
))
6105 goto overflow_label
;
6106 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
6109 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
6110 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
6111 goto overflow_label
;
6114 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
6115 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
6116 goto overflow_label
;
6117 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
6120 MINT_IN_CASE(MINT_CONV_OVF_U1_R4
)
6121 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT8
|| isnan (sp
[-1].data
.f_r4
))
6122 goto overflow_label
;
6123 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f_r4
;
6126 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
6127 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
|| isnan (sp
[-1].data
.f
))
6128 goto overflow_label
;
6129 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
6132 MINT_IN_CASE(MINT_CKFINITE
)
6133 if (!mono_isfinite (sp
[-1].data
.f
))
6134 THROW_EX (mono_get_exception_arithmetic (), ip
);
6137 MINT_IN_CASE(MINT_MKREFANY
) {
6138 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6140 /* The value address is on the stack */
6141 gpointer addr
= sp
[-1].data
.p
;
6142 /* Push the typedref value on the stack */
6143 sp
[-1].data
.p
= vt_sp
;
6144 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6146 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6148 tref
->type
= m_class_get_byval_arg (c
);
6154 MINT_IN_CASE(MINT_REFANYTYPE
) {
6155 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6156 MonoType
*type
= tref
->type
;
6158 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6159 sp
[-1].data
.p
= vt_sp
;
6161 *(gpointer
*)sp
[-1].data
.p
= type
;
6165 MINT_IN_CASE(MINT_REFANYVAL
) {
6166 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6167 gpointer addr
= tref
->value
;
6169 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6170 if (c
!= tref
->klass
)
6171 goto invalid_cast_label
;
6173 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6175 sp
[-1].data
.p
= addr
;
6179 MINT_IN_CASE(MINT_LDTOKEN
)
6182 * (gpointer
*)sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6186 MINT_IN_CASE(MINT_ADD_OVF_I4
)
6187 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6188 goto overflow_label
;
6191 MINT_IN_CASE(MINT_ADD_OVF_I8
)
6192 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6193 goto overflow_label
;
6196 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
6197 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6198 goto overflow_label
;
6199 BINOP_CAST(i
, +, guint32
);
6201 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
6202 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6203 goto overflow_label
;
6204 BINOP_CAST(l
, +, guint64
);
6206 MINT_IN_CASE(MINT_MUL_OVF_I4
)
6207 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6208 goto overflow_label
;
6211 MINT_IN_CASE(MINT_MUL_OVF_I8
)
6212 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6213 goto overflow_label
;
6216 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
6217 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6218 goto overflow_label
;
6219 BINOP_CAST(i
, *, guint32
);
6221 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
6222 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6223 goto overflow_label
;
6224 BINOP_CAST(l
, *, guint64
);
6226 MINT_IN_CASE(MINT_SUB_OVF_I4
)
6227 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6228 goto overflow_label
;
6231 MINT_IN_CASE(MINT_SUB_OVF_I8
)
6232 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6233 goto overflow_label
;
6236 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
6237 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6238 goto overflow_label
;
6239 BINOP_CAST(i
, -, guint32
);
6241 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
6242 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6243 goto overflow_label
;
6244 BINOP_CAST(l
, -, guint64
);
6246 MINT_IN_CASE(MINT_START_ABORT_PROT
)
6247 mono_threads_begin_abort_protected_block ();
6250 MINT_IN_CASE(MINT_ENDFINALLY
) {
6251 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
6254 // After mono_threads_end_abort_protected_block to conserve stack.
6255 const int clause_index
= *ip
;
6257 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
6260 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
6261 g_assert (sp
>= frame
->stack
);
6266 ip
= (const guint16
*)finally_ips
->data
;
6267 finally_ips
= g_slist_remove (finally_ips
, ip
);
6268 /* Throw abort after the last finally block to avoid confusing EH */
6269 if (pending_abort
&& !finally_ips
)
6270 EXCEPTION_CHECKPOINT
;
6271 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6272 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6279 MINT_IN_CASE(MINT_LEAVE
)
6280 MINT_IN_CASE(MINT_LEAVE_S
)
6281 MINT_IN_CASE(MINT_LEAVE_CHECK
)
6282 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
6284 // Leave is split into pieces in order to consume less stack,
6285 // but not have to change how exception handling macros access labels and locals.
6287 g_assert (sp
>= frame
->stack
);
6288 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
6293 gboolean
const check
= opcode
== MINT_LEAVE_CHECK
|| opcode
== MINT_LEAVE_S_CHECK
;
6295 if (check
&& frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
6296 // FIXME Free this frame earlier?
6297 InterpFrame
* const child_frame
= alloc_frame (context
, &dummy
, frame
, NULL
, NULL
, NULL
);
6298 MonoException
*abort_exc
= mono_interp_leave (child_frame
);
6300 THROW_EX (abort_exc
, frame
->ip
);
6303 opcode
= *ip
; // Refetch to avoid register/stack pressure.
6304 gboolean
const short_offset
= opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
;
6305 ip
+= short_offset
? (short)*(ip
+ 1) : (gint32
)READ32 (ip
+ 1);
6306 const guint16
*endfinally_ip
= ip
;
6307 GSList
*old_list
= finally_ips
;
6308 MonoMethod
*method
= frame
->imethod
->method
;
6311 g_print ("* Handle finally IL_%04x\n", endfinally_ip
- frame
->imethod
->code
);
6313 // FIXME Null check for frame->imethod follows deref.
6314 if (frame
->imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
6315 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))
6317 guint32
const ip_offset
= frame
->ip
- frame
->imethod
->code
;
6319 finally_ips
= g_slist_prepend (finally_ips
, (void *)endfinally_ip
);
6321 for (int i
= frame
->imethod
->num_clauses
- 1; i
>= 0; i
--) {
6322 MonoExceptionClause
* const clause
= &frame
->imethod
->clauses
[i
];
6323 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- frame
->imethod
->code
))) {
6324 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6325 ip
= frame
->imethod
->code
+ clause
->handler_offset
;
6326 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
6329 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, context
->has_resume_state
? "yes": "no");
6335 if (old_list
!= finally_ips
&& finally_ips
) {
6336 ip
= (const guint16
*)finally_ips
->data
;
6337 finally_ips
= g_slist_remove (finally_ips
, ip
);
6338 // we set vt_sp later here so we relieve stack pressure
6339 vt_sp
= (unsigned char*)sp
+ frame
->imethod
->stack_size
;
6340 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6341 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6348 MINT_IN_CASE(MINT_ICALL_V_V
)
6349 MINT_IN_CASE(MINT_ICALL_V_P
)
6350 MINT_IN_CASE(MINT_ICALL_P_V
)
6351 MINT_IN_CASE(MINT_ICALL_P_P
)
6352 MINT_IN_CASE(MINT_ICALL_PP_V
)
6353 MINT_IN_CASE(MINT_ICALL_PP_P
)
6354 MINT_IN_CASE(MINT_ICALL_PPP_V
)
6355 MINT_IN_CASE(MINT_ICALL_PPP_P
)
6356 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
6357 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
6358 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
6359 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
6360 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
6361 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
6363 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, frame
->imethod
->data_items
[ip
[1]], FALSE
);
6364 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
6365 CHECK_RESUME_STATE (context
);
6368 MINT_IN_CASE(MINT_MONO_LDPTR
)
6369 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6373 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
6374 sp
->data
.o
= mono_interp_new (frame
->imethod
->domain
, (MonoClass
*)frame
->imethod
->data_items
[ip
[1]]); // FIXME: do not swallow the error
6378 MINT_IN_CASE(MINT_MONO_RETOBJ
)
6381 stackval_from_data (mono_method_signature_internal (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
6382 mono_method_signature_internal (frame
->imethod
->method
)->pinvoke
);
6383 if (sp
> frame
->stack
)
6384 g_warning_d ("retobj: more values on stack: %d", sp
- frame
->stack
);
6386 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
6387 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
6391 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
6393 mono_memory_barrier ();
6396 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
6397 sp
->data
.p
= mono_domain_get ();
6401 MINT_IN_CASE(MINT_MONO_GET_SP
)
6402 sp
->data
.p
= &frame
;
6406 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
6407 if (G_UNLIKELY (ss_enabled
)) {
6408 typedef void (*T
) (void);
6412 void *tramp
= mini_get_single_step_trampoline ();
6413 mono_memory_barrier ();
6414 ss_tramp
= (T
)tramp
;
6418 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6419 * the address of that instruction is stored as the seq point address.
6424 * Use the same trampoline as the JIT. This ensures that
6425 * the debugger has the context for the last interpreter
6428 do_debugger_tramp (ss_tramp
, frame
);
6430 CHECK_RESUME_STATE (context
);
6434 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
6435 /* Just a placeholder for a breakpoint */
6438 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
6439 typedef void (*T
) (void);
6442 void *tramp
= mini_get_breakpoint_trampoline ();
6443 mono_memory_barrier ();
6444 bp_tramp
= (T
)tramp
;
6449 /* Use the same trampoline as the JIT */
6450 do_debugger_tramp (bp_tramp
, frame
);
6452 CHECK_RESUME_STATE (context
);
6458 #define RELOP(datamem, op) \
6460 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6463 #define RELOP_FP(datamem, op, noorder) \
6465 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6466 sp [-1].data.i = noorder; \
6468 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6471 MINT_IN_CASE(MINT_CEQ_I4
)
6474 MINT_IN_CASE(MINT_CEQ0_I4
)
6475 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
6478 MINT_IN_CASE(MINT_CEQ_I8
)
6481 MINT_IN_CASE(MINT_CEQ_R4
)
6482 RELOP_FP(f_r4
, ==, 0);
6484 MINT_IN_CASE(MINT_CEQ_R8
)
6487 MINT_IN_CASE(MINT_CNE_I4
)
6490 MINT_IN_CASE(MINT_CNE_I8
)
6493 MINT_IN_CASE(MINT_CNE_R4
)
6494 RELOP_FP(f_r4
, !=, 1);
6496 MINT_IN_CASE(MINT_CNE_R8
)
6499 MINT_IN_CASE(MINT_CGT_I4
)
6502 MINT_IN_CASE(MINT_CGT_I8
)
6505 MINT_IN_CASE(MINT_CGT_R4
)
6506 RELOP_FP(f_r4
, >, 0);
6508 MINT_IN_CASE(MINT_CGT_R8
)
6511 MINT_IN_CASE(MINT_CGE_I4
)
6514 MINT_IN_CASE(MINT_CGE_I8
)
6517 MINT_IN_CASE(MINT_CGE_R4
)
6518 RELOP_FP(f_r4
, >=, 0);
6520 MINT_IN_CASE(MINT_CGE_R8
)
6524 #define RELOP_CAST(datamem, op, type) \
6526 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6529 MINT_IN_CASE(MINT_CGE_UN_I4
)
6530 RELOP_CAST(l
, >=, guint32
);
6532 MINT_IN_CASE(MINT_CGE_UN_I8
)
6533 RELOP_CAST(l
, >=, guint64
);
6536 MINT_IN_CASE(MINT_CGT_UN_I4
)
6537 RELOP_CAST(i
, >, guint32
);
6539 MINT_IN_CASE(MINT_CGT_UN_I8
)
6540 RELOP_CAST(l
, >, guint64
);
6542 MINT_IN_CASE(MINT_CGT_UN_R4
)
6543 RELOP_FP(f_r4
, >, 1);
6545 MINT_IN_CASE(MINT_CGT_UN_R8
)
6548 MINT_IN_CASE(MINT_CLT_I4
)
6551 MINT_IN_CASE(MINT_CLT_I8
)
6554 MINT_IN_CASE(MINT_CLT_R4
)
6555 RELOP_FP(f_r4
, <, 0);
6557 MINT_IN_CASE(MINT_CLT_R8
)
6560 MINT_IN_CASE(MINT_CLT_UN_I4
)
6561 RELOP_CAST(i
, <, guint32
);
6563 MINT_IN_CASE(MINT_CLT_UN_I8
)
6564 RELOP_CAST(l
, <, guint64
);
6566 MINT_IN_CASE(MINT_CLT_UN_R4
)
6567 RELOP_FP(f_r4
, <, 1);
6569 MINT_IN_CASE(MINT_CLT_UN_R8
)
6572 MINT_IN_CASE(MINT_CLE_I4
)
6575 MINT_IN_CASE(MINT_CLE_I8
)
6578 MINT_IN_CASE(MINT_CLE_UN_I4
)
6579 RELOP_CAST(l
, <=, guint32
);
6581 MINT_IN_CASE(MINT_CLE_UN_I8
)
6582 RELOP_CAST(l
, <=, guint64
);
6584 MINT_IN_CASE(MINT_CLE_R4
)
6585 RELOP_FP(f_r4
, <=, 0);
6587 MINT_IN_CASE(MINT_CLE_R8
)
6595 MINT_IN_CASE(MINT_LDFTN
) {
6596 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6601 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6602 InterpMethod
*m
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
6604 NULL_CHECK (sp
->data
.p
);
6606 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6611 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6612 error_init_reuse (error
);
6613 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6614 mono_error_assert_ok (error
);
6620 #define LDARG(datamem, argtype) \
6621 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6625 #define LDARGn(datamem, argtype, n) \
6626 sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \
6630 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
6631 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
6632 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
6633 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
6634 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
6635 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
6636 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
6637 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
6638 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6639 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6641 MINT_IN_CASE(MINT_LDARG_P0
) LDARGn(p
, gpointer
, 0); MINT_IN_BREAK
;
6643 MINT_IN_CASE(MINT_LDARG_VT
) {
6645 int const i32
= READ32 (ip
+ 2);
6646 memcpy(sp
->data
.p
, frame
->stack_args
[ip
[1]].data
.p
, i32
);
6647 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6653 #define STARG(datamem, argtype) \
6655 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6658 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
6659 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
6660 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
6661 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
6662 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
6663 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
6664 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6665 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6666 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6667 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6669 MINT_IN_CASE(MINT_STARG_VT
) {
6670 int const i32
= READ32 (ip
+ 2);
6672 memcpy(frame
->stack_args
[ip
[1]].data
.p
, sp
->data
.p
, i32
);
6673 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6678 MINT_IN_CASE(MINT_PROF_ENTER
) {
6679 guint16 flag
= ip
[1];
6682 if ((flag
& TRACING_FLAG
) || ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
) &&
6683 (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
))) {
6684 MonoProfilerCallContext
*prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6685 prof_ctx
->interp_frame
= frame
;
6686 prof_ctx
->method
= frame
->imethod
->method
;
6687 if (flag
& TRACING_FLAG
)
6688 mono_trace_enter_method (frame
->imethod
->method
, frame
->imethod
->jinfo
, prof_ctx
);
6689 if (flag
& PROFILING_FLAG
)
6690 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
6692 } else if ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
)) {
6693 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, NULL
));
6698 MINT_IN_CASE(MINT_PROF_EXIT
)
6699 MINT_IN_CASE(MINT_PROF_EXIT_VOID
) {
6700 guint16 flag
= ip
[1];
6702 int const i32
= READ32 (ip
+ 2);
6706 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6709 *frame
->retval
= *sp
;
6712 if ((flag
& TRACING_FLAG
) || ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_leave
) &&
6713 (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
))) {
6714 MonoProfilerCallContext
*prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6715 prof_ctx
->interp_frame
= frame
;
6716 prof_ctx
->method
= frame
->imethod
->method
;
6719 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6721 prof_ctx
->return_value
= frame
->retval
;
6723 if (flag
& TRACING_FLAG
)
6724 mono_trace_leave_method (frame
->imethod
->method
, frame
->imethod
->jinfo
, prof_ctx
);
6725 if (flag
& PROFILING_FLAG
)
6726 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
6728 } else if ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
)) {
6729 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, NULL
));
6736 MINT_IN_CASE(MINT_LDARGA
)
6737 sp
->data
.p
= &frame
->stack_args
[ip
[1]];
6742 MINT_IN_CASE(MINT_LDARGA_VT
)
6743 sp
->data
.p
= frame
->stack_args
[ip
[1]].data
.p
;
6748 #define LDLOC(datamem, argtype) \
6749 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6753 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6754 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6755 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6756 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6757 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6758 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6759 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6760 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6761 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6762 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6764 MINT_IN_CASE(MINT_LDLOC_VT
) {
6766 int const i32
= READ32 (ip
+ 2);
6767 memcpy(sp
->data
.p
, locals
+ ip
[1], i32
);
6768 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6773 MINT_IN_CASE(MINT_LDLOCA_S
)
6774 sp
->data
.p
= locals
+ ip
[1];
6779 #define STLOC(datamem, argtype) \
6781 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6784 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6785 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6786 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6787 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6788 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6789 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6790 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6791 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6792 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6793 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6795 #define STLOC_NP(datamem, argtype) \
6796 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6799 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6800 MINT_IN_CASE(MINT_STLOC_NP_I8
) STLOC_NP(l
, gint64
); MINT_IN_BREAK
;
6801 MINT_IN_CASE(MINT_STLOC_NP_R4
) STLOC_NP(f_r4
, float); MINT_IN_BREAK
;
6802 MINT_IN_CASE(MINT_STLOC_NP_R8
) STLOC_NP(f
, double); MINT_IN_BREAK
;
6803 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6805 MINT_IN_CASE(MINT_STLOC_VT
) {
6806 int const i32
= READ32 (ip
+ 2);
6808 memcpy(locals
+ ip
[1], sp
->data
.p
, i32
);
6809 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6814 #define MOVLOC(argtype) \
6815 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6818 MINT_IN_CASE(MINT_MOVLOC_1
) MOVLOC(guint8
); MINT_IN_BREAK
;
6819 MINT_IN_CASE(MINT_MOVLOC_2
) MOVLOC(guint16
); MINT_IN_BREAK
;
6820 MINT_IN_CASE(MINT_MOVLOC_4
) MOVLOC(guint32
); MINT_IN_BREAK
;
6821 MINT_IN_CASE(MINT_MOVLOC_8
) MOVLOC(guint64
); MINT_IN_BREAK
;
6823 MINT_IN_CASE(MINT_MOVLOC_VT
) {
6824 int const i32
= READ32(ip
+ 3);
6825 memcpy (locals
+ ip
[2], locals
+ ip
[1], i32
);
6830 MINT_IN_CASE(MINT_LOCALLOC
) {
6831 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6834 int len
= sp
[-1].data
.i
;
6835 //sp [-1].data.p = alloca (len);
6836 sp
[-1].data
.p
= alloc_extra_stack_data (context
, ALIGN_TO (len
, 8));
6838 if (frame
->imethod
->init_locals
)
6839 memset (sp
[-1].data
.p
, 0, len
);
6843 MINT_IN_CASE(MINT_ENDFILTER
)
6844 /* top of stack is result of filter */
6845 frame
->retval
->data
.i
= sp
[-1].data
.i
;
6847 MINT_IN_CASE(MINT_INITOBJ
)
6849 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6852 MINT_IN_CASE(MINT_CPBLK
)
6854 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6855 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6857 /* FIXME: value and size may be int64... */
6858 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6861 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6863 /* FIXME: implement */
6865 token
= READ32 (ip
);
6870 MINT_IN_CASE(MINT_INITBLK
)
6872 NULL_CHECK (sp
[0].data
.p
);
6874 /* FIXME: value and size may be int64... */
6875 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6878 MINT_IN_CASE(MINT_NO_
)
6879 /* FIXME: implement */
6883 MINT_IN_CASE(MINT_RETHROW
) {
6884 int exvar_offset
= ip
[1];
6885 THROW_EX_GENERAL (*(MonoException
**)(frame_locals (frame
) + exvar_offset
), ip
, TRUE
);
6888 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6890 * need to clarify what this should actually do:
6892 * Takes an exception from the stack and rethrows it.
6893 * This is useful for wrappers that don't want to have to
6894 * use CEE_THROW and lose the exception stacktrace.
6899 sp
->data
.p
= mono_get_exception_null_reference ();
6901 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6904 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6908 del
= (MonoDelegate
*)sp
->data
.p
;
6909 if (!del
->interp_method
) {
6910 /* Not created from interpreted code */
6911 error_init_reuse (error
);
6912 g_assert (del
->method
);
6913 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6914 mono_error_assert_ok (error
);
6916 g_assert (del
->interp_method
);
6917 sp
->data
.p
= del
->interp_method
;
6922 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6925 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6926 if (!del
->interp_invoke_impl
) {
6928 * First time we are called. Set up the invoke wrapper. We might be able to do this
6929 * in ctor but we would need to handle AllocDelegateLike_internal separately
6931 error_init_reuse (error
);
6932 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6933 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6934 mono_error_assert_ok (error
);
6937 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6942 #define MATH_UNOP(mathfunc) \
6943 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6946 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
6947 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
6948 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
6949 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
6950 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
6951 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
6952 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
6953 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
6954 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
6955 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
6956 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
6957 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
6958 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
6959 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
6960 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
6962 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
6963 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6964 mono_interp_enum_hasflag (sp
, klass
);
6969 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
6970 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
6974 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
6975 NULL_CHECK (sp
[-1].data
.p
);
6976 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
6981 #if !USE_COMPUTED_GOTO
6983 g_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname (*ip
), ip
- frame
->imethod
->code
);
6988 g_assert_not_reached ();
6991 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6993 THROW_EX (mono_get_exception_null_reference (), ip
);
6995 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
6997 THROW_EX (mono_get_exception_overflow (), ip
);
6999 THROW_EX (mono_error_convert_to_exception (error
), ip
);
7001 THROW_EX (mono_get_exception_invalid_cast (), ip
);
7003 g_assert (context
->has_resume_state
);
7004 g_assert (frame
->imethod
);
7006 if (frame
== context
->handler_frame
&& (!clause_args
|| context
->handler_ip
< clause_args
->end_at_ip
)) {
7007 /* Set the current execution state to the resume state in context */
7009 ip
= context
->handler_ip
;
7010 /* spec says stack should be empty at endfinally so it should be at the start too */
7012 vt_sp
= (guchar
*)sp
+ frame
->imethod
->stack_size
;
7013 g_assert (context
->exc_gchandle
);
7014 sp
->data
.p
= mono_gchandle_get_target_internal (context
->exc_gchandle
);
7017 finally_ips
= clear_resume_state (context
, finally_ips
);
7018 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
7019 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
7024 error_init_reuse (error
);
7026 g_assert (frame
->imethod
);
7028 if (clause_args
&& clause_args
->base_frame
) {
7029 // We finished executing a filter. The execution stack of the base frame
7030 // should remain unmodified, but we need to update the local space.
7031 char *locals_base
= (char*)clause_args
->base_frame
->stack
+ frame
->imethod
->stack_size
+ frame
->imethod
->vt_stack_size
;
7033 memcpy (locals_base
, locals
, frame
->imethod
->locals_size
);
7036 if (!clause_args
&& frame
->parent
&& frame
->parent
->state
.ip
) {
7037 /* Return to the main loop after a non-recursive interpreter call */
7038 //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);
7039 stackval
*retval
= frame
->retval
;
7041 InterpFrame
* const child_frame
= frame
;
7043 frame
= frame
->parent
;
7044 LOAD_INTERP_STATE (frame
);
7046 pop_frame (context
, child_frame
);
7048 CHECK_RESUME_STATE (context
);
7058 pop_frame (context
, frame
);
7064 interp_parse_options (const char *options
)
7071 args
= g_strsplit (options
, ",", -1);
7072 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
7075 if (strncmp (arg
, "jit=", 4) == 0)
7076 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
7077 else if (strncmp (arg
, "interp-only=", strlen ("interp-only=")) == 0)
7078 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
7079 else if (strncmp (arg
, "-inline", 7) == 0)
7080 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
7081 else if (strncmp (arg
, "-cprop", 6) == 0)
7082 mono_interp_opt
&= ~INTERP_OPT_CPROP
;
7083 else if (strncmp (arg
, "-super", 6) == 0)
7084 mono_interp_opt
&= ~INTERP_OPT_SUPER_INSTRUCTIONS
;
7085 else if (strncmp (arg
, "-all", 4) == 0)
7086 mono_interp_opt
= INTERP_OPT_NONE
;
7091 * interp_set_resume_state:
7093 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
7096 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoObject
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
7098 ThreadContext
*context
;
7101 context
= (ThreadContext
*)jit_tls
->interp_context
;
7104 context
->has_resume_state
= TRUE
;
7105 context
->handler_frame
= (InterpFrame
*)interp_frame
;
7106 context
->handler_ei
= ei
;
7107 if (context
->exc_gchandle
)
7108 mono_gchandle_free_internal (context
->exc_gchandle
);
7109 context
->exc_gchandle
= mono_gchandle_new_internal ((MonoObject
*)ex
, FALSE
);
7112 *(MonoObject
**)(frame_locals (context
->handler_frame
) + ei
->exvar_offset
) = ex
;
7113 context
->handler_ip
= (const guint16
*)handler_ip
;
7117 interp_get_resume_state (const MonoJitTlsData
*jit_tls
, gboolean
*has_resume_state
, MonoInterpFrameHandle
*interp_frame
, gpointer
*handler_ip
)
7120 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
7122 *has_resume_state
= context
? context
->has_resume_state
: FALSE
;
7123 if (!*has_resume_state
)
7126 *interp_frame
= context
->handler_frame
;
7127 *handler_ip
= (gpointer
)context
->handler_ip
;
7131 * interp_run_finally:
7133 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
7134 * frame->interp_frame.
7135 * Return TRUE if the finally clause threw an exception.
7138 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
7140 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
7141 ThreadContext
*context
= get_context ();
7142 const unsigned short *old_ip
= iframe
->ip
;
7143 FrameClauseArgs clause_args
;
7144 const guint16
*saved_ip
;
7146 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
7147 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
7148 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
7149 clause_args
.exit_clause
= clause_index
;
7151 saved_ip
= iframe
->state
.ip
;
7152 iframe
->state
.ip
= NULL
;
7155 interp_exec_method_full (iframe
, context
, &clause_args
, error
);
7156 iframe
->state
.ip
= saved_ip
;
7157 iframe
->state
.clause_args
= NULL
;
7158 if (context
->has_resume_state
) {
7161 iframe
->ip
= old_ip
;
7167 * interp_run_filter:
7169 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
7170 * frame->interp_frame.
7173 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
7175 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
7176 ThreadContext
*context
= get_context ();
7177 InterpFrame
*child_frame
;
7179 FrameClauseArgs clause_args
;
7182 * Have to run the clause in a new frame which is a copy of IFRAME, since
7183 * during debugging, there are two copies of the frame on the stack.
7185 child_frame
= alloc_frame (context
, &retval
, iframe
, iframe
->imethod
, iframe
->stack_args
, &retval
);
7187 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
7188 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
7189 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
7190 clause_args
.filter_exception
= ex
;
7191 clause_args
.base_frame
= iframe
;
7194 interp_exec_method_full (child_frame
, context
, &clause_args
, error
);
7195 /* ENDFILTER stores the result into child_frame->retval */
7196 return retval
.data
.i
? TRUE
: FALSE
;
7200 InterpFrame
*current
;
7204 * interp_frame_iter_init:
7206 * Initialize an iterator for iterating through interpreted frames.
7209 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
7211 StackIter
*stack_iter
= (StackIter
*)iter
;
7213 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
7217 * interp_frame_iter_next:
7219 * Fill out FRAME with date for the next interpreter frame.
7222 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
7224 StackIter
*stack_iter
= (StackIter
*)iter
;
7225 InterpFrame
*iframe
= stack_iter
->current
;
7227 memset (frame
, 0, sizeof (StackFrameInfo
));
7228 /* pinvoke frames doesn't have imethod set */
7229 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
7230 iframe
= iframe
->parent
;
7234 MonoMethod
*method
= iframe
->imethod
->method
;
7235 frame
->domain
= iframe
->imethod
->domain
;
7236 frame
->interp_frame
= iframe
;
7237 frame
->method
= method
;
7238 frame
->actual_method
= method
;
7239 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
7240 frame
->native_offset
= -1;
7241 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
7243 frame
->type
= FRAME_TYPE_INTERP
;
7244 /* This is the offset in the interpreter IR */
7245 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
7246 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
7247 frame
->managed
= TRUE
;
7249 frame
->ji
= iframe
->imethod
->jinfo
;
7250 frame
->frame_addr
= iframe
->native_stack_addr
;
7252 stack_iter
->current
= iframe
->parent
;
7258 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
7260 InterpMethod
* imethod
;
7262 imethod
= lookup_imethod (domain
, method
);
7264 return imethod
->jinfo
;
7270 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
7272 guint16
*code
= (guint16
*)ip
;
7273 g_assert (*code
== MINT_SDB_SEQ_POINT
);
7274 *code
= MINT_SDB_BREAKPOINT
;
7278 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
7280 guint16
*code
= (guint16
*)ip
;
7281 g_assert (*code
== MINT_SDB_BREAKPOINT
);
7282 *code
= MINT_SDB_SEQ_POINT
;
7286 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
7288 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7290 g_assert (iframe
->imethod
);
7291 return iframe
->imethod
->jinfo
;
7295 interp_frame_get_ip (MonoInterpFrameHandle frame
)
7297 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7299 g_assert (iframe
->imethod
);
7300 return (gpointer
)iframe
->ip
;
7304 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
7306 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7307 MonoMethodSignature
*sig
;
7309 g_assert (iframe
->imethod
);
7311 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
7312 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
7316 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
7318 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7320 g_assert (iframe
->imethod
);
7322 return frame_locals (iframe
) + iframe
->imethod
->local_offsets
[pos
];
7326 interp_frame_get_this (MonoInterpFrameHandle frame
)
7328 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7330 g_assert (iframe
->imethod
);
7331 g_assert (iframe
->imethod
->hasthis
);
7332 return &iframe
->stack_args
[0].data
.p
;
7335 static MonoInterpFrameHandle
7336 interp_frame_get_parent (MonoInterpFrameHandle frame
)
7338 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7340 return iframe
->parent
;
7344 interp_frame_get_res (MonoInterpFrameHandle frame
)
7346 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7347 MonoMethodSignature
*sig
;
7349 g_assert (iframe
->imethod
);
7350 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
7351 if (sig
->ret
->type
== MONO_TYPE_VOID
)
7354 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
7358 interp_frame_get_native_stack_addr (MonoInterpFrameHandle frame
)
7360 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7362 return iframe
->native_stack_addr
;
7366 interp_start_single_stepping (void)
7372 interp_stop_single_stepping (void)
7378 * interp_mark_stack:
7380 * Mark the interpreter stack frames for a thread.
7384 interp_mark_stack (gpointer thread_data
, GcScanFunc func
, gpointer gc_data
, gboolean precise
)
7386 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread_data
;
7388 if (!mono_use_interpreter
)
7394 * We explicitly mark the frames instead of registering the stack fragments as GC roots, so
7395 * we have to process less data and avoid false pinning from data which is above 'pos'.
7397 * The stack frame handling code uses compiler write barriers only, but the calling code
7398 * in sgen-mono.c already did a mono_memory_barrier_process_wide () so we can
7399 * process these data structures normally.
7401 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)info
->tls
[TLS_KEY_JIT_TLS
];
7405 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
7406 if (!context
|| !context
->data_stack
.inited
)
7409 StackFragment
*frag
;
7410 for (frag
= context
->data_stack
.first
; frag
; frag
= frag
->next
) {
7411 // FIXME: Scan the whole area with 1 call
7412 for (gpointer
*p
= (gpointer
*)&frag
->data
; p
< (gpointer
*)frag
->pos
; ++p
)
7414 if (frag
== context
->data_stack
.current
)
7422 opcode_count_comparer (const void * pa
, const void * pb
)
7424 long counta
= opcode_counts
[*(int*)pa
];
7425 long countb
= opcode_counts
[*(int*)pb
];
7427 if (counta
< countb
)
7429 else if (counta
> countb
)
7436 interp_print_op_count (void)
7438 int ordered_ops
[MINT_LASTOP
];
7442 for (i
= 0; i
< MINT_LASTOP
; i
++) {
7443 ordered_ops
[i
] = i
;
7444 total_ops
+= opcode_counts
[i
];
7446 qsort (ordered_ops
, MINT_LASTOP
, sizeof (int), opcode_count_comparer
);
7448 for (i
= 0; i
< MINT_LASTOP
; i
++) {
7449 long count
= opcode_counts
[ordered_ops
[i
]];
7450 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops
[i
]), count
, (double)count
/ total_ops
* 100);
7456 interp_set_optimizations (guint32 opts
)
7458 mono_interp_opt
= opts
;
7462 invalidate_transform (gpointer imethod_
)
7464 InterpMethod
*imethod
= (InterpMethod
*) imethod_
;
7465 imethod
->transformed
= FALSE
;
7469 interp_invalidate_transformed (MonoDomain
*domain
)
7471 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
7472 mono_domain_jit_code_hash_lock (domain
);
7473 mono_internal_hash_table_apply (&info
->interp_code_hash
, invalidate_transform
);
7474 mono_domain_jit_code_hash_unlock (domain
);
7478 interp_cleanup (void)
7481 interp_print_op_count ();
7486 register_interp_stats (void)
7488 mono_counters_init ();
7489 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
7490 mono_counters_register ("Methods transformed", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
, &mono_interp_stats
.methods_transformed
);
7491 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.cprop_time
);
7492 mono_counters_register ("Total super instructions time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.super_instructions_time
);
7493 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.stloc_nps
);
7494 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.movlocs
);
7495 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.copy_propagations
);
7496 mono_counters_register ("Added pop count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.added_pop_count
);
7497 mono_counters_register ("Constant folds", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.constant_folds
);
7498 mono_counters_register ("Super instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.super_instructions
);
7499 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.killed_instructions
);
7500 mono_counters_register ("Emitted instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.emitted_instructions
);
7501 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
7502 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
7505 #undef MONO_EE_CALLBACK
7506 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
7508 static const MonoEECallbacks mono_interp_callbacks
= {
7513 mono_ee_interp_init (const char *opts
)
7515 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
7516 g_assert (!interp_init_done
);
7517 interp_init_done
= TRUE
;
7519 mono_native_tls_alloc (&thread_context_id
, NULL
);
7522 interp_parse_options (opts
);
7523 /* Don't do any optimizations if running under debugger */
7524 if (mini_get_debug_options ()->mdb_optimizations
)
7525 mono_interp_opt
= 0;
7526 mono_interp_transform_init ();
7528 mini_install_interp_callbacks (&mono_interp_callbacks
);
7530 register_interp_stats ();