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"
66 #include "interp-intrins.h"
68 #include <mono/mini/mini.h>
69 #include <mono/mini/mini-runtime.h>
70 #include <mono/mini/aot-runtime.h>
71 #include <mono/mini/llvm-runtime.h>
72 #include <mono/mini/llvmonly-runtime.h>
73 #include <mono/mini/jit-icalls.h>
74 #include <mono/mini/debugger-agent.h>
75 #include <mono/mini/ee.h>
76 #include <mono/mini/trace.h>
79 #include <mono/mini/mini-arm.h>
81 #include <mono/metadata/icall-decl.h>
83 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
84 struct FrameClauseArgs
{
85 /* Where we start the frame execution from */
86 const guint16
*start_with_ip
;
88 * End ip of the exit_clause. We need it so we know whether the resume
89 * state is for this frame (which is called from EH) or for the original
90 * frame further down the stack.
92 const guint16
*end_at_ip
;
93 /* When exiting this clause we also exit the frame */
95 /* Exception that we are filtering */
96 MonoException
*filter_exception
;
97 /* Frame that is executing this clause */
98 InterpFrame
*exec_frame
;
102 * This code synchronizes with interp_mark_stack () using compiler memory barriers.
105 static FrameDataFragment
*
106 frame_data_frag_new (int size
)
108 FrameDataFragment
*frag
= (FrameDataFragment
*)g_malloc (size
);
110 frag
->pos
= (guint8
*)&frag
->data
;
111 frag
->end
= (guint8
*)frag
+ size
;
117 frame_data_frag_free (FrameDataFragment
*frag
)
120 FrameDataFragment
*next
= frag
->next
;
127 frame_data_allocator_init (FrameDataAllocator
*stack
, int size
)
129 FrameDataFragment
*frag
;
131 frag
= frame_data_frag_new (size
);
132 stack
->first
= stack
->current
= frag
;
133 stack
->infos_capacity
= 4;
134 stack
->infos
= g_malloc (stack
->infos_capacity
* sizeof (FrameDataInfo
));
138 frame_data_allocator_free (FrameDataAllocator
*stack
)
140 /* Assert to catch leaks */
141 g_assert_checked (stack
->current
== stack
->first
&& stack
->current
->pos
== (guint8
*)&stack
->current
->data
);
142 frame_data_frag_free (stack
->first
);
145 static FrameDataFragment
*
146 frame_data_allocator_add_frag (FrameDataAllocator
*stack
, int size
)
148 FrameDataFragment
*new_frag
;
151 int frag_size
= 4096;
152 if (size
+ sizeof (FrameDataFragment
) > frag_size
)
153 frag_size
= size
+ sizeof (FrameDataFragment
);
154 new_frag
= frame_data_frag_new (frag_size
);
155 mono_compiler_barrier ();
156 stack
->current
->next
= new_frag
;
157 stack
->current
= new_frag
;
162 frame_data_allocator_alloc (FrameDataAllocator
*stack
, InterpFrame
*frame
, int size
)
164 FrameDataFragment
*current
= stack
->current
;
167 int infos_len
= stack
->infos_len
;
169 if (!infos_len
|| (infos_len
> 0 && stack
->infos
[infos_len
- 1].frame
!= frame
)) {
170 /* First allocation by this frame. Save the markers for restore */
171 if (infos_len
== stack
->infos_capacity
) {
172 stack
->infos_capacity
= infos_len
* 2;
173 stack
->infos
= g_realloc (stack
->infos
, stack
->infos_capacity
* sizeof (FrameDataInfo
));
175 stack
->infos
[infos_len
].frame
= frame
;
176 stack
->infos
[infos_len
].frag
= current
;
177 stack
->infos
[infos_len
].pos
= current
->pos
;
181 if (G_LIKELY (current
->pos
+ size
<= current
->end
)) {
183 current
->pos
+= size
;
185 if (current
->next
&& current
->next
->pos
+ size
<= current
->next
->end
) {
186 current
= stack
->current
= current
->next
;
187 current
->pos
= (guint8
*)¤t
->data
;
189 FrameDataFragment
*tmp
= current
->next
;
190 /* avoid linking to be freed fragments, so the GC can't trip over it */
191 current
->next
= NULL
;
192 mono_compiler_barrier ();
193 frame_data_frag_free (tmp
);
195 current
= frame_data_allocator_add_frag (stack
, size
);
197 g_assert (current
->pos
+ size
<= current
->end
);
198 res
= (gpointer
)current
->pos
;
199 current
->pos
+= size
;
201 mono_compiler_barrier ();
206 frame_data_allocator_pop (FrameDataAllocator
*stack
, InterpFrame
*frame
)
208 int infos_len
= stack
->infos_len
;
210 if (infos_len
> 0 && stack
->infos
[infos_len
- 1].frame
== frame
) {
212 stack
->current
= stack
->infos
[infos_len
].frag
;
213 stack
->current
->pos
= stack
->infos
[infos_len
].pos
;
214 stack
->infos_len
= infos_len
;
221 * Reinitialize a frame.
224 reinit_frame (InterpFrame
*frame
, InterpFrame
*parent
, InterpMethod
*imethod
, stackval
*sp
)
226 frame
->parent
= parent
;
227 frame
->imethod
= imethod
;
229 frame
->state
.ip
= NULL
;
233 * List of classes whose methods will be executed by transitioning to JITted code.
236 GSList
*mono_interp_jit_classes
;
237 /* Optimizations enabled with interpreter */
238 int mono_interp_opt
= INTERP_OPT_DEFAULT
;
239 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
240 static gboolean ss_enabled
;
242 static gboolean interp_init_done
= FALSE
;
245 interp_exec_method (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
);
247 static MonoException
* do_transform_method (InterpFrame
*frame
, ThreadContext
*context
);
249 static InterpMethod
* lookup_method_pointer (gpointer addr
);
251 typedef void (*ICallMethod
) (InterpFrame
*frame
);
253 static MonoNativeTlsKey thread_context_id
;
255 #define DEBUG_INTERP 0
259 int mono_interp_traceopt
= 2;
260 /* If true, then we output the opcodes as we interpret them */
261 static int global_tracing
= 2;
263 static int debug_indent_level
= 0;
265 static int break_on_method
= 0;
266 static int nested_trace
= 0;
267 static GList
*db_methods
= NULL
;
268 static char* dump_args (InterpFrame
*inv
);
275 for (h
= 0; h
< debug_indent_level
; h
++)
280 db_match_method (gpointer data
, gpointer user_data
)
282 MonoMethod
*m
= (MonoMethod
*)user_data
;
283 MonoMethodDesc
*desc
= (MonoMethodDesc
*)data
;
285 if (mono_method_desc_full_match (desc
, m
))
290 debug_enter (InterpFrame
*frame
, int *tracing
)
293 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
295 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
299 MonoMethod
*method
= frame
->imethod
->method
;
300 char *mn
, *args
= dump_args (frame
);
301 debug_indent_level
++;
303 mn
= mono_method_full_name (method
, FALSE
);
304 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
306 g_print ("%s)\n", args
);
311 #define DEBUG_LEAVE() \
314 args = dump_retval (frame); \
316 mn = mono_method_full_name (frame->imethod->method, FALSE); \
317 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
319 g_print (" => %s\n", args); \
321 debug_indent_level--; \
322 if (tracing == 3) global_tracing = 0; \
327 int mono_interp_traceopt
= 0;
328 #define DEBUG_LEAVE()
332 #if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP && !ENABLE_CHECKED_BUILD && !PROFILE_INTERP
333 #define USE_COMPUTED_GOTO 1
336 #if USE_COMPUTED_GOTO
338 #define MINT_IN_DISPATCH(op) goto *in_labels [opcode = (MintOpcode)(op)]
339 #define MINT_IN_SWITCH(op) MINT_IN_DISPATCH (op);
340 #define MINT_IN_BREAK MINT_IN_DISPATCH (*ip)
341 #define MINT_IN_CASE(x) LAB_ ## x:
345 #define MINT_IN_SWITCH(op) COUNT_OP(op); switch (opcode = (MintOpcode)(op))
346 #define MINT_IN_CASE(x) case x:
347 #define MINT_IN_BREAK break
352 clear_resume_state (ThreadContext
*context
, GSList
*finally_ips
)
354 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
355 while (finally_ips
&&
356 finally_ips
->data
>= context
->handler_ei
->try_start
&&
357 finally_ips
->data
< context
->handler_ei
->try_end
)
358 finally_ips
= g_slist_remove (finally_ips
, finally_ips
->data
);
359 context
->has_resume_state
= 0;
360 context
->handler_frame
= NULL
;
361 context
->handler_ei
= NULL
;
362 g_assert (context
->exc_gchandle
);
363 mono_gchandle_free_internal (context
->exc_gchandle
);
364 context
->exc_gchandle
= 0;
369 * If this bit is set, it means the call has thrown the exception, and we
370 * reached this point because the EH code in mono_handle_exception ()
371 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
372 * has set the fields in context to indicate where we have to resume execution.
374 #define CHECK_RESUME_STATE(context) do { \
375 if ((context)->has_resume_state) \
380 set_context (ThreadContext
*context
)
382 mono_native_tls_set_value (thread_context_id
, context
);
387 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
388 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
390 /* jit_tls assumes ownership of 'context' */
391 jit_tls
->interp_context
= context
;
394 static ThreadContext
*
397 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
398 if (context
== NULL
) {
399 context
= g_new0 (ThreadContext
, 1);
400 context
->stack_start
= (guchar
*)mono_valloc (0, INTERP_STACK_SIZE
, MONO_MMAP_READ
| MONO_MMAP_WRITE
, MONO_MEM_ACCOUNT_INTERP_STACK
);
401 context
->stack_pointer
= context
->stack_start
;
403 frame_data_allocator_init (&context
->data_stack
, 8192);
404 /* Make sure all data is initialized before publishing the context */
405 mono_compiler_barrier ();
406 set_context (context
);
412 interp_free_context (gpointer ctx
)
414 ThreadContext
*context
= (ThreadContext
*)ctx
;
416 mono_vfree (context
->stack_start
, INTERP_STACK_SIZE
, MONO_MEM_ACCOUNT_INTERP_STACK
);
417 /* Prevent interp_mark_stack from trying to scan the data_stack, before freeing it */
418 context
->stack_start
= NULL
;
419 mono_compiler_barrier ();
420 frame_data_allocator_free (&context
->data_stack
);
425 mono_interp_error_cleanup (MonoError
* error
)
427 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
428 error_init_reuse (error
); // one instruction, so this function is good inline candidate
431 static MONO_NEVER_INLINE
void
432 ves_real_abort (int line
, MonoMethod
*mh
,
433 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
436 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
437 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
438 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
439 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
440 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
441 mono_metadata_free_mh (header
);
442 g_assert_not_reached ();
445 #define ves_abort() \
447 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
448 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
452 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
454 InterpMethod
*imethod
;
455 MonoJitDomainInfo
*info
;
457 info
= domain_jit_info (domain
);
458 mono_domain_jit_code_hash_lock (domain
);
459 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
460 mono_domain_jit_code_hash_unlock (domain
);
465 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
467 #ifndef DISABLE_REMOTING
468 InterpMethod
*imethod
;
471 imethod
= lookup_method_pointer (addr
);
474 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
475 return_val_if_nok (error
, NULL
);
478 g_assert (mono_use_interpreter
);
480 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
481 return_val_if_nok (error
, NULL
);
482 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
484 g_assert_not_reached ();
490 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
492 InterpMethod
*imethod
;
493 MonoJitDomainInfo
*info
;
494 MonoMethodSignature
*sig
;
499 info
= domain_jit_info (domain
);
500 mono_domain_jit_code_hash_lock (domain
);
501 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
502 mono_domain_jit_code_hash_unlock (domain
);
506 sig
= mono_method_signature_internal (method
);
508 imethod
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
509 imethod
->method
= method
;
510 imethod
->domain
= domain
;
511 imethod
->param_count
= sig
->param_count
;
512 imethod
->hasthis
= sig
->hasthis
;
513 imethod
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
514 imethod
->code_type
= IMETHOD_CODE_UNKNOWN
;
515 if (imethod
->method
->string_ctor
)
516 imethod
->rtype
= m_class_get_byval_arg (mono_defaults
.string_class
);
518 imethod
->rtype
= mini_get_underlying_type (sig
->ret
);
519 imethod
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
520 for (i
= 0; i
< sig
->param_count
; ++i
)
521 imethod
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
523 mono_domain_jit_code_hash_lock (domain
);
524 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
525 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, imethod
);
526 mono_domain_jit_code_hash_unlock (domain
);
528 imethod
->prof_flags
= mono_profiler_get_call_instrumentation_flags (imethod
->method
);
533 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
534 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
535 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
537 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
538 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
539 * (registers are not accurate), thus resuming to the label does not work. */
540 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
541 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
542 #elif defined (_MSC_VER)
543 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
544 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
545 (ext).interp_exit_label_set = FALSE; \
546 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
547 if ((ext).interp_exit_label_set == FALSE) \
548 mono_arch_do_ip_adjustment (&(ext).ctx); \
549 if ((ext).interp_exit_label_set == TRUE) \
551 (ext).interp_exit_label_set = TRUE;
552 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
553 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
554 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
555 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
556 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
557 mono_arch_do_ip_adjustment (&(ext).ctx);
559 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
562 /* INTERP_PUSH_LMF_WITH_CTX:
564 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
565 * This is needed to resume into the interp when the exception is thrown from
566 * native code (see ./mono/tests/install_eh_callback.exe).
568 * This must be a macro in order to retrieve the right register values for
571 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
572 memset (&(ext), 0, sizeof (MonoLMFExt)); \
573 (ext).interp_exit_data = (frame); \
574 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
575 mono_push_lmf (&(ext));
580 * Push an LMF frame on the LMF stack
581 * to mark the transition to native code.
582 * This is needed for the native code to
583 * be able to do stack walks.
586 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
588 memset (ext
, 0, sizeof (MonoLMFExt
));
589 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
590 ext
->interp_exit_data
= frame
;
596 interp_pop_lmf (MonoLMFExt
*ext
)
598 mono_pop_lmf (&ext
->lmf
);
602 get_virtual_method (InterpMethod
*imethod
, MonoVTable
*vtable
)
604 MonoMethod
*m
= imethod
->method
;
605 MonoDomain
*domain
= imethod
->domain
;
606 InterpMethod
*ret
= NULL
;
608 #ifndef DISABLE_REMOTING
609 if (mono_class_is_transparent_proxy (vtable
->klass
)) {
611 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
612 mono_error_assert_ok (error
);
613 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
614 mono_error_assert_ok (error
);
619 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
620 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
622 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
623 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
630 mono_class_setup_vtable (vtable
->klass
);
632 int slot
= mono_method_get_vtable_slot (m
);
633 if (mono_class_is_interface (m
->klass
)) {
634 g_assert (vtable
->klass
!= m
->klass
);
635 /* TODO: interface offset lookup is slow, go through IMT instead */
636 gboolean non_exact_match
;
637 slot
+= mono_class_interface_offset_with_variance (vtable
->klass
, m
->klass
, &non_exact_match
);
640 MonoMethod
*virtual_method
= m_class_get_vtable (vtable
->klass
) [slot
];
641 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
642 MonoGenericContext context
= { NULL
, NULL
};
644 if (mono_class_is_ginst (virtual_method
->klass
))
645 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
646 else if (mono_class_is_gtd (virtual_method
->klass
))
647 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
648 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
651 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
652 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
655 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
656 virtual_method
= mono_marshal_get_native_wrapper (virtual_method
, FALSE
, FALSE
);
659 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
660 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
664 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
665 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
666 return virtual_imethod
;
670 InterpMethod
*imethod
;
671 InterpMethod
*target_imethod
;
674 /* memory manager lock must be held */
676 append_imethod (MonoMemoryManager
*memory_manager
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
679 InterpVTableEntry
*entry
;
681 entry
= (InterpVTableEntry
*) mono_mem_manager_alloc_nolock (memory_manager
, sizeof (InterpVTableEntry
));
682 entry
->imethod
= imethod
;
683 entry
->target_imethod
= target_imethod
;
684 ret
= g_slist_append_mempool (memory_manager
->mp
, list
, entry
);
690 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
692 while (list
!= NULL
) {
693 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
694 if (entry
->imethod
== imethod
)
695 return entry
->target_imethod
;
702 get_method_table (MonoVTable
*vtable
, int offset
)
705 return vtable
->interp_vtable
;
707 return (gpointer
*)vtable
;
711 alloc_method_table (MonoVTable
*vtable
, int offset
)
716 table
= mono_domain_alloc0 (vtable
->domain
, m_class_get_vtable_size (vtable
->klass
) * sizeof (gpointer
));
717 vtable
->interp_vtable
= table
;
719 table
= (gpointer
*)vtable
;
725 static InterpMethod
* // Inlining causes additional stack use in caller.
726 get_virtual_method_fast (InterpMethod
*imethod
, MonoVTable
*vtable
, int offset
)
729 MonoMemoryManager
*memory_manager
= mono_domain_ambient_memory_manager (vtable
->domain
);
731 #ifndef DISABLE_REMOTING
733 if (mono_class_is_transparent_proxy (vtable
->klass
))
734 return get_virtual_method (imethod
, vtable
);
737 table
= get_method_table (vtable
, offset
);
740 /* Lazily allocate method table */
741 mono_domain_lock (vtable
->domain
);
742 table
= get_method_table (vtable
, offset
);
744 table
= alloc_method_table (vtable
, offset
);
745 mono_domain_unlock (vtable
->domain
);
748 if (!table
[offset
]) {
749 InterpMethod
*target_imethod
= get_virtual_method (imethod
, vtable
);
750 /* Lazily initialize the method table slot */
751 mono_mem_manager_lock (memory_manager
);
752 if (!table
[offset
]) {
753 if (imethod
->method
->is_inflated
|| offset
< 0)
754 table
[offset
] = append_imethod (memory_manager
, NULL
, imethod
, target_imethod
);
756 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
758 mono_mem_manager_unlock (memory_manager
);
761 if ((gsize
)table
[offset
] & 0x1) {
762 /* Non generic virtual call. Only one method in slot */
763 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
765 /* Virtual generic or interface call. Multiple methods in slot */
766 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
768 if (!target_imethod
) {
769 target_imethod
= get_virtual_method (imethod
, vtable
);
770 mono_mem_manager_lock (memory_manager
);
771 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
772 table
[offset
] = append_imethod (memory_manager
, (GSList
*)table
[offset
], imethod
, target_imethod
);
773 mono_mem_manager_unlock (memory_manager
);
775 return target_imethod
;
780 stackval_from_data (MonoType
*type
, stackval
*result
, const void *data
, gboolean pinvoke
)
782 type
= mini_native_type_replace_type (type
);
784 switch (type
->type
) {
785 case MONO_TYPE_OBJECT
:
786 case MONO_TYPE_CLASS
:
787 case MONO_TYPE_STRING
:
788 case MONO_TYPE_ARRAY
:
789 case MONO_TYPE_SZARRAY
:
794 result
->data
.p
= *(gpointer
*)data
;
797 switch (type
->type
) {
801 result
->data
.i
= *(gint8
*)data
;
804 case MONO_TYPE_BOOLEAN
:
805 result
->data
.i
= *(guint8
*)data
;
808 result
->data
.i
= *(gint16
*)data
;
812 result
->data
.i
= *(guint16
*)data
;
815 result
->data
.i
= *(gint32
*)data
;
819 result
->data
.nati
= *(mono_i
*)data
;
822 result
->data
.p
= *(gpointer
*)data
;
825 result
->data
.i
= *(guint32
*)data
;
828 /* memmove handles unaligned case */
829 memmove (&result
->data
.f_r4
, data
, sizeof (float));
833 memmove (&result
->data
.l
, data
, sizeof (gint64
));
836 memmove (&result
->data
.f
, data
, sizeof (double));
838 case MONO_TYPE_STRING
:
839 case MONO_TYPE_SZARRAY
:
840 case MONO_TYPE_CLASS
:
841 case MONO_TYPE_OBJECT
:
842 case MONO_TYPE_ARRAY
:
843 result
->data
.p
= *(gpointer
*)data
;
845 case MONO_TYPE_VALUETYPE
:
846 if (m_class_is_enumtype (type
->data
.klass
)) {
847 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
849 } else if (pinvoke
) {
850 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
852 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
855 case MONO_TYPE_GENERICINST
: {
856 if (mono_type_generic_inst_is_valuetype (type
)) {
857 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
859 memcpy (result
->data
.vt
, data
, mono_class_native_size (klass
, NULL
));
861 mono_value_copy_internal (result
->data
.vt
, data
, klass
);
864 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
868 g_error ("got type 0x%02x", type
->type
);
873 stackval_to_data (MonoType
*type
, stackval
*val
, void *data
, gboolean pinvoke
)
875 type
= mini_native_type_replace_type (type
);
877 gpointer
*p
= (gpointer
*)data
;
881 /* printf ("TODAT0 %p\n", data); */
882 switch (type
->type
) {
885 guint8
*p
= (guint8
*)data
;
889 case MONO_TYPE_BOOLEAN
: {
890 guint8
*p
= (guint8
*)data
;
891 *p
= (val
->data
.i
!= 0);
896 case MONO_TYPE_CHAR
: {
897 guint16
*p
= (guint16
*)data
;
902 mono_i
*p
= (mono_i
*)data
;
903 /* In theory the value used by stloc should match the local var type
904 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
905 a native int - both by csc and mcs). Not sure what to do about sign extension
906 as it is outside the spec... doing the obvious */
907 *p
= (mono_i
)val
->data
.nati
;
911 mono_u
*p
= (mono_u
*)data
;
913 *p
= (mono_u
)val
->data
.nati
;
918 gint32
*p
= (gint32
*)data
;
924 memmove (data
, &val
->data
.l
, sizeof (gint64
));
928 /* memmove handles unaligned case */
929 memmove (data
, &val
->data
.f_r4
, sizeof (float));
933 memmove (data
, &val
->data
.f
, sizeof (double));
936 case MONO_TYPE_STRING
:
937 case MONO_TYPE_SZARRAY
:
938 case MONO_TYPE_CLASS
:
939 case MONO_TYPE_OBJECT
:
940 case MONO_TYPE_ARRAY
: {
941 gpointer
*p
= (gpointer
*) data
;
942 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
945 case MONO_TYPE_PTR
: {
946 gpointer
*p
= (gpointer
*) data
;
950 case MONO_TYPE_VALUETYPE
:
951 if (m_class_is_enumtype (type
->data
.klass
)) {
952 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
954 } else if (pinvoke
) {
955 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
957 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
960 case MONO_TYPE_GENERICINST
: {
961 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
963 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
964 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
966 memcpy (data
, val
->data
.vt
, mono_class_native_size (klass
, NULL
));
968 mono_value_copy_internal (data
, val
->data
.vt
, klass
);
971 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
975 g_error ("got type %x", type
->type
);
980 * Same as stackval_to_data but return address of storage instead
981 * of copying the value.
984 stackval_to_data_addr (MonoType
*type
, stackval
*val
)
986 type
= mini_native_type_replace_type (type
);
990 switch (type
->type
) {
993 case MONO_TYPE_BOOLEAN
:
1002 return &val
->data
.nati
;
1005 return &val
->data
.l
;
1007 return &val
->data
.f_r4
;
1009 return &val
->data
.f
;
1010 case MONO_TYPE_STRING
:
1011 case MONO_TYPE_SZARRAY
:
1012 case MONO_TYPE_CLASS
:
1013 case MONO_TYPE_OBJECT
:
1014 case MONO_TYPE_ARRAY
:
1016 return &val
->data
.p
;
1017 case MONO_TYPE_VALUETYPE
:
1018 if (m_class_is_enumtype (type
->data
.klass
))
1019 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
1021 return val
->data
.vt
;
1022 case MONO_TYPE_TYPEDBYREF
:
1023 return val
->data
.vt
;
1024 case MONO_TYPE_GENERICINST
: {
1025 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
1027 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
1028 return val
->data
.vt
;
1029 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
1032 g_error ("got type %x", type
->type
);
1038 * Throw an exception from the interpreter.
1040 static MONO_NEVER_INLINE
void
1041 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, const guint16
* ip
, gboolean rethrow
)
1046 interp_push_lmf (&ext
, frame
);
1048 * When explicitly throwing exception we pass the ip of the instruction that throws the exception.
1049 * Offset the subtraction from interp_frame_get_ip, so we don't end up in prev instruction.
1051 frame
->state
.ip
= ip
+ 1;
1053 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
1054 MonoException
*mono_ex
= ex
;
1056 mono_ex
->stack_trace
= NULL
;
1057 mono_ex
->trace_ips
= NULL
;
1060 mono_error_assert_ok (error
);
1063 memset (&ctx
, 0, sizeof (MonoContext
));
1064 MONO_CONTEXT_SET_SP (&ctx
, frame
);
1067 * Call the JIT EH code. The EH code will call back to us using:
1068 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
1069 * Since ctx.ip is 0, this will start unwinding from the LMF frame
1070 * pushed above, which points to our frames.
1072 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
1073 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
1074 /* We need to unwind into non-interpreter code */
1075 mono_restore_context (&ctx
);
1076 g_assert_not_reached ();
1079 interp_pop_lmf (&ext
);
1081 g_assert (context
->has_resume_state
);
1084 // We conservatively pin exception object here to avoid tweaking the
1085 // numerous call sites of this macro, even though, in a few cases,
1086 // this is not needed.
1087 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
1089 MonoException *__ex = (exception); \
1090 MONO_HANDLE_ASSIGN_RAW (tmp_handle, (MonoObject*)__ex); \
1091 interp_throw (context, __ex, (frame), (ex_ip), (rethrow)); \
1092 MONO_HANDLE_ASSIGN_RAW (tmp_handle, (MonoObject*)NULL); \
1096 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
1098 #define NULL_CHECK(o) do { \
1099 if (G_UNLIKELY (!(o))) \
1100 THROW_EX (mono_get_exception_null_reference (), ip); \
1103 #define EXCEPTION_CHECKPOINT \
1105 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
1106 MonoException *exc = mono_thread_interruption_checkpoint (); \
1108 THROW_EX (exc, ip); \
1112 /* Don't throw exception if thread is in GC Safe mode. Should only happen in managed-to-native wrapper. */
1113 #define EXCEPTION_CHECKPOINT_GC_UNSAFE \
1115 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method) && mono_thread_is_gc_unsafe_mode ()) { \
1116 MonoException *exc = mono_thread_interruption_checkpoint (); \
1118 THROW_EX (exc, ip); \
1123 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
1125 int rank
= m_class_get_rank (klass
);
1126 uintptr_t *lengths
= g_newa (uintptr_t, rank
* 2);
1127 intptr_t *lower_bounds
= NULL
;
1128 if (2 * rank
== param_count
) {
1129 for (int l
= 0; l
< 2; ++l
) {
1132 for (int r
= 0; r
< rank
; ++r
, src
+= 2, ++dst
) {
1133 lengths
[dst
] = values
[src
].data
.i
;
1136 /* lower bounds are first. */
1137 lower_bounds
= (intptr_t *) lengths
;
1140 /* Only lengths provided. */
1141 for (int i
= 0; i
< param_count
; ++i
) {
1142 lengths
[i
] = values
[i
].data
.i
;
1145 return (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
1149 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, gboolean safe
)
1151 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1155 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
1156 gint32 idx
= sp
[i
].data
.i
;
1157 gint32 lower
= ao
->bounds
[i
].lower_bound
;
1158 guint32 len
= ao
->bounds
[i
].length
;
1159 if (safe
&& (idx
< lower
|| (guint32
)(idx
- lower
) >= len
))
1161 pos
= (pos
* len
) + (guint32
)(idx
- lower
);
1164 pos
= sp
[0].data
.i
;
1165 if (safe
&& pos
>= ao
->max_length
)
1171 static MonoException
*
1172 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1174 MonoObject
*o
= sp
->data
.o
;
1175 MonoArray
*ao
= (MonoArray
*) o
;
1176 MonoClass
*ac
= o
->vtable
->klass
;
1178 g_assert (m_class_get_rank (ac
) >= 1);
1180 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, safe
);
1182 return mono_get_exception_index_out_of_range ();
1184 gint32 esize
= mono_array_element_size (ac
);
1185 gconstpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1187 MonoType
*mt
= sig
->ret
;
1188 stackval_from_data (mt
, retval
, ea
, FALSE
);
1192 static MonoException
*
1193 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1195 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1197 g_assert (m_class_get_rank (ac
) >= 1);
1199 gint32 pos
= ves_array_calculate_index (ao
, sp
, TRUE
);
1201 return mono_get_exception_index_out_of_range ();
1203 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
))
1204 return mono_get_exception_array_type_mismatch ();
1205 gint32 esize
= mono_array_element_size (ac
);
1206 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1210 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1211 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1214 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1215 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1217 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1220 g_assert (mono_arm_eabi_supported ());
1221 int i8_align
= mono_arm_i8_align ();
1231 for (int i
= 0; i
< sig
->param_count
; i
++) {
1232 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1234 case MONO_TYPE_BOOLEAN
:
1235 case MONO_TYPE_CHAR
:
1245 case MONO_TYPE_SZARRAY
:
1246 case MONO_TYPE_CLASS
:
1247 case MONO_TYPE_OBJECT
:
1248 case MONO_TYPE_STRING
:
1249 case MONO_TYPE_VALUETYPE
:
1250 case MONO_TYPE_GENERICINST
:
1251 #if SIZEOF_VOID_P == 8
1257 #if SIZEOF_VOID_P == 4
1261 /* pairs begin at even registers */
1262 if (i8_align
== 8 && margs
->ilen
& 1)
1273 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1277 if (margs
->ilen
> 0)
1278 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1280 if (margs
->flen
> 0)
1281 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1283 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1284 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1286 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1287 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1294 margs
->iargs
[0] = frame
->stack
[0].data
.p
;
1296 g_error ("FIXME if hasthis, we incorrectly access the args below");
1299 for (int i
= 0; i
< sig
->param_count
; i
++) {
1300 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1302 case MONO_TYPE_BOOLEAN
:
1303 case MONO_TYPE_CHAR
:
1313 case MONO_TYPE_SZARRAY
:
1314 case MONO_TYPE_CLASS
:
1315 case MONO_TYPE_OBJECT
:
1316 case MONO_TYPE_STRING
:
1317 case MONO_TYPE_VALUETYPE
:
1318 case MONO_TYPE_GENERICINST
:
1319 #if SIZEOF_VOID_P == 8
1323 margs
->iargs
[int_i
] = frame
->stack
[i
].data
.p
;
1325 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1329 #if SIZEOF_VOID_P == 4
1331 case MONO_TYPE_U8
: {
1332 stackval
*sarg
= &frame
->stack
[i
];
1334 /* pairs begin at even registers */
1335 if (i8_align
== 8 && int_i
& 1)
1338 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1340 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1342 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
);
1350 if (ptype
== MONO_TYPE_R4
)
1351 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack
[i
].data
.f_r4
;
1353 margs
->fargs
[int_f
] = frame
->stack
[i
].data
.f
;
1355 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
);
1360 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1364 switch (sig
->ret
->type
) {
1365 case MONO_TYPE_BOOLEAN
:
1366 case MONO_TYPE_CHAR
:
1376 case MONO_TYPE_SZARRAY
:
1377 case MONO_TYPE_CLASS
:
1378 case MONO_TYPE_OBJECT
:
1379 case MONO_TYPE_STRING
:
1382 case MONO_TYPE_VALUETYPE
:
1383 case MONO_TYPE_GENERICINST
:
1384 margs
->retval
= &frame
->retval
->data
.p
;
1385 margs
->is_float_ret
= 0;
1389 margs
->retval
= &frame
->retval
->data
.p
;
1390 margs
->is_float_ret
= 1;
1392 case MONO_TYPE_VOID
:
1393 margs
->retval
= NULL
;
1396 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1404 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1406 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1409 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1411 stackval_to_data (sig
->params
[index
], &iframe
->stack
[index
], data
, sig
->pinvoke
);
1415 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gconstpointer data
)
1417 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1420 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1421 else if (sig
->hasthis
&& index
== 0)
1422 iframe
->stack
[index
].data
.p
= *(gpointer
*)data
;
1424 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack
[index
], data
, sig
->pinvoke
);
1428 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1430 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1433 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1435 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack
[index
]);
1439 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1441 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1442 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack
[index
];
1443 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1445 switch (type
->type
) {
1446 case MONO_TYPE_GENERICINST
:
1447 if (!MONO_TYPE_IS_REFERENCE (type
))
1448 val
->data
.vt
= storage
;
1450 case MONO_TYPE_VALUETYPE
:
1451 val
->data
.vt
= storage
;
1454 g_assert_not_reached ();
1459 get_interp_to_native_trampoline (void)
1461 static MonoPIFunc trampoline
= NULL
;
1464 if (mono_ee_features
.use_aot_trampolines
) {
1465 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1467 MonoTrampInfo
*info
;
1468 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1469 mono_tramp_info_register (info
, NULL
);
1471 mono_memory_barrier ();
1477 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1479 get_interp_to_native_trampoline () (addr
, ccontext
);
1482 /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1484 #pragma optimize ("", off)
1486 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1487 ves_pinvoke_method (
1488 MonoMethodSignature
*sig
,
1490 ThreadContext
*context
,
1491 InterpFrame
*parent_frame
,
1493 gboolean save_last_error
,
1497 InterpFrame frame
= {0};
1498 frame
.parent
= parent_frame
;
1500 frame
.retval
= retval
;
1505 g_assert (!frame
.imethod
);
1508 * When there's a calli in a pinvoke wrapper, we're in GC Safe mode.
1509 * When we're called for some other calli, we may be in GC Unsafe mode.
1511 * On any code path where we call anything other than the entry_func,
1512 * we need to switch back to GC Unsafe before calling the runtime.
1514 MONO_REQ_GC_NEUTRAL_MODE
;
1518 * Use a per-signature entry function.
1519 * Cache it in imethod->data_items.
1522 MonoPIFunc entry_func
= *cache
;
1524 entry_func
= (MonoPIFunc
)mono_wasm_get_interp_to_native_trampoline (sig
);
1525 mono_memory_barrier ();
1526 *cache
= entry_func
;
1529 static MonoPIFunc entry_func
= NULL
;
1531 MONO_ENTER_GC_UNSAFE
;
1532 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1534 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
);
1535 mono_error_assert_ok (error
);
1537 entry_func
= get_interp_to_native_trampoline ();
1539 mono_memory_barrier ();
1540 MONO_EXIT_GC_UNSAFE
;
1544 #ifdef ENABLE_NETCORE
1545 if (save_last_error
) {
1546 mono_marshal_clear_last_error ();
1550 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1551 CallContext ccontext
;
1552 MONO_ENTER_GC_UNSAFE
;
1553 mono_arch_set_native_call_context_args (&ccontext
, &frame
, sig
);
1554 MONO_EXIT_GC_UNSAFE
;
1557 InterpMethodArguments
*margs
= build_args_from_sig (sig
, &frame
);
1561 INTERP_PUSH_LMF_WITH_CTX (&frame
, ext
, exit_pinvoke
);
1562 entry_func ((gpointer
) addr
, args
);
1563 if (save_last_error
)
1564 mono_marshal_set_last_error ();
1565 interp_pop_lmf (&ext
);
1567 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1568 if (!context
->has_resume_state
) {
1569 MONO_ENTER_GC_UNSAFE
;
1570 mono_arch_get_native_call_context_ret (&ccontext
, &frame
, sig
);
1571 MONO_EXIT_GC_UNSAFE
;
1574 g_free (ccontext
.stack
);
1576 if (!context
->has_resume_state
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1577 stackval_from_data (sig
->ret
, frame
.retval
, (char*)&frame
.retval
->data
.p
, sig
->pinvoke
);
1579 g_free (margs
->iargs
);
1580 g_free (margs
->fargs
);
1583 goto exit_pinvoke
; // prevent unused label warning in some configurations
1588 #pragma optimize ("", on)
1592 * interp_init_delegate:
1594 * Initialize del->interp_method.
1597 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1601 if (del
->interp_method
) {
1602 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1603 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1604 } if (del
->method_ptr
&& !del
->method
) {
1605 /* Delegate created from methodInfo.MethodHandle.GetFunctionPointer() */
1606 del
->interp_method
= (InterpMethod
*)del
->method_ptr
;
1607 } else if (del
->method
) {
1608 /* Delegate created dynamically */
1609 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1611 /* Created from JITted code */
1612 g_assert_not_reached ();
1615 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1618 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1619 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1620 mono_class_is_abstract (method
->klass
))
1621 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1623 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1624 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1625 const char *name
= method
->name
;
1626 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1628 * When invoking the delegate interp_method is executed directly. If it's an
1629 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1631 * FIXME We should do this later, when we also know the delegate on which the
1632 * target method is called.
1634 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1635 mono_error_assert_ok (error
);
1639 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1640 /* Return any errors from method compilation */
1641 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1642 return_if_nok (error
);
1647 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1650 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1652 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1654 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1655 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1656 /* virtual invoke delegates must not have null check */
1657 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1658 && MONO_HANDLE_IS_NULL (target
)) {
1659 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1664 g_assert (imethod
->method
);
1665 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1666 return_if_nok (error
);
1668 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1670 mono_delegate_ctor (this_obj
, target
, entry
, imethod
->method
, error
);
1675 * runtime specifies that the implementation of the method is automatically
1676 * provided by the runtime and is primarily used for the methods of delegates.
1678 #ifndef ENABLE_NETCORE
1679 static MONO_NEVER_INLINE MonoException
*
1680 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1682 const char *name
= method
->name
;
1683 mono_class_init_internal (method
->klass
);
1685 if (method
->klass
== mono_defaults
.array_class
) {
1686 if (!strcmp (name
, "UnsafeMov")) {
1687 /* TODO: layout checks */
1688 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1691 if (!strcmp (name
, "UnsafeLoad"))
1692 return ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1695 g_error ("Don't know how to exec runtime method %s.%s::%s",
1696 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1703 dump_stack (stackval
*stack
, stackval
*sp
)
1705 stackval
*s
= stack
;
1706 GString
*str
= g_string_new ("");
1709 return g_string_free (str
, FALSE
);
1712 g_string_append_printf (str
, "[%p (%" PRId64
")] ", s
->data
.l
, (gint64
)s
->data
.l
);
1715 return g_string_free (str
, FALSE
);
1719 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1721 switch (type
->type
) {
1728 case MONO_TYPE_CHAR
:
1729 case MONO_TYPE_BOOLEAN
:
1730 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1732 case MONO_TYPE_STRING
:
1733 case MONO_TYPE_SZARRAY
:
1734 case MONO_TYPE_CLASS
:
1735 case MONO_TYPE_OBJECT
:
1736 case MONO_TYPE_ARRAY
:
1740 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1742 case MONO_TYPE_VALUETYPE
:
1743 if (m_class_is_enumtype (type
->data
.klass
))
1744 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1746 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1749 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1752 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1757 GString
*res
= g_string_new ("");
1758 mono_type_get_desc (res
, type
, TRUE
);
1759 g_string_append_printf (str
, "[{%s} %" PRId64
"/0x%0" PRIx64
"] ", res
->str
, (gint64
)s
->data
.l
, (guint64
)s
->data
.l
);
1760 g_string_free (res
, TRUE
);
1767 dump_retval (InterpFrame
*inv
)
1769 GString
*str
= g_string_new ("");
1770 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1772 if (ret
->type
!= MONO_TYPE_VOID
)
1773 dump_stackval (str
, inv
->retval
, ret
);
1775 return g_string_free (str
, FALSE
);
1779 dump_args (InterpFrame
*inv
)
1781 GString
*str
= g_string_new ("");
1783 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1785 if (signature
->param_count
== 0 && !signature
->hasthis
)
1786 return g_string_free (str
, FALSE
);
1788 if (signature
->hasthis
) {
1789 MonoMethod
*method
= inv
->imethod
->method
;
1790 dump_stackval (str
, inv
->stack
, m_class_get_byval_arg (method
->klass
));
1793 for (i
= 0; i
< signature
->param_count
; ++i
)
1794 dump_stackval (str
, inv
->stack
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1796 return g_string_free (str
, FALSE
);
1800 #define CHECK_ADD_OVERFLOW(a,b) \
1801 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1802 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1804 #define CHECK_SUB_OVERFLOW(a,b) \
1805 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1806 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1808 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1809 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1811 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1812 (guint32)(a) < (guint32)(b) ? -1 : 0
1814 #define CHECK_ADD_OVERFLOW64(a,b) \
1815 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1816 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1818 #define CHECK_SUB_OVERFLOW64(a,b) \
1819 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1820 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1822 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1823 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1825 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1826 (guint64)(a) < (guint64)(b) ? -1 : 0
1828 #if SIZEOF_VOID_P == 4
1829 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1830 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1832 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1833 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1836 /* Resolves to TRUE if the operands would overflow */
1837 #define CHECK_MUL_OVERFLOW(a,b) \
1838 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1839 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1840 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1841 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1842 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1843 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1844 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1846 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1847 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1848 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1850 #define CHECK_MUL_OVERFLOW64(a,b) \
1851 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1852 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1853 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1854 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1855 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1856 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1857 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1859 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1860 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1861 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1863 #if SIZEOF_VOID_P == 4
1864 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1865 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1867 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1868 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1871 // Do not inline in case order of frame addresses matters.
1872 static MONO_NEVER_INLINE MonoObject
*
1873 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1875 ThreadContext
*context
= get_context ();
1876 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1877 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1879 stackval
*sp
= (stackval
*)context
->stack_pointer
;
1880 MonoMethod
*target_method
= method
;
1886 MonoDomain
*domain
= mono_domain_get ();
1888 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1889 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1890 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1892 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1894 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1896 sp
[0].data
.p
= obj
;
1898 sp
[0].data
.p
= NULL
;
1899 sp
[1].data
.p
= params
;
1900 sp
[2].data
.p
= exc
;
1901 sp
[3].data
.p
= target_method
;
1903 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1904 mono_error_assert_ok (error
);
1906 InterpFrame frame
= {0};
1907 frame
.imethod
= imethod
;
1909 frame
.retval
= &result
;
1911 // The method to execute might not be transformed yet, so we don't know how much stack
1912 // it uses. We bump the stack_pointer here so any code triggered by method compilation
1913 // will not attempt to use the space that we used to push the args for this method.
1914 // The real top of stack for this method will be set in interp_exec_method once the
1915 // method is transformed.
1916 context
->stack_pointer
= (guchar
*)(sp
+ 4);
1918 interp_exec_method (&frame
, context
, NULL
);
1920 context
->stack_pointer
= (guchar
*)sp
;
1922 if (context
->has_resume_state
) {
1924 * This can happen on wasm where native frames cannot be skipped during EH.
1925 * EH processing will continue when control returns to the interpreter.
1929 return (MonoObject
*)result
.data
.p
;
1933 InterpMethod
*rmethod
;
1937 gpointer
*many_args
;
1940 /* Main function for entering the interpreter from compiled code */
1941 // Do not inline in case order of frame addresses matters.
1942 static MONO_NEVER_INLINE
void
1943 interp_entry (InterpEntryData
*data
)
1945 InterpMethod
*rmethod
;
1946 ThreadContext
*context
;
1950 MonoMethodSignature
*sig
;
1952 gpointer orig_domain
= NULL
, attach_cookie
;
1955 if ((gsize
)data
->rmethod
& 1) {
1957 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1958 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1960 rmethod
= data
->rmethod
;
1962 if (rmethod
->needs_thread_attach
)
1963 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1965 context
= get_context ();
1966 sp
= (stackval
*)context
->stack_pointer
;
1968 method
= rmethod
->method
;
1969 sig
= mono_method_signature_internal (method
);
1971 // FIXME: Optimize this
1974 sp
[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 sp
[a_index
].data
.p
= params
[i
];
1987 type
= rmethod
->param_types
[i
];
1988 switch (type
->type
) {
1989 case MONO_TYPE_VALUETYPE
:
1990 sp
[a_index
].data
.p
= params
[i
];
1992 case MONO_TYPE_GENERICINST
:
1993 if (MONO_TYPE_IS_REFERENCE (type
))
1994 sp
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1996 sp
[a_index
].data
.vt
= params
[i
];
1999 stackval_from_data (type
, &sp
[a_index
], params
[i
], FALSE
);
2004 memset (&result
, 0, sizeof (result
));
2006 InterpFrame frame
= {0};
2007 frame
.imethod
= data
->rmethod
;
2009 frame
.retval
= &result
;
2011 type
= rmethod
->rtype
;
2012 switch (type
->type
) {
2013 case MONO_TYPE_GENERICINST
:
2014 if (!MONO_TYPE_IS_REFERENCE (type
))
2015 result
.data
.vt
= data
->res
;
2017 case MONO_TYPE_VALUETYPE
:
2018 result
.data
.vt
= data
->res
;
2024 context
->stack_pointer
= (guchar
*)(sp
+ sig
->hasthis
+ sig
->param_count
);
2026 interp_exec_method (&frame
, context
, NULL
);
2028 context
->stack_pointer
= (guchar
*)sp
;
2030 g_assert (!context
->has_resume_state
);
2032 if (rmethod
->needs_thread_attach
)
2033 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2035 if (mono_llvm_only
) {
2036 if (context
->has_resume_state
)
2037 mono_llvm_reraise_exception ((MonoException
*)mono_gchandle_get_target_internal (context
->exc_gchandle
));
2039 g_assert (!context
->has_resume_state
);
2042 type
= rmethod
->rtype
;
2043 switch (type
->type
) {
2044 case MONO_TYPE_VOID
:
2046 case MONO_TYPE_OBJECT
:
2047 /* No need for a write barrier */
2048 *(MonoObject
**)data
->res
= (MonoObject
*)result
.data
.p
;
2050 case MONO_TYPE_GENERICINST
:
2051 if (MONO_TYPE_IS_REFERENCE (type
)) {
2052 *(MonoObject
**)data
->res
= (MonoObject
*)result
.data
.p
;
2054 /* Already set before the call */
2057 case MONO_TYPE_VALUETYPE
:
2058 /* Already set before the call */
2061 stackval_to_data (type
, &result
, data
->res
, FALSE
);
2067 do_icall (MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2069 #ifdef ENABLE_NETCORE
2070 if (save_last_error
)
2071 mono_marshal_clear_last_error ();
2075 case MINT_ICALL_V_V
: {
2076 typedef void (*T
)(void);
2081 case MINT_ICALL_V_P
: {
2082 typedef gpointer (*T
)(void);
2085 sp
[-1].data
.p
= func ();
2088 case MINT_ICALL_P_V
: {
2089 typedef void (*T
)(gpointer
);
2091 func (sp
[-1].data
.p
);
2095 case MINT_ICALL_P_P
: {
2096 typedef gpointer (*T
)(gpointer
);
2098 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
2101 case MINT_ICALL_PP_V
: {
2102 typedef void (*T
)(gpointer
,gpointer
);
2105 func (sp
[0].data
.p
, sp
[1].data
.p
);
2108 case MINT_ICALL_PP_P
: {
2109 typedef gpointer (*T
)(gpointer
,gpointer
);
2112 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
2115 case MINT_ICALL_PPP_V
: {
2116 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
2119 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2122 case MINT_ICALL_PPP_P
: {
2123 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
2126 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
2129 case MINT_ICALL_PPPP_V
: {
2130 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2133 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
2136 case MINT_ICALL_PPPP_P
: {
2137 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
2140 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
2143 case MINT_ICALL_PPPPP_V
: {
2144 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2147 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
2150 case MINT_ICALL_PPPPP_P
: {
2151 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2154 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
);
2157 case MINT_ICALL_PPPPPP_V
: {
2158 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2161 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
);
2164 case MINT_ICALL_PPPPPP_P
: {
2165 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2168 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
);
2172 g_assert_not_reached ();
2175 if (save_last_error
)
2176 mono_marshal_set_last_error ();
2178 /* convert the native representation to the stackval representation */
2180 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2185 /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2187 #pragma optimize ("", off)
2189 // Do not inline in case order of frame addresses matters, and maybe other reasons.
2190 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
2191 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2194 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
2196 sp
= do_icall (sig
, op
, sp
, ptr
, save_last_error
);
2198 interp_pop_lmf (&ext
);
2200 goto exit_icall
; // prevent unused label warning in some configurations
2205 #pragma optimize ("", on)
2210 gpointer jit_wrapper
;
2212 MonoFtnDesc ftndesc
;
2215 /* Callback called by mono_llvm_cpp_catch_exception () */
2217 jit_call_cb (gpointer arg
)
2219 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2220 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2221 int pindex
= cb_data
->pindex
;
2222 gpointer
*args
= cb_data
->args
;
2223 MonoFtnDesc
*ftndesc
= &cb_data
->ftndesc
;
2227 typedef void (*T
)(gpointer
);
2228 T func
= (T
)jit_wrapper
;
2234 typedef void (*T
)(gpointer
, gpointer
);
2235 T func
= (T
)jit_wrapper
;
2237 func (args
[0], ftndesc
);
2241 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2242 T func
= (T
)jit_wrapper
;
2244 func (args
[0], args
[1], ftndesc
);
2248 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2249 T func
= (T
)jit_wrapper
;
2251 func (args
[0], args
[1], args
[2], ftndesc
);
2255 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2256 T func
= (T
)jit_wrapper
;
2258 func (args
[0], args
[1], args
[2], args
[3], ftndesc
);
2262 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2263 T func
= (T
)jit_wrapper
;
2265 func (args
[0], args
[1], args
[2], args
[3], args
[4], ftndesc
);
2269 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2270 T func
= (T
)jit_wrapper
;
2272 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], ftndesc
);
2276 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2277 T func
= (T
)jit_wrapper
;
2279 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], ftndesc
);
2283 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2284 T func
= (T
)jit_wrapper
;
2286 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], ftndesc
);
2290 g_assert_not_reached ();
2296 /* Pass stackval->data.p */
2298 /* Pass &stackval->data.p */
2308 typedef struct _JitCallInfo JitCallInfo
;
2309 struct _JitCallInfo
{
2313 MonoMethodSignature
*sig
;
2319 static MONO_NEVER_INLINE
void
2320 init_jit_call_info (InterpMethod
*rmethod
, MonoError
*error
)
2322 MonoMethodSignature
*sig
;
2325 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2327 MonoMethod
*method
= rmethod
->method
;
2329 // FIXME: Memory management
2330 cinfo
= g_new0 (JitCallInfo
, 1);
2332 sig
= mono_method_signature_internal (method
);
2335 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2336 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2338 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2339 mono_error_assert_ok (error
);
2341 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2342 return_if_nok (error
);
2346 cinfo
->addr
= mini_llvmonly_add_method_wrappers (method
, addr
, FALSE
, FALSE
, &cinfo
->extra_arg
);
2350 cinfo
->wrapper
= jit_wrapper
;
2352 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
2353 int mt
= mint_type (sig
->ret
);
2354 if (mt
== MINT_TYPE_VT
) {
2355 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
2357 * We cache this size here, instead of the instruction stream of the
2358 * calling instruction, to save space for common callvirt instructions
2359 * that could end up doing a jit call.
2361 gint32 size
= mono_class_value_size (klass
, NULL
);
2362 cinfo
->vt_res_size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
2369 if (sig
->param_count
) {
2370 cinfo
->arginfo
= g_new0 (guint8
, sig
->param_count
);
2372 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2373 MonoType
*t
= rmethod
->param_types
[i
];
2374 int mt
= mint_type (t
);
2375 if (sig
->params
[i
]->byref
) {
2376 cinfo
->arginfo
[i
] = JIT_ARG_BYVAL
;
2377 } else if (mt
== MINT_TYPE_VT
) {
2378 cinfo
->arginfo
[i
] = JIT_ARG_BYVAL
;
2379 } else if (mt
== MINT_TYPE_O
) {
2380 cinfo
->arginfo
[i
] = JIT_ARG_BYREF
;
2382 /* stackval->data is an union */
2383 cinfo
->arginfo
[i
] = JIT_ARG_BYREF
;
2388 mono_memory_barrier ();
2389 rmethod
->jit_call_info
= cinfo
;
2392 static MONO_NEVER_INLINE
void
2393 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2395 guint8 res_buf
[256];
2399 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2402 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2403 * by ref and return a return value using an explicit return value argument.
2405 if (G_UNLIKELY (!rmethod
->jit_call_info
)) {
2406 init_jit_call_info (rmethod
, error
);
2407 mono_error_assert_ok (error
);
2409 cinfo
= (JitCallInfo
*)rmethod
->jit_call_info
;
2412 * Convert the arguments on the interpeter stack to the format expected by the gsharedvt_out wrapper.
2416 int stack_index
= 0;
2417 if (rmethod
->hasthis
) {
2418 args
[pindex
++] = sp
[0].data
.p
;
2421 switch (cinfo
->ret_mt
) {
2425 args
[pindex
++] = vt_sp
;
2428 args
[pindex
++] = res_buf
;
2431 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2432 stackval
*sval
= &sp
[stack_index
+ i
];
2433 if (cinfo
->arginfo
[i
] == JIT_ARG_BYVAL
)
2434 args
[pindex
++] = sval
->data
.p
;
2436 /* data is an union, so can use 'p' for all types */
2437 args
[pindex
++] = &sval
->data
.p
;
2440 JitCallCbData cb_data
;
2441 memset (&cb_data
, 0, sizeof (cb_data
));
2442 cb_data
.jit_wrapper
= cinfo
->wrapper
;
2443 cb_data
.pindex
= pindex
;
2444 cb_data
.args
= args
;
2445 cb_data
.ftndesc
.addr
= cinfo
->addr
;
2446 cb_data
.ftndesc
.arg
= cinfo
->extra_arg
;
2448 interp_push_lmf (&ext
, frame
);
2449 gboolean thrown
= FALSE
;
2450 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2451 /* Catch the exception thrown by the native code using a try-catch */
2452 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2454 jit_call_cb (&cb_data
);
2456 interp_pop_lmf (&ext
);
2458 MonoObject
*obj
= mono_llvm_load_exception ();
2460 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2464 if (cinfo
->ret_mt
!= -1) {
2465 switch (cinfo
->ret_mt
) {
2467 sp
->data
.p
= *(gpointer
*)res_buf
;
2470 sp
->data
.i
= *(gint8
*)res_buf
;
2473 sp
->data
.i
= *(guint8
*)res_buf
;
2476 sp
->data
.i
= *(gint16
*)res_buf
;
2479 sp
->data
.i
= *(guint16
*)res_buf
;
2482 sp
->data
.i
= *(gint32
*)res_buf
;
2485 sp
->data
.l
= *(gint64
*)res_buf
;
2488 sp
->data
.f_r4
= *(float*)res_buf
;
2491 sp
->data
.f
= *(double*)res_buf
;
2494 /* The result was written to vt_sp */
2498 g_assert_not_reached ();
2503 static MONO_NEVER_INLINE
void
2504 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2507 interp_push_lmf (&ext
, frame
);
2509 interp_pop_lmf (&ext
);
2512 static MONO_NEVER_INLINE MonoException
*
2513 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2516 /* Don't push lmf if we have no interp data */
2517 gboolean push_lmf
= frame
->parent
!= NULL
;
2521 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
2522 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2526 /* Use the parent frame as the current frame is not complete yet */
2528 interp_push_lmf (&ext
, frame
->parent
);
2530 mono_interp_transform_method (frame
->imethod
, context
, error
);
2533 interp_pop_lmf (&ext
);
2535 return mono_error_convert_to_exception (error
);
2539 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, guchar
*vt_sp_start
)
2541 stackval
*first_arg
= sp
- csig
->param_count
;
2542 guchar
*vt_sp
= vt_sp_start
;
2545 * We need to have the varargs linearly on the stack so the ArgIterator
2546 * can iterate over them. We pass the signature first and then copy them
2547 * one by one on the vtstack. The callee (MINT_ARGLIST) will be able to
2548 * find this space by adding the current vt_sp pointer in the parent frame
2549 * with the amount of vtstack space used by the parameters.
2551 *(gpointer
*)vt_sp
= csig
;
2552 vt_sp
+= sizeof (gpointer
);
2554 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2555 int align
, arg_size
;
2556 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2557 vt_sp
= (guchar
*)ALIGN_PTR_TO (vt_sp
, align
);
2559 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt_sp
, FALSE
);
2565 * These functions are the entry points into the interpreter from compiled code.
2566 * They are called by the interp_in wrappers. They have the following signature:
2567 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2568 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2569 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2570 * more wrappers then these functions.
2571 * this/static * ret/void * 16 arguments -> 64 functions.
2574 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2575 InterpEntryData data; \
2576 (data).rmethod = (_method); \
2577 (data).res = (_res); \
2578 (data).this_arg = (_this_arg); \
2579 (data).many_args = NULL;
2581 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2582 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2583 interp_entry (&data); \
2585 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2586 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2587 (data).args [0] = arg1; \
2588 interp_entry (&data); \
2590 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2591 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2592 (data).args [0] = arg1; \
2593 (data).args [1] = arg2; \
2594 interp_entry (&data); \
2596 #define INTERP_ENTRY3(_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 interp_entry (&data); \
2603 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2604 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2605 (data).args [0] = arg1; \
2606 (data).args [1] = arg2; \
2607 (data).args [2] = arg3; \
2608 (data).args [3] = arg4; \
2609 interp_entry (&data); \
2611 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2612 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2613 (data).args [0] = arg1; \
2614 (data).args [1] = arg2; \
2615 (data).args [2] = arg3; \
2616 (data).args [3] = arg4; \
2617 (data).args [4] = arg5; \
2618 interp_entry (&data); \
2620 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2621 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2622 (data).args [0] = arg1; \
2623 (data).args [1] = arg2; \
2624 (data).args [2] = arg3; \
2625 (data).args [3] = arg4; \
2626 (data).args [4] = arg5; \
2627 (data).args [5] = arg6; \
2628 interp_entry (&data); \
2630 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2631 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2632 (data).args [0] = arg1; \
2633 (data).args [1] = arg2; \
2634 (data).args [2] = arg3; \
2635 (data).args [3] = arg4; \
2636 (data).args [4] = arg5; \
2637 (data).args [5] = arg6; \
2638 (data).args [6] = arg7; \
2639 interp_entry (&data); \
2641 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2642 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2643 (data).args [0] = arg1; \
2644 (data).args [1] = arg2; \
2645 (data).args [2] = arg3; \
2646 (data).args [3] = arg4; \
2647 (data).args [4] = arg5; \
2648 (data).args [5] = arg6; \
2649 (data).args [6] = arg7; \
2650 (data).args [7] = arg8; \
2651 interp_entry (&data); \
2654 #define ARGLIST0 InterpMethod *rmethod
2655 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2656 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2657 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2658 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2659 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2660 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2661 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2662 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2664 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2665 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2666 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2667 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2668 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2669 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2670 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2671 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2672 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2673 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2674 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2675 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2676 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2677 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2678 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2679 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2680 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2681 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2682 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2683 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2684 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2685 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2686 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2687 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2688 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2689 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2690 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2691 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2692 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2693 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2694 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2695 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2696 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2697 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2698 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2699 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2701 #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
2703 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2704 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2705 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2706 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2708 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2710 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2712 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2713 data
.many_args
= args
;
2714 interp_entry (&data
);
2717 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2719 // inline so we can alloc on stack
2720 #define alloc_storage_for_stackval(s, t, p) do { \
2721 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2722 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2723 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2725 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2727 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2731 // Do not inline in case order of frame addresses matters.
2732 static MONO_NEVER_INLINE
void
2733 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2735 ThreadContext
*context
;
2739 MonoMethodSignature
*sig
;
2740 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2741 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2742 gpointer orig_domain
= NULL
, attach_cookie
;
2745 if (rmethod
->needs_thread_attach
)
2746 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2748 context
= get_context ();
2749 sp
= (stackval
*)context
->stack_pointer
;
2751 method
= rmethod
->method
;
2752 sig
= mono_method_signature_internal (method
);
2753 if (method
->string_ctor
) {
2754 MonoMethodSignature
*newsig
= g_alloca (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
2755 memcpy (newsig
, sig
, mono_metadata_signature_size (sig
));
2756 newsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2760 /* Allocate storage for value types */
2761 for (i
= 0; i
< sig
->param_count
; i
++) {
2762 MonoType
*type
= sig
->params
[i
];
2763 alloc_storage_for_stackval (&sp
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2766 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2767 alloc_storage_for_stackval (&result
, sig
->ret
, sig
->pinvoke
);
2769 InterpFrame frame
= {0};
2770 frame
.imethod
= rmethod
;
2772 frame
.retval
= &result
;
2774 /* Copy the args saved in the trampoline to the frame stack */
2775 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2777 context
->stack_pointer
= (guchar
*)(sp
+ sig
->hasthis
+ sig
->param_count
);
2779 interp_exec_method (&frame
, context
, NULL
);
2781 context
->stack_pointer
= (guchar
*)sp
;
2782 g_assert (!context
->has_resume_state
);
2784 if (rmethod
->needs_thread_attach
)
2785 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2787 /* Write back the return value */
2788 /* 'frame' is still valid */
2789 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2795 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2797 g_assert_not_reached ();
2800 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2802 static InterpMethod
*
2803 lookup_method_pointer (gpointer addr
)
2805 MonoDomain
*domain
= mono_domain_get ();
2806 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2807 InterpMethod
*res
= NULL
;
2809 mono_domain_lock (domain
);
2810 if (info
->interp_method_pointer_hash
)
2811 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2812 mono_domain_unlock (domain
);
2817 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2819 interp_no_native_to_managed (void)
2821 g_error ("interpreter: native-to-managed transition not available on this platform");
2826 no_llvmonly_interp_method_pointer (void)
2828 g_assert_not_reached ();
2832 * interp_create_method_pointer_llvmonly:
2834 * Return an ftndesc for entering the interpreter and executing METHOD.
2837 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2839 MonoDomain
*domain
= mono_domain_get ();
2840 gpointer addr
, entry_func
, entry_wrapper
;
2841 MonoMethodSignature
*sig
;
2842 MonoMethod
*wrapper
;
2843 MonoJitDomainInfo
*info
;
2844 InterpMethod
*imethod
;
2846 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2847 return_val_if_nok (error
, NULL
);
2850 if (imethod
->llvmonly_unbox_entry
)
2851 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2853 if (imethod
->jit_entry
)
2854 return (MonoFtnDesc
*)imethod
->jit_entry
;
2857 sig
= mono_method_signature_internal (method
);
2860 * The entry functions need access to the method to call, so we have
2861 * to use a ftndesc. The caller uses a normal signature, while the
2862 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2863 * a gsharedvt_in_sig wrapper.
2864 * We use a gsharedvt_in_sig wrapper instead of an interp_in wrapper, because they
2865 * are mostly the same, and they are already generated. The exception is the
2866 * wrappers for methods with more than 8 arguments, those are different.
2868 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
)
2869 wrapper
= mini_get_interp_in_wrapper (sig
);
2871 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2873 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2874 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2875 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2876 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2878 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2879 entry_func
= (gpointer
)interp_entry_general
;
2880 } else if (sig
->hasthis
) {
2881 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2882 entry_func
= entry_funcs_instance
[sig
->param_count
];
2884 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2886 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2887 entry_func
= entry_funcs_static
[sig
->param_count
];
2889 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2891 g_assert (entry_func
);
2893 /* Encode unbox in the lower bit of imethod */
2894 gpointer entry_arg
= imethod
;
2896 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2897 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2899 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2901 info
= domain_jit_info (domain
);
2902 mono_domain_lock (domain
);
2903 if (!info
->interp_method_pointer_hash
)
2904 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2905 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2906 mono_domain_unlock (domain
);
2908 mono_memory_barrier ();
2910 imethod
->llvmonly_unbox_entry
= addr
;
2912 imethod
->jit_entry
= addr
;
2914 return (MonoFtnDesc
*)addr
;
2918 * interp_create_method_pointer:
2920 * Return a function pointer which can be used to call METHOD using the
2921 * interpreter. Return NULL for methods which are not supported.
2924 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2926 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2927 MonoDomain
*domain
= mono_domain_get ();
2928 MonoJitDomainInfo
*info
;
2929 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2931 if (imethod
->jit_entry
)
2932 return imethod
->jit_entry
;
2934 if (compile
&& !imethod
->transformed
) {
2935 /* Return any errors from method compilation */
2936 mono_interp_transform_method (imethod
, get_context (), error
);
2937 return_val_if_nok (error
, NULL
);
2940 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2941 if (method
->string_ctor
) {
2942 MonoMethodSignature
*newsig
= g_alloca (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
2943 memcpy (newsig
, sig
, mono_metadata_signature_size (sig
));
2944 newsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2948 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2949 entry_func
= (gpointer
)interp_entry_general
;
2950 } else if (sig
->hasthis
) {
2951 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2952 entry_func
= entry_funcs_instance
[sig
->param_count
];
2954 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2956 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2957 entry_func
= entry_funcs_static
[sig
->param_count
];
2959 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2962 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2964 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2965 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
2966 MonoMethod
*orig_method
= info
->d
.native_to_managed
.method
;
2969 * These are called from native code. Ask the host app for a trampoline.
2971 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2972 ftndesc
->addr
= entry_func
;
2973 ftndesc
->arg
= imethod
;
2975 addr
= mono_wasm_get_native_to_interp_trampoline (orig_method
, ftndesc
);
2977 mono_memory_barrier ();
2978 imethod
->jit_entry
= addr
;
2982 #ifdef ENABLE_NETCORE
2984 * The runtime expects a function pointer unique to method and
2985 * the native caller expects a function pointer with the
2986 * right signature, so fail right away.
2988 mono_error_set_platform_not_supported (error
, "No native to managed transitions on this platform.");
2993 return (gpointer
)interp_no_native_to_managed
;
2996 if (mono_llvm_only
) {
2997 /* The caller should call interp_create_method_pointer_llvmonly */
2998 //g_assert_not_reached ();
2999 return (gpointer
)no_llvmonly_interp_method_pointer
;
3002 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
3005 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
3007 * Interp in wrappers get the argument in the rgctx register. If
3008 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
3009 * on that arch the rgctx register is not scratch, so we use a
3010 * separate temp register. We should update the wrappers for this
3011 * if we really care about those architectures (arm).
3013 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
3015 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
3017 if (!entry_wrapper
) {
3018 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
3019 g_assertion_message ("couldn't compile wrapper \"%s\" for \"%s\"",
3020 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
3021 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
3023 mono_error_cleanup (error
);
3024 error_init_reuse (error
);
3025 if (!mono_native_to_interp_trampoline
) {
3026 if (mono_aot_only
) {
3027 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
3029 MonoTrampInfo
*info
;
3030 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
3031 mono_tramp_info_register (info
, NULL
);
3034 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
3035 /* We need the lmf wrapper only when being called from mixed mode */
3037 entry_func
= (gpointer
)interp_entry_from_trampoline
;
3039 static gpointer cached_func
= NULL
;
3041 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
);
3042 mono_memory_barrier ();
3044 entry_func
= cached_func
;
3049 g_assert (entry_func
);
3050 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
3051 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
3052 ftndesc
->addr
= entry_func
;
3053 ftndesc
->arg
= imethod
;
3054 mono_error_assert_ok (error
);
3057 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
3058 * rgctx register using a trampoline.
3061 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
3063 info
= domain_jit_info (domain
);
3064 mono_domain_lock (domain
);
3065 if (!info
->interp_method_pointer_hash
)
3066 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
3067 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
3068 mono_domain_unlock (domain
);
3070 mono_memory_barrier ();
3071 imethod
->jit_entry
= addr
;
3077 interp_free_method (MonoDomain
*domain
, MonoMethod
*method
)
3079 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
3081 mono_domain_jit_code_hash_lock (domain
);
3082 /* InterpMethod is allocated in the domain mempool. We might haven't
3083 * allocated an InterpMethod for this instance yet */
3084 mono_internal_hash_table_remove (&info
->interp_code_hash
, method
);
3085 mono_domain_jit_code_hash_unlock (domain
);
3089 static long opcode_counts
[MINT_LASTOP
];
3091 #define COUNT_OP(op) opcode_counts[op]++
3093 #define COUNT_OP(op)
3097 #define DUMP_INSTR() \
3098 if (tracing > 1) { \
3100 if (sp > frame->stack) { \
3101 ins = dump_stack (frame->stack, sp); \
3103 ins = g_strdup (""); \
3107 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
3108 char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
3109 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
3115 #define DUMP_INSTR()
3118 #define INIT_VTABLE(vtable) do { \
3119 if (G_UNLIKELY (!(vtable)->initialized)) { \
3120 mono_runtime_class_init_full ((vtable), error); \
3121 if (!is_ok (error)) \
3122 THROW_EX (mono_error_convert_to_exception (error), ip); \
3127 mono_interp_new (MonoDomain
* domain
, MonoClass
* klass
)
3130 MonoObject
* const object
= mono_object_new_checked (domain
, klass
, error
);
3131 mono_error_cleanup (error
); // FIXME: do not swallow the error
3136 mono_interp_load_remote_field (
3137 InterpMethod
* imethod
,
3142 g_assert (o
); // Caller checks and throws exception properly.
3145 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3147 #ifndef DISABLE_REMOTING
3149 if (mono_object_is_transparent_proxy (o
)) {
3150 MonoClass
* const klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3152 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3153 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3156 addr
= (char*)o
+ field
->offset
;
3157 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
3161 guchar
* // Return new vt_sp instead of take-address.
3162 mono_interp_load_remote_field_vt (
3163 InterpMethod
* imethod
,
3169 g_assert (o
); // Caller checks and throws exception properly.
3172 MonoClassField
* const field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3173 MonoClass
* klass
= mono_class_from_mono_type_internal (field
->type
);
3174 int const i32
= mono_class_value_size (klass
, NULL
);
3176 #ifndef DISABLE_REMOTING
3178 if (mono_object_is_transparent_proxy (o
)) {
3179 klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3181 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
3182 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3185 addr
= (char*)o
+ field
->offset
;
3186 sp
[-1].data
.p
= vt_sp
;
3187 memcpy (vt_sp
, addr
, i32
);
3188 return vt_sp
+ ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3192 mono_interp_isinst (MonoObject
* object
, MonoClass
* klass
)
3196 MonoClass
*obj_class
= mono_object_class (object
);
3197 // mono_class_is_assignable_from_checked can't handle remoting casts
3198 if (mono_class_is_transparent_proxy (obj_class
))
3199 isinst
= mono_object_isinst_checked (object
, klass
, error
) != NULL
;
3201 mono_class_is_assignable_from_checked (klass
, obj_class
, &isinst
, error
);
3202 mono_error_cleanup (error
); // FIXME: do not swallow the error
3206 static MONO_NEVER_INLINE InterpMethod
*
3207 mono_interp_get_native_func_wrapper (InterpMethod
* imethod
, MonoMethodSignature
* csignature
, guchar
* code
)
3211 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3212 MonoMarshalSpec
** mspecs
= g_newa0 (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3214 MonoMethodPInvoke iinfo
;
3215 memset (&iinfo
, 0, sizeof (iinfo
));
3217 MonoMethod
* m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &iinfo
, mspecs
, code
);
3219 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3221 mono_metadata_free_marshal_spec (mspecs
[i
]);
3223 InterpMethod
*cmethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
3224 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3229 // Do not inline in case order of frame addresses matters.
3230 static MONO_NEVER_INLINE MonoException
*
3231 mono_interp_leave (InterpFrame
* parent_frame
)
3233 InterpFrame frame
= {parent_frame
};
3237 * We need for mono_thread_get_undeniable_exception to be able to unwind
3238 * to check the abort threshold. For this to work we use frame as a
3239 * dummy frame that is stored in the lmf and serves as the transition frame
3241 do_icall_wrapper (&frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
3243 return (MonoException
*)tmp_sp
.data
.p
;
3247 mono_interp_enum_hasflag (stackval
* sp
, MonoClass
* klass
)
3249 guint64 a_val
= 0, b_val
= 0;
3251 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &b_val
, FALSE
);
3252 stackval_to_data (m_class_get_byval_arg (klass
), --sp
, &a_val
, FALSE
);
3253 sp
->data
.i
= (a_val
& b_val
) == b_val
;
3257 mono_interp_box_nullable (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3259 InterpMethod
* const imethod
= frame
->imethod
;
3260 MonoClass
* const c
= (MonoClass
*)imethod
->data_items
[ip
[1]];
3262 int const size
= mono_class_value_size (c
, NULL
);
3264 guint16 offset
= ip
[2];
3265 guint16 pop_vt_sp
= !ip
[3];
3267 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
3268 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3270 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3274 mono_interp_box_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoObjectHandle tmp_handle
)
3276 InterpMethod
* const imethod
= frame
->imethod
;
3278 MonoVTable
* const vtable
= (MonoVTable
*)imethod
->data_items
[ip
[1]];
3279 MonoClass
* const c
= vtable
->klass
;
3281 int const size
= mono_class_value_size (c
, NULL
);
3283 guint16 offset
= ip
[2];
3284 guint16 pop_vt_sp
= !ip
[3];
3286 MonoObject
* o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3287 MONO_HANDLE_ASSIGN_RAW (tmp_handle
, o
);
3288 mono_value_copy_internal (mono_object_get_data (o
), sp
[-1 - offset
].data
.p
, c
);
3289 MONO_HANDLE_ASSIGN_RAW (tmp_handle
, NULL
);
3291 sp
[-1 - offset
].data
.o
= o
;
3292 return pop_vt_sp
? ALIGN_TO (size
, MINT_VT_ALIGNMENT
) : 0;
3296 mono_interp_box (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoObjectHandle tmp_handle
)
3298 MonoVTable
* const vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
3299 guint16
const offset
= ip
[2];
3301 MonoObject
*o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
3302 MONO_HANDLE_ASSIGN_RAW (tmp_handle
, o
);
3303 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (o
), FALSE
);
3304 MONO_HANDLE_ASSIGN_RAW (tmp_handle
, NULL
);
3306 sp
[-1 - offset
].data
.o
= o
;
3310 mono_interp_store_remote_field_vt (InterpFrame
* frame
, const guint16
* ip
, stackval
* sp
, MonoError
* error
)
3312 InterpMethod
* const imethod
= frame
->imethod
;
3313 MonoClassField
*field
;
3315 MonoObject
* const o
= sp
[-2].data
.o
;
3317 field
= (MonoClassField
*)imethod
->data_items
[ip
[1]];
3318 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
3319 int const i32
= mono_class_value_size (klass
, NULL
);
3321 #ifndef DISABLE_REMOTING
3322 if (mono_object_is_transparent_proxy (o
)) {
3323 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3324 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
3325 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3328 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3330 return ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3333 // varargs in wasm consumes extra linear stack per call-site.
3334 // These g_warning/g_error wrappers fix that. It is not the
3335 // small wasm stack, but conserving it is still desirable.
3337 g_warning_d (const char *format
, int d
)
3339 g_warning (format
, d
);
3342 #if !USE_COMPUTED_GOTO
3344 interp_error_xsx (const char *format
, int x1
, const char *s
, int x2
)
3346 g_error (format
, x1
, s
, x2
);
3350 static MONO_ALWAYS_INLINE gboolean
3351 method_entry (ThreadContext
*context
, InterpFrame
*frame
,
3355 MonoException
**out_ex
)
3357 gboolean slow
= FALSE
;
3360 debug_enter (frame
, out_tracing
);
3363 frame
->imethod
->calls
++;
3367 if (!G_UNLIKELY (frame
->imethod
->transformed
)) {
3369 MonoException
*ex
= do_transform_method (frame
, context
);
3373 * Initialize the stack base pointer here, in the uncommon branch, so we don't
3374 * need to check for it everytime when exitting a frame.
3376 frame
->stack
= (stackval
*)context
->stack_pointer
;
3384 /* Save the state of the interpeter main loop into FRAME */
3385 #define SAVE_INTERP_STATE(frame) do { \
3386 frame->state.ip = ip; \
3387 frame->state.sp = sp; \
3388 frame->state.vt_sp = vt_sp; \
3389 frame->state.finally_ips = finally_ips; \
3392 /* Load and clear state from FRAME */
3393 #define LOAD_INTERP_STATE(frame) do { \
3394 ip = frame->state.ip; \
3395 sp = frame->state.sp; \
3396 vt_sp = frame->state.vt_sp; \
3397 finally_ips = frame->state.finally_ips; \
3398 locals = (unsigned char *)frame->stack; \
3399 frame->state.ip = NULL; \
3402 /* Initialize interpreter state for executing FRAME */
3403 #define INIT_INTERP_STATE(frame, _clause_args) do { \
3404 ip = _clause_args ? ((FrameClauseArgs *)_clause_args)->start_with_ip : (frame)->imethod->code; \
3405 locals = (unsigned char *)(frame)->stack; \
3406 vt_sp = (unsigned char *) locals + (frame)->imethod->total_locals_size; \
3407 sp = (stackval*)(vt_sp + (frame)->imethod->vt_stack_size); \
3408 finally_ips = NULL; \
3412 static long total_executed_opcodes
;
3416 * If CLAUSE_ARGS is non-null, start executing from it.
3417 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3418 * to return error information.
3419 * FRAME is only valid until the next call to alloc_frame ().
3421 static MONO_NEVER_INLINE
void
3422 interp_exec_method (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
)
3424 InterpMethod
*cmethod
;
3428 /* Interpreter main loop state (InterpState) */
3429 const guint16
*ip
= NULL
;
3431 unsigned char *vt_sp
;
3432 unsigned char *locals
= NULL
;
3433 GSList
*finally_ips
= NULL
;
3436 int tracing
= global_tracing
;
3437 unsigned char *vtalloc
;
3439 #if USE_COMPUTED_GOTO
3440 static void * const in_labels
[] = {
3441 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3442 #include "mintops.def"
3446 HANDLE_FUNCTION_ENTER ();
3450 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, we cannot rely on
3451 * scanning the stack or any registers. In order to make the code GC safe, every objref
3452 * handled by the code needs to be kept alive and pinned in any of the following ways:
3453 * - the object needs to be stored on the interpreter stack. In order to make sure the
3454 * object actually gets stored on the interp stack and the store is not optimized out,
3455 * the store/variable should be volatile.
3456 * - if the execution of an opcode requires an object not coming from interp stack to be
3457 * kept alive, the tmp_handle below can be used. This handle will keep only one object
3458 * pinned by the GC. Ideally, once this object is no longer needed, the handle should be
3459 * cleared. If we will need to have more objects pinned simultaneously, additional handles
3460 * can be reserved here.
3462 MonoObjectHandle tmp_handle
= MONO_HANDLE_NEW (MonoObject
, NULL
);
3464 if (method_entry (context
, frame
,
3470 THROW_EX (ex
, NULL
);
3471 EXCEPTION_CHECKPOINT
;
3475 context
->stack_pointer
= (guchar
*)frame
->stack
+ frame
->imethod
->alloca_size
;
3476 /* Make sure the stack pointer is bumped before we store any references on the stack */
3477 mono_compiler_barrier ();
3480 INIT_INTERP_STATE (frame
, clause_args
);
3486 if (clause_args
&& clause_args
->filter_exception
) {
3487 sp
->data
.p
= clause_args
->filter_exception
;
3491 #ifdef ENABLE_EXPERIMENT_TIERED
3492 mini_tiered_inc (frame
->imethod
->domain
, frame
->imethod
->method
, &frame
->imethod
->tiered_counter
, 0);
3494 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3496 #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND)
3497 mono_threads_safepoint ();
3501 * using while (ip < end) may result in a 15% performance drop,
3502 * but it may be useful for debug
3506 frame
->imethod
->opcounts
++;
3507 total_executed_opcodes
++;
3510 #ifdef ENABLE_CHECKED_BUILD
3511 guchar
*vt_start
= (guchar
*)frame
->stack
+ frame
->imethod
->total_locals_size
;
3512 guchar
*sp_start
= vt_start
+ frame
->imethod
->vt_stack_size
;
3513 guchar
*sp_end
= sp_start
+ frame
->imethod
->stack_size
;
3514 g_assert (locals
== (guchar
*)frame
->stack
);
3515 g_assert (vt_sp
>= vt_start
);
3516 g_assert (vt_sp
<= sp_start
);
3517 g_assert ((guchar
*)sp
>= sp_start
);
3518 g_assert ((guchar
*)sp
<= sp_end
);
3521 MINT_IN_SWITCH (*ip
) {
3522 MINT_IN_CASE(MINT_INITLOCALS
)
3523 memset (locals
+ ip
[1], 0, ip
[2]);
3526 MINT_IN_CASE(MINT_NOP
)
3527 MINT_IN_CASE(MINT_NIY
)
3528 g_assert_not_reached ();
3530 MINT_IN_CASE(MINT_BREAK
)
3532 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3534 MINT_IN_CASE(MINT_BREAKPOINT
)
3538 MINT_IN_CASE(MINT_LDNULL
)
3543 MINT_IN_CASE(MINT_ARGLIST
)
3546 * We know we have been called by an MINT_CALL_VARARG and the amount of vtstack
3547 * used by the parameters is at ip [-1] (the last argument to MINT_CALL_VARARG that
3548 * is embedded in the instruction stream).
3550 *(gpointer
*)sp
->data
.p
= frame
->parent
->state
.vt_sp
+ frame
->parent
->state
.ip
[-1];
3551 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3555 MINT_IN_CASE(MINT_VTRESULT
) {
3556 int ret_size
= ip
[1];
3557 unsigned char *ret_vt_sp
= vt_sp
;
3558 vt_sp
-= READ32(ip
+ 2);
3560 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3561 sp
[-1].data
.p
= vt_sp
;
3562 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3567 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3568 MINT_IN_CASE(MINT_LDC_I4_M1
)
3571 MINT_IN_CASE(MINT_LDC_I4_0
)
3574 MINT_IN_CASE(MINT_LDC_I4_1
)
3577 MINT_IN_CASE(MINT_LDC_I4_2
)
3580 MINT_IN_CASE(MINT_LDC_I4_3
)
3583 MINT_IN_CASE(MINT_LDC_I4_4
)
3586 MINT_IN_CASE(MINT_LDC_I4_5
)
3589 MINT_IN_CASE(MINT_LDC_I4_6
)
3592 MINT_IN_CASE(MINT_LDC_I4_7
)
3595 MINT_IN_CASE(MINT_LDC_I4_8
)
3598 MINT_IN_CASE(MINT_LDC_I4_S
)
3599 sp
->data
.i
= (short)ip
[1];
3603 MINT_IN_CASE(MINT_LDC_I4
)
3605 sp
->data
.i
= READ32 (ip
);
3609 MINT_IN_CASE(MINT_LDC_I8
)
3611 sp
->data
.l
= READ64 (ip
);
3615 MINT_IN_CASE(MINT_LDC_I8_S
)
3616 sp
->data
.l
= (short)ip
[1];
3620 MINT_IN_CASE(MINT_LDC_R4
) {
3624 sp
->data
.f_r4
= * (float *)&val
;
3629 MINT_IN_CASE(MINT_LDC_R8
)
3630 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3634 MINT_IN_CASE(MINT_DUP
)
3639 MINT_IN_CASE(MINT_DUP_VT
) {
3640 int const i32
= READ32 (ip
+ 1);
3642 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3643 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3648 MINT_IN_CASE(MINT_POP
) {
3653 MINT_IN_CASE(MINT_POP_VT
) {
3654 int i32
= READ32 (ip
+ 1);
3655 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3660 MINT_IN_CASE(MINT_POP1
) {
3666 MINT_IN_CASE(MINT_JMP
) {
3667 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
3668 InterpMethod
*new_method
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3670 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3671 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
3673 if (!new_method
->transformed
) {
3674 error_init_reuse (error
);
3676 mono_interp_transform_method (new_method
, context
, error
);
3677 MonoException
*ex
= mono_error_convert_to_exception (error
);
3680 EXCEPTION_CHECKPOINT
;
3683 * It's possible for the caller stack frame to be smaller
3684 * than the callee stack frame (at the interp level)
3686 context
->stack_pointer
= (guchar
*)frame
->stack
+ new_method
->alloca_size
;
3687 frame
->imethod
= new_method
;
3688 vt_sp
= locals
+ frame
->imethod
->total_locals_size
;
3692 sp
= (stackval
*)(vt_sp
+ frame
->imethod
->vt_stack_size
);
3693 ip
= frame
->imethod
->code
;
3696 MINT_IN_CASE(MINT_CALL_DELEGATE
) {
3697 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3698 int param_count
= csignature
->param_count
;
3699 MonoDelegate
*del
= (MonoDelegate
*) sp
[-param_count
- 1].data
.o
;
3700 gboolean is_multicast
= del
->method
== NULL
;
3701 InterpMethod
*del_imethod
= (InterpMethod
*)del
->interp_invoke_impl
;
3705 error_init_reuse (error
);
3706 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
3707 del_imethod
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
3708 del
->interp_invoke_impl
= del_imethod
;
3709 mono_error_assert_ok (error
);
3710 } else if (!del
->interp_method
) {
3711 // Not created from interpreted code
3712 error_init_reuse (error
);
3713 g_assert (del
->method
);
3714 del_imethod
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
3715 del
->interp_method
= del_imethod
;
3716 del
->interp_invoke_impl
= del_imethod
;
3717 mono_error_assert_ok (error
);
3719 del_imethod
= (InterpMethod
*)del
->interp_method
;
3720 if (del_imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3721 error_init_reuse (error
);
3722 del_imethod
= mono_interp_get_imethod (frame
->imethod
->domain
, mono_marshal_get_native_wrapper (del_imethod
->method
, FALSE
, FALSE
), error
);
3723 mono_error_assert_ok (error
);
3724 del
->interp_invoke_impl
= del_imethod
;
3725 } else if (del_imethod
->method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&& !del
->target
) {
3726 // 'this' is passed dynamically, we need to recompute the target method
3728 del_imethod
= get_virtual_method (del_imethod
, sp
[-param_count
].data
.o
->vtable
);
3730 del
->interp_invoke_impl
= del_imethod
;
3734 cmethod
= del_imethod
;
3736 sp
-= param_count
+ 1;
3737 if (!is_multicast
) {
3738 if (cmethod
->param_count
== param_count
+ 1) {
3739 // Target method is static but the delegate has a target object. We handle
3740 // this separately from the case below, because, for these calls, the instance
3741 // is allowed to be null.
3742 sp
[0].data
.o
= del
->target
;
3743 } else if (del
->target
) {
3744 MonoObject
*this_arg
= del
->target
;
3746 // replace the MonoDelegate* on the stack with 'this' pointer
3747 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3748 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3749 sp
[0].data
.p
= unboxed
;
3751 sp
[0].data
.o
= this_arg
;
3754 // skip the delegate pointer for static calls
3755 // FIXME we could avoid memmove
3756 memmove (sp
, sp
+ 1, param_count
* sizeof (stackval
));
3763 MINT_IN_CASE(MINT_CALLI
) {
3764 MonoMethodSignature
*csignature
;
3766 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3769 cmethod
= (InterpMethod
*)sp
->data
.p
;
3770 if (cmethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3771 cmethod
= mono_interp_get_imethod (frame
->imethod
->domain
, mono_marshal_get_native_wrapper (cmethod
->method
, FALSE
, FALSE
), error
);
3772 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
3775 /* decrement by the actual number of args */
3776 sp
-= csignature
->param_count
;
3777 if (csignature
->hasthis
)
3781 if (csignature
->hasthis
) {
3782 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3784 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3785 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3786 sp
[0].data
.p
= unboxed
;
3793 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3794 gpointer target_ip
= sp
[-1].data
.p
;
3795 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3796 int opcode
= ip
[2];
3797 gboolean save_last_error
= ip
[3];
3800 /* for calls, have ip pointing at the start of next instruction */
3801 frame
->state
.ip
= ip
+ 4;
3803 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3804 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
3805 CHECK_RESUME_STATE (context
);
3809 MINT_IN_CASE(MINT_CALLI_NAT_DYNAMIC
) {
3810 MonoMethodSignature
* csignature
;
3812 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3815 guchar
* code
= (guchar
*)sp
->data
.p
;
3817 /* decrement by the actual number of args */
3818 sp
-= csignature
->param_count
;
3819 if (csignature
->hasthis
)
3823 cmethod
= mono_interp_get_native_func_wrapper (frame
->imethod
, csignature
, code
);
3828 MINT_IN_CASE(MINT_CALLI_NAT
) {
3829 MonoMethodSignature
* csignature
;
3832 csignature
= (MonoMethodSignature
*)frame
->imethod
->data_items
[ip
[1]];
3835 guchar
* const code
= (guchar
*)sp
->data
.p
;
3837 /* decrement by the actual number of args */
3838 sp
-= csignature
->param_count
;
3839 if (csignature
->hasthis
)
3842 /* If this is a vt return, the pinvoke will write the result directly to vt_sp */
3843 retval
.data
.p
= vt_sp
;
3845 gboolean save_last_error
= ip
[4];
3846 gpointer
*cache
= (gpointer
*)&frame
->imethod
->data_items
[ip
[5]];
3847 /* for calls, have ip pointing at the start of next instruction */
3848 frame
->state
.ip
= ip
+ 6;
3849 ves_pinvoke_method (csignature
, (MonoFuncV
)code
, context
, frame
, &retval
, save_last_error
, cache
, sp
);
3851 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
3852 CHECK_RESUME_STATE (context
);
3854 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3862 MINT_IN_CASE(MINT_CALLVIRT_FAST
) {
3863 MonoObject
*this_arg
;
3866 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3867 slot
= (gint16
)ip
[2];
3869 /* decrement by the actual number of args */
3870 sp
-= cmethod
->param_count
+ cmethod
->hasthis
;
3872 this_arg
= (MonoObject
*)sp
->data
.p
;
3875 cmethod
= get_virtual_method_fast (cmethod
, this_arg
->vtable
, slot
);
3876 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (cmethod
->method
->klass
)) {
3878 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3879 sp
[0].data
.p
= unboxed
;
3882 InterpMethodCodeType code_type
= cmethod
->code_type
;
3884 g_assert (code_type
== IMETHOD_CODE_UNKNOWN
||
3885 code_type
== IMETHOD_CODE_INTERP
||
3886 code_type
== IMETHOD_CODE_COMPILED
);
3888 if (G_UNLIKELY (code_type
== IMETHOD_CODE_UNKNOWN
)) {
3889 MonoMethodSignature
*sig
= mono_method_signature_internal (cmethod
->method
);
3890 if (mono_interp_jit_call_supported (cmethod
->method
, sig
))
3891 code_type
= IMETHOD_CODE_COMPILED
;
3893 code_type
= IMETHOD_CODE_INTERP
;
3894 cmethod
->code_type
= code_type
;
3897 if (code_type
== IMETHOD_CODE_INTERP
) {
3901 } else if (code_type
== IMETHOD_CODE_COMPILED
) {
3902 frame
->state
.ip
= ip
;
3903 error_init_reuse (error
);
3904 do_jit_call (sp
, vt_sp
, frame
, cmethod
, error
);
3905 if (!is_ok (error
)) {
3906 MonoException
*ex
= mono_error_convert_to_exception (error
);
3910 CHECK_RESUME_STATE (context
);
3912 if (cmethod
->rtype
->type
!= MONO_TYPE_VOID
) {
3914 vt_sp
+= ((JitCallInfo
*)cmethod
->jit_call_info
)->vt_res_size
;
3920 MINT_IN_CASE(MINT_CALL_VARARG
) {
3921 MonoMethodSignature
*csig
;
3923 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3925 /* The real signature for vararg calls */
3926 csig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
3928 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3929 copy_varargs_vtstack (csig
, sp
, vt_sp
);
3932 /* decrement by the actual number of args */
3933 // FIXME This seems excessive: frame and csig param_count.
3934 sp
-= cmethod
->param_count
+ cmethod
->hasthis
+ csig
->param_count
- csig
->sentinelpos
;
3939 MINT_IN_CASE(MINT_CALLVIRT
) {
3940 // FIXME CALLVIRT opcodes are not used on netcore. We should kill them.
3941 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3943 /* decrement by the actual number of args */
3947 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3949 cmethod
= get_virtual_method (cmethod
, this_arg
->vtable
);
3950 if (m_class_is_valuetype (this_arg
->vtable
->klass
) && m_class_is_valuetype (cmethod
->method
->klass
)) {
3952 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3953 sp
[0].data
.p
= unboxed
;
3956 #ifdef ENABLE_EXPERIMENT_TIERED
3963 MINT_IN_CASE(MINT_CALL
) {
3964 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
3966 /* decrement by the actual number of args */
3970 #ifdef ENABLE_EXPERIMENT_TIERED
3977 * Make a non-recursive call by loading the new interpreter state based on child frame,
3978 * and going back to the main loop.
3980 SAVE_INTERP_STATE (frame
);
3982 // Allocate child frame.
3983 // FIXME: Add stack overflow checks
3985 InterpFrame
*child_frame
= frame
->next_free
;
3987 child_frame
= g_newa0 (InterpFrame
, 1);
3988 // Not free currently, but will be when allocation attempted.
3989 frame
->next_free
= child_frame
;
3991 reinit_frame (child_frame
, frame
, cmethod
, sp
);
3992 frame
= child_frame
;
3994 if (method_entry (context
, frame
,
4000 THROW_EX (ex
, NULL
);
4001 EXCEPTION_CHECKPOINT
;
4004 context
->stack_pointer
= (guchar
*)sp
+ cmethod
->alloca_size
;
4005 /* Make sure the stack pointer is bumped before we store any references on the stack */
4006 mono_compiler_barrier ();
4008 INIT_INTERP_STATE (frame
, NULL
);
4012 MINT_IN_CASE(MINT_JIT_CALL
) {
4013 InterpMethod
*rmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
4014 error_init_reuse (error
);
4015 sp
-= rmethod
->param_count
+ rmethod
->hasthis
;
4017 /* for calls, have ip pointing at the start of next instruction */
4018 frame
->state
.ip
= ip
+ 3;
4019 do_jit_call (sp
, vt_sp
, frame
, rmethod
, error
);
4020 if (!is_ok (error
)) {
4021 MonoException
*ex
= mono_error_convert_to_exception (error
);
4025 CHECK_RESUME_STATE (context
);
4027 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
) {
4029 vt_sp
+= ((JitCallInfo
*)rmethod
->jit_call_info
)->vt_res_size
;
4035 MINT_IN_CASE(MINT_JIT_CALL2
) {
4036 #ifdef ENABLE_EXPERIMENT_TIERED
4037 InterpMethod
*rmethod
= (InterpMethod
*) READ64 (ip
+ 1);
4039 error_init_reuse (error
);
4041 sp
-= rmethod
->param_count
+ rmethod
->hasthis
;
4042 frame
->state
.ip
= ip
+ 5;
4043 do_jit_call (sp
, vt_sp
, frame
, rmethod
, error
);
4044 if (!is_ok (error
)) {
4045 MonoException
*ex
= mono_error_convert_to_exception (error
);
4049 CHECK_RESUME_STATE (context
);
4051 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
4055 g_error ("MINT_JIT_ICALL2 shouldn't be used");
4059 MINT_IN_CASE(MINT_CALLRUN
) {
4060 #ifndef ENABLE_NETCORE
4061 MonoMethod
*target_method
= (MonoMethod
*) frame
->imethod
->data_items
[ip
[1]];
4062 MonoMethodSignature
*sig
= (MonoMethodSignature
*) frame
->imethod
->data_items
[ip
[2]];
4065 stackval
*retval
= sp
;
4067 sp
-= sig
->param_count
;
4071 MonoException
*ex
= ves_imethod (frame
, target_method
, sig
, sp
, retval
);
4075 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
4081 g_assert_not_reached ();
4085 MINT_IN_CASE(MINT_RET
)
4087 if (frame
->parent
) {
4088 frame
->parent
->state
.sp
[0] = *sp
;
4089 frame
->parent
->state
.sp
++;
4091 // FIXME This can only happen in a few wrappers. Add separate opcode for it
4092 *frame
->retval
= *sp
;
4094 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
4096 MINT_IN_CASE(MINT_RET_VOID
)
4097 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
4099 MINT_IN_CASE(MINT_RET_VT
) {
4100 int const i32
= READ32 (ip
+ 1);
4102 if (frame
->parent
) {
4103 gpointer dest_vt
= frame
->parent
->state
.vt_sp
;
4104 // Push the valuetype in the parent frame. parent->state.sp [0] can be inside
4105 // vt to be returned, so we need to copy it before updating sp [0].
4106 memcpy (dest_vt
, sp
->data
.p
, i32
);
4107 frame
->parent
->state
.sp
[0].data
.p
= dest_vt
;
4108 frame
->parent
->state
.sp
++;
4109 frame
->parent
->state
.vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4111 gpointer dest_vt
= frame
->retval
->data
.p
;
4112 memcpy (dest_vt
, sp
->data
.p
, i32
);
4114 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
4117 MINT_IN_CASE(MINT_RET_LOCALLOC
)
4119 if (frame
->parent
) {
4120 frame
->parent
->state
.sp
[0] = *sp
;
4121 frame
->parent
->state
.sp
++;
4123 // FIXME This can only happen in a few wrappers. Add separate opcode for it
4124 *frame
->retval
= *sp
;
4126 frame_data_allocator_pop (&context
->data_stack
, frame
);
4127 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
4129 MINT_IN_CASE(MINT_RET_VOID_LOCALLOC
)
4130 frame_data_allocator_pop (&context
->data_stack
, frame
);
4131 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
4133 MINT_IN_CASE(MINT_RET_VT_LOCALLOC
) {
4134 int const i32
= READ32 (ip
+ 1);
4136 if (frame
->parent
) {
4137 gpointer dest_vt
= frame
->parent
->state
.vt_sp
;
4138 /* Push the valuetype in the parent frame */
4139 memcpy (dest_vt
, sp
->data
.p
, i32
);
4140 frame
->parent
->state
.sp
[0].data
.p
= dest_vt
;
4141 frame
->parent
->state
.sp
++;
4142 frame
->parent
->state
.vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4144 memcpy (frame
->retval
->data
.p
, sp
->data
.p
, i32
);
4146 frame_data_allocator_pop (&context
->data_stack
, frame
);
4147 g_assert_checked (sp
== (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
));
4151 #ifdef ENABLE_EXPERIMENT_TIERED
4152 #define BACK_BRANCH_PROFILE(offset) do { \
4154 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0); \
4157 #define BACK_BRANCH_PROFILE(offset)
4160 MINT_IN_CASE(MINT_BR_S
) {
4161 short br_offset
= (short) *(ip
+ 1);
4162 BACK_BRANCH_PROFILE (br_offset
);
4166 MINT_IN_CASE(MINT_BR
) {
4167 gint32 br_offset
= (gint32
) READ32(ip
+ 1);
4168 BACK_BRANCH_PROFILE (br_offset
);
4173 #define ZEROP_S(datamem, op) \
4175 if (sp->data.datamem op 0) { \
4176 gint16 br_offset = (gint16) ip [1]; \
4177 BACK_BRANCH_PROFILE (br_offset); \
4182 #define ZEROP(datamem, op) \
4184 if (sp->data.datamem op 0) { \
4185 gint32 br_offset = (gint32)READ32(ip + 1); \
4186 BACK_BRANCH_PROFILE (br_offset); \
4191 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
4194 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
4197 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
4200 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
4203 MINT_IN_CASE(MINT_BRFALSE_I4
)
4206 MINT_IN_CASE(MINT_BRFALSE_I8
)
4209 MINT_IN_CASE(MINT_BRFALSE_R4
)
4212 MINT_IN_CASE(MINT_BRFALSE_R8
)
4215 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
4218 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
4221 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
4224 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
4227 MINT_IN_CASE(MINT_BRTRUE_I4
)
4230 MINT_IN_CASE(MINT_BRTRUE_I8
)
4233 MINT_IN_CASE(MINT_BRTRUE_R4
)
4236 MINT_IN_CASE(MINT_BRTRUE_R8
)
4239 #define CONDBR_S(cond) \
4242 gint16 br_offset = (gint16) ip [1]; \
4243 BACK_BRANCH_PROFILE (br_offset); \
4247 #define BRELOP_S(datamem, op) \
4248 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
4250 #define CONDBR(cond) \
4253 gint32 br_offset = (gint32) READ32 (ip + 1); \
4254 BACK_BRANCH_PROFILE (br_offset); \
4259 #define BRELOP(datamem, op) \
4260 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
4262 MINT_IN_CASE(MINT_BEQ_I4_S
)
4265 MINT_IN_CASE(MINT_BEQ_I8_S
)
4268 MINT_IN_CASE(MINT_BEQ_R4_S
)
4269 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
4271 MINT_IN_CASE(MINT_BEQ_R8_S
)
4272 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
4274 MINT_IN_CASE(MINT_BEQ_I4
)
4277 MINT_IN_CASE(MINT_BEQ_I8
)
4280 MINT_IN_CASE(MINT_BEQ_R4
)
4281 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
4283 MINT_IN_CASE(MINT_BEQ_R8
)
4284 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
4286 MINT_IN_CASE(MINT_BGE_I4_S
)
4289 MINT_IN_CASE(MINT_BGE_I8_S
)
4292 MINT_IN_CASE(MINT_BGE_R4_S
)
4293 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4295 MINT_IN_CASE(MINT_BGE_R8_S
)
4296 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
4298 MINT_IN_CASE(MINT_BGE_I4
)
4301 MINT_IN_CASE(MINT_BGE_I8
)
4304 MINT_IN_CASE(MINT_BGE_R4
)
4305 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4307 MINT_IN_CASE(MINT_BGE_R8
)
4308 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
4310 MINT_IN_CASE(MINT_BGT_I4_S
)
4313 MINT_IN_CASE(MINT_BGT_I8_S
)
4316 MINT_IN_CASE(MINT_BGT_R4_S
)
4317 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4319 MINT_IN_CASE(MINT_BGT_R8_S
)
4320 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
4322 MINT_IN_CASE(MINT_BGT_I4
)
4325 MINT_IN_CASE(MINT_BGT_I8
)
4328 MINT_IN_CASE(MINT_BGT_R4
)
4329 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4331 MINT_IN_CASE(MINT_BGT_R8
)
4332 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
4334 MINT_IN_CASE(MINT_BLT_I4_S
)
4337 MINT_IN_CASE(MINT_BLT_I8_S
)
4340 MINT_IN_CASE(MINT_BLT_R4_S
)
4341 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4343 MINT_IN_CASE(MINT_BLT_R8_S
)
4344 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
4346 MINT_IN_CASE(MINT_BLT_I4
)
4349 MINT_IN_CASE(MINT_BLT_I8
)
4352 MINT_IN_CASE(MINT_BLT_R4
)
4353 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4355 MINT_IN_CASE(MINT_BLT_R8
)
4356 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
4358 MINT_IN_CASE(MINT_BLE_I4_S
)
4361 MINT_IN_CASE(MINT_BLE_I8_S
)
4364 MINT_IN_CASE(MINT_BLE_R4_S
)
4365 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4367 MINT_IN_CASE(MINT_BLE_R8_S
)
4368 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
4370 MINT_IN_CASE(MINT_BLE_I4
)
4373 MINT_IN_CASE(MINT_BLE_I8
)
4376 MINT_IN_CASE(MINT_BLE_R4
)
4377 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4379 MINT_IN_CASE(MINT_BLE_R8
)
4380 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
4382 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
4385 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
4388 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
4389 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
4391 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
4392 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
4394 MINT_IN_CASE(MINT_BNE_UN_I4
)
4397 MINT_IN_CASE(MINT_BNE_UN_I8
)
4400 MINT_IN_CASE(MINT_BNE_UN_R4
)
4401 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
4403 MINT_IN_CASE(MINT_BNE_UN_R8
)
4404 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
4407 #define BRELOP_S_CAST(datamem, op, type) \
4409 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4410 gint16 br_offset = (gint16) ip [1]; \
4411 BACK_BRANCH_PROFILE (br_offset); \
4416 #define BRELOP_CAST(datamem, op, type) \
4418 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4419 gint32 br_offset = (gint32) ip [1]; \
4420 BACK_BRANCH_PROFILE (br_offset); \
4425 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
4426 BRELOP_S_CAST(i
, >=, guint32
);
4428 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
4429 BRELOP_S_CAST(l
, >=, guint64
);
4431 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
4432 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4434 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
4435 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4437 MINT_IN_CASE(MINT_BGE_UN_I4
)
4438 BRELOP_CAST(i
, >=, guint32
);
4440 MINT_IN_CASE(MINT_BGE_UN_I8
)
4441 BRELOP_CAST(l
, >=, guint64
);
4443 MINT_IN_CASE(MINT_BGE_UN_R4
)
4444 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
4446 MINT_IN_CASE(MINT_BGE_UN_R8
)
4447 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
4449 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
4450 BRELOP_S_CAST(i
, >, guint32
);
4452 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
4453 BRELOP_S_CAST(l
, >, guint64
);
4455 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
4456 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4458 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
4459 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4461 MINT_IN_CASE(MINT_BGT_UN_I4
)
4462 BRELOP_CAST(i
, >, guint32
);
4464 MINT_IN_CASE(MINT_BGT_UN_I8
)
4465 BRELOP_CAST(l
, >, guint64
);
4467 MINT_IN_CASE(MINT_BGT_UN_R4
)
4468 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
4470 MINT_IN_CASE(MINT_BGT_UN_R8
)
4471 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
4473 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
4474 BRELOP_S_CAST(i
, <=, guint32
);
4476 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
4477 BRELOP_S_CAST(l
, <=, guint64
);
4479 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
4480 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4482 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
4483 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4485 MINT_IN_CASE(MINT_BLE_UN_I4
)
4486 BRELOP_CAST(i
, <=, guint32
);
4488 MINT_IN_CASE(MINT_BLE_UN_I8
)
4489 BRELOP_CAST(l
, <=, guint64
);
4491 MINT_IN_CASE(MINT_BLE_UN_R4
)
4492 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
4494 MINT_IN_CASE(MINT_BLE_UN_R8
)
4495 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
4497 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
4498 BRELOP_S_CAST(i
, <, guint32
);
4500 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
4501 BRELOP_S_CAST(l
, <, guint64
);
4503 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
4504 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4506 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
4507 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4509 MINT_IN_CASE(MINT_BLT_UN_I4
)
4510 BRELOP_CAST(i
, <, guint32
);
4512 MINT_IN_CASE(MINT_BLT_UN_I8
)
4513 BRELOP_CAST(l
, <, guint64
);
4515 MINT_IN_CASE(MINT_BLT_UN_R4
)
4516 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
4518 MINT_IN_CASE(MINT_BLT_UN_R8
)
4519 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
4521 MINT_IN_CASE(MINT_SWITCH
) {
4523 const unsigned short *st
;
4529 if ((guint32
)sp
->data
.i
< n
) {
4531 ip
+= 2 * (guint32
)sp
->data
.i
;
4532 offset
= READ32 (ip
);
4539 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
4540 NULL_CHECK (sp
[-1].data
.p
);
4542 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
4544 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
4545 NULL_CHECK (sp
[-1].data
.p
);
4547 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
4549 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
4550 NULL_CHECK (sp
[-1].data
.p
);
4552 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
4554 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
4555 NULL_CHECK (sp
[-1].data
.p
);
4557 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
4559 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
4560 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
4561 NULL_CHECK (sp
[-1].data
.p
);
4563 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
4565 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
4566 NULL_CHECK (sp
[-1].data
.p
);
4568 #ifdef NO_UNALIGNED_ACCESS
4569 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4570 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
4573 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
4575 MINT_IN_CASE(MINT_LDIND_I
) {
4576 guint16 offset
= ip
[1];
4577 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
4581 MINT_IN_CASE(MINT_LDIND_I8
) {
4582 guint16 offset
= ip
[1];
4583 #ifdef NO_UNALIGNED_ACCESS
4584 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
4585 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
4588 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
4592 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
4593 NULL_CHECK (sp
[-1].data
.p
);
4595 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
4597 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
4598 NULL_CHECK (sp
[-1].data
.p
);
4600 #ifdef NO_UNALIGNED_ACCESS
4601 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
4602 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
4605 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
4607 MINT_IN_CASE(MINT_LDIND_REF
)
4609 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4611 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
4612 NULL_CHECK (sp
[-1].data
.p
);
4614 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
4617 MINT_IN_CASE(MINT_STIND_REF
)
4618 NULL_CHECK (sp
[-2].data
.p
);
4621 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
4623 MINT_IN_CASE(MINT_STIND_I1
)
4624 NULL_CHECK (sp
[-2].data
.p
);
4627 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
4629 MINT_IN_CASE(MINT_STIND_I2
)
4630 NULL_CHECK (sp
[-2].data
.p
);
4633 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
4635 MINT_IN_CASE(MINT_STIND_I4
)
4636 NULL_CHECK (sp
[-2].data
.p
);
4639 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
4641 MINT_IN_CASE(MINT_STIND_I
)
4642 NULL_CHECK (sp
[-2].data
.p
);
4645 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
4647 MINT_IN_CASE(MINT_STIND_I8
)
4648 NULL_CHECK (sp
[-2].data
.p
);
4651 #ifdef NO_UNALIGNED_ACCESS
4652 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4653 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
4656 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
4658 MINT_IN_CASE(MINT_STIND_R4
)
4659 NULL_CHECK (sp
[-2].data
.p
);
4662 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
4664 MINT_IN_CASE(MINT_STIND_R8
)
4665 NULL_CHECK (sp
[-2].data
.p
);
4668 #ifdef NO_UNALIGNED_ACCESS
4669 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
4670 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
4673 * (double *) sp
->data
.p
= sp
[1].data
.f
;
4675 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
4678 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
4680 #define BINOP(datamem, op) \
4682 sp [-1].data.datamem op ## = sp [0].data.datamem; \
4684 MINT_IN_CASE(MINT_ADD_I4
)
4687 MINT_IN_CASE(MINT_ADD_I8
)
4690 MINT_IN_CASE(MINT_ADD_R4
)
4693 MINT_IN_CASE(MINT_ADD_R8
)
4696 MINT_IN_CASE(MINT_ADD1_I4
)
4700 MINT_IN_CASE(MINT_ADD1_I8
)
4704 MINT_IN_CASE(MINT_LOCADD1_I4
)
4705 *(gint32
*)(locals
+ ip
[1]) += 1;
4708 MINT_IN_CASE(MINT_LOCADD1_I8
)
4709 *(gint64
*)(locals
+ ip
[1]) += 1;
4712 MINT_IN_CASE(MINT_SUB_I4
)
4715 MINT_IN_CASE(MINT_SUB_I8
)
4718 MINT_IN_CASE(MINT_SUB_R4
)
4721 MINT_IN_CASE(MINT_SUB_R8
)
4724 MINT_IN_CASE(MINT_SUB1_I4
)
4728 MINT_IN_CASE(MINT_SUB1_I8
)
4732 MINT_IN_CASE(MINT_LOCSUB1_I4
)
4733 *(gint32
*)(locals
+ ip
[1]) -= 1;
4736 MINT_IN_CASE(MINT_LOCSUB1_I8
)
4737 *(gint64
*)(locals
+ ip
[1]) -= 1;
4739 MINT_IN_CASE(MINT_MUL_I4
)
4742 MINT_IN_CASE(MINT_MUL_I8
)
4745 MINT_IN_CASE(MINT_MUL_R4
)
4748 MINT_IN_CASE(MINT_MUL_R8
)
4751 MINT_IN_CASE(MINT_DIV_I4
) {
4752 gint32 l1
= sp
[-1].data
.i
;
4753 gint32 l2
= sp
[-2].data
.i
;
4755 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4756 if (l1
== (-1) && l2
== G_MININT32
)
4757 THROW_EX (mono_get_exception_overflow (), ip
);
4761 MINT_IN_CASE(MINT_DIV_I8
) {
4762 gint64 l1
= sp
[-1].data
.l
;
4763 gint64 l2
= sp
[-2].data
.l
;
4765 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4766 if (l1
== (-1) && l2
== G_MININT64
)
4767 THROW_EX (mono_get_exception_overflow (), ip
);
4771 MINT_IN_CASE(MINT_DIV_R4
)
4774 MINT_IN_CASE(MINT_DIV_R8
)
4778 #define BINOP_CAST(datamem, op, type) \
4780 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4782 MINT_IN_CASE(MINT_DIV_UN_I4
)
4783 if (sp
[-1].data
.i
== 0)
4784 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4785 BINOP_CAST(i
, /, guint32
);
4787 MINT_IN_CASE(MINT_DIV_UN_I8
)
4788 if (sp
[-1].data
.l
== 0)
4789 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4790 BINOP_CAST(l
, /, guint64
);
4792 MINT_IN_CASE(MINT_REM_I4
) {
4793 int i1
= sp
[-1].data
.i
;
4794 int i2
= sp
[-2].data
.i
;
4796 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4797 if (i1
== (-1) && i2
== G_MININT32
)
4798 THROW_EX (mono_get_exception_overflow (), ip
);
4802 MINT_IN_CASE(MINT_REM_I8
) {
4803 gint64 l1
= sp
[-1].data
.l
;
4804 gint64 l2
= sp
[-2].data
.l
;
4806 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4807 if (l1
== (-1) && l2
== G_MININT64
)
4808 THROW_EX (mono_get_exception_overflow (), ip
);
4812 MINT_IN_CASE(MINT_REM_R4
)
4813 /* FIXME: what do we actually do here? */
4815 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4818 MINT_IN_CASE(MINT_REM_R8
)
4819 /* FIXME: what do we actually do here? */
4821 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4824 MINT_IN_CASE(MINT_REM_UN_I4
)
4825 if (sp
[-1].data
.i
== 0)
4826 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4827 BINOP_CAST(i
, %, guint32
);
4829 MINT_IN_CASE(MINT_REM_UN_I8
)
4830 if (sp
[-1].data
.l
== 0)
4831 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4832 BINOP_CAST(l
, %, guint64
);
4834 MINT_IN_CASE(MINT_AND_I4
)
4837 MINT_IN_CASE(MINT_AND_I8
)
4840 MINT_IN_CASE(MINT_OR_I4
)
4843 MINT_IN_CASE(MINT_OR_I8
)
4846 MINT_IN_CASE(MINT_XOR_I4
)
4849 MINT_IN_CASE(MINT_XOR_I8
)
4853 #define SHIFTOP(datamem, op) \
4855 sp [-1].data.datamem op ## = sp [0].data.i; \
4858 MINT_IN_CASE(MINT_SHL_I4
)
4861 MINT_IN_CASE(MINT_SHL_I8
)
4864 MINT_IN_CASE(MINT_SHR_I4
)
4867 MINT_IN_CASE(MINT_SHR_I8
)
4870 MINT_IN_CASE(MINT_SHR_UN_I4
)
4872 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4875 MINT_IN_CASE(MINT_SHR_UN_I8
)
4877 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4880 MINT_IN_CASE(MINT_NEG_I4
)
4881 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4884 MINT_IN_CASE(MINT_NEG_I8
)
4885 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4888 MINT_IN_CASE(MINT_NEG_R4
)
4889 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4892 MINT_IN_CASE(MINT_NEG_R8
)
4893 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4896 MINT_IN_CASE(MINT_NOT_I4
)
4897 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4900 MINT_IN_CASE(MINT_NOT_I8
)
4901 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4904 MINT_IN_CASE(MINT_CONV_I1_I4
)
4905 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4908 MINT_IN_CASE(MINT_CONV_I1_I8
)
4909 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4912 MINT_IN_CASE(MINT_CONV_I1_R4
)
4913 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4916 MINT_IN_CASE(MINT_CONV_I1_R8
)
4917 /* without gint32 cast, C compiler is allowed to use undefined
4918 * behaviour if data.f is bigger than >255. See conv.fpint section
4920 * > The conversion truncates; that is, the fractional part
4921 * > is discarded. The behavior is undefined if the truncated
4922 * > value cannot be represented in the destination type.
4924 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4927 MINT_IN_CASE(MINT_CONV_U1_I4
)
4928 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4931 MINT_IN_CASE(MINT_CONV_U1_I8
)
4932 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4935 MINT_IN_CASE(MINT_CONV_U1_R4
)
4936 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4939 MINT_IN_CASE(MINT_CONV_U1_R8
)
4940 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4943 MINT_IN_CASE(MINT_CONV_I2_I4
)
4944 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4947 MINT_IN_CASE(MINT_CONV_I2_I8
)
4948 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4951 MINT_IN_CASE(MINT_CONV_I2_R4
)
4952 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4955 MINT_IN_CASE(MINT_CONV_I2_R8
)
4956 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4959 MINT_IN_CASE(MINT_CONV_U2_I4
)
4960 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4963 MINT_IN_CASE(MINT_CONV_U2_I8
)
4964 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4967 MINT_IN_CASE(MINT_CONV_U2_R4
)
4968 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4971 MINT_IN_CASE(MINT_CONV_U2_R8
)
4972 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4975 MINT_IN_CASE(MINT_CONV_I4_R4
)
4976 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4979 MINT_IN_CASE(MINT_CONV_I4_R8
)
4980 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4983 MINT_IN_CASE(MINT_CONV_U4_I8
)
4984 MINT_IN_CASE(MINT_CONV_I4_I8
)
4985 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4988 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4989 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4992 MINT_IN_CASE(MINT_CONV_U4_R4
)
4993 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4994 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4996 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5000 MINT_IN_CASE(MINT_CONV_U4_R8
)
5001 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
5002 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
5004 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5008 MINT_IN_CASE(MINT_CONV_I8_I4
)
5009 sp
[-1].data
.l
= sp
[-1].data
.i
;
5012 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
5013 sp
[-2].data
.l
= sp
[-2].data
.i
;
5016 MINT_IN_CASE(MINT_CONV_I8_U4
)
5017 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
5020 MINT_IN_CASE(MINT_CONV_I8_R4
)
5021 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
5024 MINT_IN_CASE(MINT_CONV_I8_R8
)
5025 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5028 MINT_IN_CASE(MINT_CONV_R4_I4
)
5029 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
5032 MINT_IN_CASE(MINT_CONV_R4_I8
)
5033 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
5036 MINT_IN_CASE(MINT_CONV_R4_R8
)
5037 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
5040 MINT_IN_CASE(MINT_CONV_R8_I4
)
5041 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
5044 MINT_IN_CASE(MINT_CONV_R8_I8
)
5045 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
5048 MINT_IN_CASE(MINT_CONV_R8_R4
)
5049 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
5052 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
5053 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
5056 MINT_IN_CASE(MINT_CONV_U8_R4
)
5057 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
5058 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
5060 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
5064 MINT_IN_CASE(MINT_CONV_U8_R8
)
5065 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
5066 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
5068 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5072 MINT_IN_CASE(MINT_CPOBJ
) {
5073 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5074 g_assert (m_class_is_valuetype (c
));
5075 /* if this assertion fails, we need to add a write barrier */
5076 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
5077 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
5082 MINT_IN_CASE(MINT_CPOBJ_VT
) {
5083 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5084 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
5089 MINT_IN_CASE(MINT_LDOBJ_VT
) {
5090 int size
= READ32(ip
+ 1);
5092 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
5093 sp
[-1].data
.p
= vt_sp
;
5094 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5097 MINT_IN_CASE(MINT_LDSTR
)
5098 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
5102 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
5103 MonoString
*s
= NULL
;
5104 guint32 strtoken
= (guint32
)(gsize
)frame
->imethod
->data_items
[ip
[1]];
5106 MonoMethod
*method
= frame
->imethod
->method
;
5107 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
5108 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
5109 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
5110 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
5112 g_assert_not_reached ();
5119 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
5120 MonoClass
*newobj_class
;
5121 guint32 token
= ip
[1];
5122 guint16 param_count
= ip
[2];
5124 newobj_class
= (MonoClass
*) frame
->imethod
->data_items
[token
];
5127 sp
->data
.o
= ves_array_create (frame
->imethod
->domain
, newobj_class
, param_count
, sp
, error
);
5129 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5135 MINT_IN_CASE(MINT_NEWOBJ_STRING
) {
5136 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
5138 const int param_count
= ip
[2];
5141 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
5143 // `this` is implicit null. The created string will be returned
5144 // by the call, even though the call has void return (?!).
5149 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
5150 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[3]];
5151 INIT_VTABLE (vtable
);
5152 guint16 param_count
;
5153 guint16 imethod_index
= ip
[1];
5155 const gboolean is_inlined
= imethod_index
== INLINED_METHOD_FLAG
;
5157 param_count
= ip
[2];
5159 // Make room for two copies of o -- this parameter and return value.
5160 if (param_count
|| !is_inlined
) {
5162 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
5165 MonoObject
*o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5166 if (G_UNLIKELY (!o
)) {
5167 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
5168 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5171 // Store o next to and before the parameters on the stack so GC will see it,
5172 // and where it is needed when the call returns.
5177 sp
+= param_count
+ 2;
5179 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[imethod_index
];
5186 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
5187 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
5188 guint16 imethod_index
= ip
[1];
5189 gboolean is_inlined
= imethod_index
== INLINED_METHOD_FLAG
;
5191 guint16
const param_count
= ip
[2];
5193 // Make room for extra parameter and result.
5196 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
5199 gboolean
const vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
5201 memset (vt_sp
, 0, ip
[3]);
5203 // Put extra parameter and result on stack, before other parameters,
5204 // and point stack to extra parameter, after result.
5205 // This pattern occurs for newobj_vt_fast and newobj_fast.
5206 sp
[1].data
.p
= vt_sp
;
5207 sp
[0].data
.p
= vt_sp
;
5210 // Like newobj_fast, add valuetype_this parameter
5211 // and result and point stack to this after result.
5212 memset (sp
, 0, sizeof (*sp
));
5213 sp
[1].data
.p
= &sp
[0].data
; // valuetype_this == result
5218 vt_sp
+= ALIGN_TO (ip
[-1], MINT_VT_ALIGNMENT
);
5219 sp
+= param_count
+ 2;
5222 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[imethod_index
];
5224 // call_newobj captures the pattern where the return value is placed
5225 // on the stack before the call, instead of the call forming it.
5227 ++sp
; // Point sp at added extra param, after return value.
5230 MINT_IN_CASE(MINT_NEWOBJ
) {
5231 guint32
const token
= ip
[1];
5233 cmethod
= (InterpMethod
*)frame
->imethod
->data_items
[token
];
5235 MonoMethodSignature
* const csig
= mono_method_signature_internal (cmethod
->method
);
5237 g_assert (csig
->hasthis
);
5239 // Make room for first parameter and return value.
5240 const int param_count
= csig
->param_count
;
5243 memmove (sp
+ 2, sp
, param_count
* sizeof (stackval
));
5246 MonoClass
* const newobj_class
= cmethod
->method
->klass
;
5248 /*if (profiling_classes) {
5249 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
5251 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
5255 * First arg is the object.
5256 * a constructor returns void, but we need to return the object we created
5259 g_assert (!m_class_is_valuetype (newobj_class
));
5261 MonoDomain
* const domain
= frame
->imethod
->domain
;
5262 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, newobj_class
, error
);
5263 if (!is_ok (error
) || !mono_runtime_class_init_full (vtable
, error
)) {
5264 MonoException
*exc
= mono_error_convert_to_exception (error
);
5268 error_init_reuse (error
);
5269 MonoObject
* o
= mono_object_new_checked (domain
, newobj_class
, error
);
5270 sp
[0].data
.o
= o
; // return value
5271 sp
[1].data
.o
= o
; // first parameter
5273 mono_error_cleanup (error
); // FIXME: do not swallow the error
5274 error_init_reuse (error
);
5275 EXCEPTION_CHECKPOINT
;
5276 #ifndef DISABLE_REMOTING
5277 if (mono_object_is_transparent_proxy (o
)) {
5278 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (cmethod
->method
, error
);
5279 mono_error_assert_ok (error
);
5280 cmethod
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
5281 mono_error_assert_ok (error
);
5287 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
5292 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
5293 gpointer arg0
= sp
[-1].data
.p
;
5294 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
5295 *byreference_this
= arg0
;
5297 sp
[-1].data
.p
= vt_sp
;
5298 vt_sp
+= MINT_VT_ALIGNMENT
;
5302 MINT_IN_CASE(MINT_INTRINS_SPAN_CTOR
) {
5303 gpointer ptr
= sp
[-2].data
.p
;
5304 int len
= sp
[-1].data
.i
;
5306 THROW_EX (mono_get_exception_argument_out_of_range ("length"), ip
);
5307 *(gpointer
*)vt_sp
= ptr
;
5308 *(gint32
*)((gpointer
*)vt_sp
+ 1) = len
;
5309 sp
[-2].data
.p
= vt_sp
;
5310 #if SIZEOF_VOID_P == 8
5311 vt_sp
+= ALIGN_TO (12, MINT_VT_ALIGNMENT
);
5313 vt_sp
+= ALIGN_TO (8, MINT_VT_ALIGNMENT
);
5319 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
5320 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
5321 sp
[-1].data
.p
= *byreference_this
;
5325 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
5327 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
5332 MINT_IN_CASE(MINT_INTRINS_CLEAR_WITH_REFERENCES
) {
5334 gpointer p
= sp
[0].data
.p
;
5335 size_t size
= sp
[1].data
.nati
* sizeof (gpointer
);
5336 mono_gc_bzero_aligned (p
, size
);
5340 MINT_IN_CASE(MINT_INTRINS_MARVIN_BLOCK
) {
5342 interp_intrins_marvin_block ((guint32
*)sp
[0].data
.p
, (guint32
*)sp
[1].data
.p
);
5346 MINT_IN_CASE(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE
) {
5347 sp
[-1].data
.i
= interp_intrins_ascii_chars_to_uppercase ((guint32
)sp
[-1].data
.i
);
5351 MINT_IN_CASE(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF
) {
5352 MonoObject
* const o
= sp
[-1].data
.o
;
5354 sp
[-1].data
.p
= (guint8
*)o
+ MONO_STRUCT_OFFSET (MonoArray
, vector
);
5358 MINT_IN_CASE(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII
) {
5360 sp
[-1].data
.i
= interp_intrins_ordinal_ignore_case_ascii ((guint32
)sp
[-1].data
.i
, (guint32
)sp
[0].data
.i
);
5364 MINT_IN_CASE(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII
) {
5366 sp
[-1].data
.i
= interp_intrins_64ordinal_ignore_case_ascii ((guint64
)sp
[-1].data
.l
, (guint64
)sp
[0].data
.l
);
5370 MINT_IN_CASE(MINT_INTRINS_U32_TO_DECSTR
) {
5371 MonoArray
**cache_addr
= (MonoArray
**)frame
->imethod
->data_items
[ip
[1]];
5372 MonoVTable
*string_vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[2]];
5373 sp
[-1].data
.o
= (MonoObject
*)interp_intrins_u32_to_decstr ((guint32
)sp
[-1].data
.i
, *cache_addr
, string_vtable
);
5377 MINT_IN_CASE(MINT_INTRINS_WIDEN_ASCII_TO_UTF16
) {
5379 sp
[-1].data
.nati
= interp_intrins_widen_ascii_to_utf16 ((guint8
*)sp
[-1].data
.p
, (mono_unichar2
*)sp
[0].data
.p
, sp
[1].data
.nati
);
5383 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
5385 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
5390 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
5391 MonoObject
*obj
= sp
[-1].data
.o
;
5392 sp
[-1].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
5396 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
5397 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
5398 MonoObject
* const o
= sp
[-1].data
.o
;
5400 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5402 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
5404 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
5406 isinst
= mono_interp_isinst (o
, c
); // FIXME: do not swallow the error
5412 gboolean
const isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
5414 sp
[-1].data
.p
= NULL
;
5416 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5422 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
5423 MINT_IN_CASE(MINT_ISINST_COMMON
) {
5424 MonoObject
* const o
= sp
[-1].data
.o
;
5426 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5427 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
5430 gboolean
const isinst_instr
= *ip
== MINT_ISINST_COMMON
;
5432 sp
[-1].data
.p
= NULL
;
5434 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5440 MINT_IN_CASE(MINT_CASTCLASS
)
5441 MINT_IN_CASE(MINT_ISINST
) {
5442 MonoObject
* const o
= sp
[-1].data
.o
;
5444 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5445 if (!mono_interp_isinst (o
, c
)) { // FIXME: do not swallow the error
5446 gboolean
const isinst_instr
= *ip
== MINT_ISINST
;
5448 sp
[-1].data
.p
= NULL
;
5450 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5456 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
5457 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
5460 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
5461 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
5464 MINT_IN_CASE(MINT_UNBOX
) {
5465 MonoObject
* const o
= sp
[-1].data
.o
;
5467 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5469 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
5470 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5472 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
5476 MINT_IN_CASE(MINT_THROW
)
5479 sp
->data
.p
= mono_get_exception_null_reference ();
5481 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
5483 MINT_IN_CASE(MINT_CHECKPOINT
)
5484 /* Do synchronous checking of abort requests */
5485 EXCEPTION_CHECKPOINT
;
5488 MINT_IN_CASE(MINT_SAFEPOINT
)
5489 /* Do synchronous checking of abort requests */
5490 EXCEPTION_CHECKPOINT
;
5491 /* Poll safepoint */
5492 mono_threads_safepoint ();
5495 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
) {
5496 sp
[-1].data
.p
= (char*)sp
[-1].data
.o
+ ip
[1];
5500 MINT_IN_CASE(MINT_LDFLDA
) {
5501 MonoObject
* const o
= sp
[-1].data
.o
;
5503 sp
[-1].data
.p
= (char *)o
+ ip
[1];
5507 MINT_IN_CASE(MINT_CKNULL_N
) {
5508 /* Same as CKNULL, but further down the stack */
5509 int const n
= ip
[1];
5510 MonoObject
* const o
= sp
[-n
].data
.o
;
5516 #define LDFLD_VT_UNALIGNED(datamem, fieldtype, unaligned) do { \
5517 gpointer p = sp [-1].data.p; \
5520 memcpy (&sp[-1].data.datamem, (char *)p + ip [1], sizeof (fieldtype)); \
5522 sp [-1].data.datamem = * (fieldtype *)((char *)p + ip [1]); \
5526 #define LDFLD_VT(datamem, fieldtype) LDFLD_VT_UNALIGNED(datamem, fieldtype, FALSE)
5528 MINT_IN_CASE(MINT_LDFLD_VT_I1
) LDFLD_VT(i
, gint8
); MINT_IN_BREAK
;
5529 MINT_IN_CASE(MINT_LDFLD_VT_U1
) LDFLD_VT(i
, guint8
); MINT_IN_BREAK
;
5530 MINT_IN_CASE(MINT_LDFLD_VT_I2
) LDFLD_VT(i
, gint16
); MINT_IN_BREAK
;
5531 MINT_IN_CASE(MINT_LDFLD_VT_U2
) LDFLD_VT(i
, guint16
); MINT_IN_BREAK
;
5532 MINT_IN_CASE(MINT_LDFLD_VT_I4
) LDFLD_VT(i
, gint32
); MINT_IN_BREAK
;
5533 MINT_IN_CASE(MINT_LDFLD_VT_I8
) LDFLD_VT(l
, gint64
); MINT_IN_BREAK
;
5534 MINT_IN_CASE(MINT_LDFLD_VT_R4
) LDFLD_VT(f_r4
, float); MINT_IN_BREAK
;
5535 MINT_IN_CASE(MINT_LDFLD_VT_R8
) LDFLD_VT(f
, double); MINT_IN_BREAK
;
5536 MINT_IN_CASE(MINT_LDFLD_VT_O
) LDFLD_VT(p
, gpointer
); MINT_IN_BREAK
;
5537 MINT_IN_CASE(MINT_LDFLD_VT_I8_UNALIGNED
) LDFLD_VT_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5538 MINT_IN_CASE(MINT_LDFLD_VT_R8_UNALIGNED
) LDFLD_VT_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5540 MINT_IN_CASE(MINT_LDFLD_VT_VT
) {
5541 gpointer p
= sp
[-1].data
.p
;
5544 sp
[-1].data
.p
= vt_sp
;
5545 memmove (vt_sp
, (char *)p
+ ip
[1], ip
[3]);
5551 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5552 MonoObject* const o = sp [-1].data.o; \
5555 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
5557 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
5561 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
5563 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
5564 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
5565 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
5566 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
5567 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
5568 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
5569 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
5570 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
5571 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
5572 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5573 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5575 MINT_IN_CASE(MINT_LDFLD_VT
) {
5576 MonoObject
* const o
= sp
[-1].data
.o
;
5579 int size
= READ32(ip
+ 2);
5580 sp
[-1].data
.p
= vt_sp
;
5581 memcpy (sp
[-1].data
.p
, (char *)o
+ ip
[1], size
);
5582 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5587 MINT_IN_CASE(MINT_LDRMFLD
) {
5588 MonoObject
* const o
= sp
[-1].data
.o
;
5590 mono_interp_load_remote_field (frame
->imethod
, o
, ip
, sp
);
5594 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
5595 MonoObject
* const o
= sp
[-1].data
.o
;
5597 vt_sp
= mono_interp_load_remote_field_vt (frame
->imethod
, o
, ip
, sp
, vt_sp
);
5602 #define LDLOCFLD(datamem, fieldtype) do { \
5603 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5605 sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \
5609 MINT_IN_CASE(MINT_LDLOCFLD_I1
) LDLOCFLD(i
, gint8
); MINT_IN_BREAK
;
5610 MINT_IN_CASE(MINT_LDLOCFLD_U1
) LDLOCFLD(i
, guint8
); MINT_IN_BREAK
;
5611 MINT_IN_CASE(MINT_LDLOCFLD_I2
) LDLOCFLD(i
, gint16
); MINT_IN_BREAK
;
5612 MINT_IN_CASE(MINT_LDLOCFLD_U2
) LDLOCFLD(i
, guint16
); MINT_IN_BREAK
;
5613 MINT_IN_CASE(MINT_LDLOCFLD_I4
) LDLOCFLD(i
, gint32
); MINT_IN_BREAK
;
5614 MINT_IN_CASE(MINT_LDLOCFLD_I8
) LDLOCFLD(l
, gint64
); MINT_IN_BREAK
;
5615 MINT_IN_CASE(MINT_LDLOCFLD_R4
) LDLOCFLD(f_r4
, float); MINT_IN_BREAK
;
5616 MINT_IN_CASE(MINT_LDLOCFLD_R8
) LDLOCFLD(f
, double); MINT_IN_BREAK
;
5617 MINT_IN_CASE(MINT_LDLOCFLD_O
) LDLOCFLD(p
, gpointer
); MINT_IN_BREAK
;
5619 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5620 MonoObject* const o = sp [-2].data.o; \
5624 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
5626 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
5630 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5632 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
5633 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
5634 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
5635 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
5636 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
5637 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
5638 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
5639 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
5640 MINT_IN_CASE(MINT_STFLD_O
) {
5641 MonoObject
* const o
= sp
[-2].data
.o
;
5644 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[1], sp
[1].data
.o
);
5648 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
5649 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
5651 MINT_IN_CASE(MINT_STFLD_VT_NOREF
) {
5652 MonoObject
* const o
= sp
[-2].data
.o
;
5656 guint16 offset
= ip
[1];
5657 guint16 vtsize
= ip
[2];
5659 memcpy ((char *) o
+ offset
, sp
[1].data
.p
, vtsize
);
5661 vt_sp
-= ALIGN_TO (vtsize
, MINT_VT_ALIGNMENT
);
5666 MINT_IN_CASE(MINT_STFLD_VT
) {
5667 MonoObject
* const o
= sp
[-2].data
.o
;
5671 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[2]];
5672 int const i32
= mono_class_value_size (klass
, NULL
);
5674 guint16 offset
= ip
[1];
5675 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
5677 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5681 MINT_IN_CASE(MINT_STRMFLD
) {
5682 MonoClassField
*field
;
5684 MonoObject
* const o
= sp
[-2].data
.o
;
5687 field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5690 #ifndef DISABLE_REMOTING
5691 if (mono_object_is_transparent_proxy (o
)) {
5692 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
5693 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
5694 mono_interp_error_cleanup (error
); /* FIXME: don't swallow the error */
5697 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
5702 MINT_IN_CASE(MINT_STRMFLD_VT
)
5704 NULL_CHECK (sp
[-2].data
.o
);
5705 vt_sp
-= mono_interp_store_remote_field_vt (frame
, ip
, sp
, error
);
5710 #define STLOCFLD(datamem, fieldtype) do { \
5711 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5714 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5717 MINT_IN_CASE(MINT_STLOCFLD_I1
) STLOCFLD(i
, gint8
); MINT_IN_BREAK
;
5718 MINT_IN_CASE(MINT_STLOCFLD_U1
) STLOCFLD(i
, guint8
); MINT_IN_BREAK
;
5719 MINT_IN_CASE(MINT_STLOCFLD_I2
) STLOCFLD(i
, gint16
); MINT_IN_BREAK
;
5720 MINT_IN_CASE(MINT_STLOCFLD_U2
) STLOCFLD(i
, guint16
); MINT_IN_BREAK
;
5721 MINT_IN_CASE(MINT_STLOCFLD_I4
) STLOCFLD(i
, gint32
); MINT_IN_BREAK
;
5722 MINT_IN_CASE(MINT_STLOCFLD_I8
) STLOCFLD(l
, gint64
); MINT_IN_BREAK
;
5723 MINT_IN_CASE(MINT_STLOCFLD_R4
) STLOCFLD(f_r4
, float); MINT_IN_BREAK
;
5724 MINT_IN_CASE(MINT_STLOCFLD_R8
) STLOCFLD(f
, double); MINT_IN_BREAK
;
5725 MINT_IN_CASE(MINT_STLOCFLD_O
) {
5726 MonoObject
*o
= *(MonoObject
**)(locals
+ ip
[1]);
5729 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ ip
[2], sp
[0].data
.o
);
5734 MINT_IN_CASE(MINT_LDSFLDA
) {
5735 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5736 INIT_VTABLE (vtable
);
5737 sp
->data
.p
= frame
->imethod
->data_items
[ip
[2]];
5743 MINT_IN_CASE(MINT_LDSSFLDA
) {
5744 guint32 offset
= READ32(ip
+ 1);
5745 sp
->data
.p
= mono_get_special_static_data (offset
);
5751 /* We init class here to preserve cctor order */
5752 #define LDSFLD(datamem, fieldtype) { \
5753 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5754 INIT_VTABLE (vtable); \
5755 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5760 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
5761 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
5762 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
5763 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
5764 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
5765 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
5766 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
5767 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
5768 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
5770 MINT_IN_CASE(MINT_LDSFLD_VT
) {
5771 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5772 INIT_VTABLE (vtable
);
5775 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5776 int const i32
= READ32 (ip
+ 3);
5777 memcpy (vt_sp
, addr
, i32
);
5778 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5784 #define LDTSFLD(datamem, fieldtype) { \
5785 MonoInternalThread *thread = mono_thread_internal_current (); \
5786 guint32 offset = READ32 (ip + 1); \
5787 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5788 sp[0].data.datamem = *(fieldtype*)addr; \
5792 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
5793 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
5794 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
5795 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
5796 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
5797 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
5798 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
5799 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
5800 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5802 MINT_IN_CASE(MINT_LDSSFLD
) {
5803 guint32 offset
= READ32(ip
+ 2);
5804 gpointer addr
= mono_get_special_static_data (offset
);
5805 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5806 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
5811 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
5812 guint32 offset
= READ32(ip
+ 1);
5813 gpointer addr
= mono_get_special_static_data (offset
);
5815 int size
= READ32 (ip
+ 3);
5816 memcpy (vt_sp
, addr
, size
);
5818 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5823 #define STSFLD(datamem, fieldtype) { \
5824 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5825 INIT_VTABLE (vtable); \
5827 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5831 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5832 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5833 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5834 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5835 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5836 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5837 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5838 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5839 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5841 MINT_IN_CASE(MINT_STSFLD_VT
) {
5842 MonoVTable
*vtable
= (MonoVTable
*) frame
->imethod
->data_items
[ip
[1]];
5843 INIT_VTABLE (vtable
);
5844 int const i32
= READ32 (ip
+ 3);
5845 gpointer addr
= frame
->imethod
->data_items
[ip
[2]];
5847 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5848 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5854 #define STTSFLD(datamem, fieldtype) { \
5855 MonoInternalThread *thread = mono_thread_internal_current (); \
5856 guint32 offset = READ32 (ip + 1); \
5857 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5859 *(fieldtype*)addr = sp[0].data.datamem; \
5863 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5864 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5865 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5866 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5867 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5868 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5869 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5870 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5871 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5873 MINT_IN_CASE(MINT_STSSFLD
) {
5874 guint32 offset
= READ32(ip
+ 2);
5875 gpointer addr
= mono_get_special_static_data (offset
);
5876 MonoClassField
*field
= (MonoClassField
*)frame
->imethod
->data_items
[ip
[1]];
5878 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5882 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5883 guint32 offset
= READ32(ip
+ 1);
5884 gpointer addr
= mono_get_special_static_data (offset
);
5886 int size
= READ32 (ip
+ 3);
5887 memcpy (addr
, sp
->data
.vt
, size
);
5888 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5893 MINT_IN_CASE(MINT_STOBJ_VT
) {
5895 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
5897 size
= mono_class_value_size (c
, NULL
);
5898 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5899 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5903 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5904 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5905 THROW_EX (mono_get_exception_overflow (), ip
);
5906 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5909 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5910 if (sp
[-1].data
.i
< 0)
5911 THROW_EX (mono_get_exception_overflow (), ip
);
5912 sp
[-1].data
.l
= sp
[-1].data
.i
;
5915 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5916 if (sp
[-1].data
.l
< 0)
5917 THROW_EX (mono_get_exception_overflow (), ip
);
5920 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5921 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5922 THROW_EX (mono_get_exception_overflow (), ip
);
5925 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
) {
5926 guint64 res
= (guint64
)sp
[-1].data
.f_r4
;
5927 if (mono_isnan (sp
[-1].data
.f_r4
) || mono_trunc (sp
[-1].data
.f_r4
) != res
)
5928 THROW_EX (mono_get_exception_overflow (), ip
);
5929 sp
[-1].data
.l
= res
;
5933 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
) {
5934 guint64 res
= (guint64
)sp
[-1].data
.f
;
5935 if (mono_isnan (sp
[-1].data
.f
) || mono_trunc (sp
[-1].data
.f
) != res
)
5936 THROW_EX (mono_get_exception_overflow (), ip
);
5937 sp
[-1].data
.l
= res
;
5941 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
) {
5942 gint64 res
= (gint64
)sp
[-1].data
.f
;
5943 if (res
< 0 || mono_isnan (sp
[-1].data
.f
) || mono_trunc (sp
[-1].data
.f
) != res
)
5944 THROW_EX (mono_get_exception_overflow (), ip
);
5945 sp
[-1].data
.l
= res
;
5949 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
) {
5950 gint64 res
= (gint64
)sp
[-1].data
.f_r4
;
5951 if (res
< 0 || mono_isnan (sp
[-1].data
.f_r4
) || mono_trunc (sp
[-1].data
.f_r4
) != res
)
5952 THROW_EX (mono_get_exception_overflow (), ip
);
5953 sp
[-1].data
.l
= res
;
5957 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
) {
5958 gint64 res
= (gint64
)sp
[-1].data
.f_r4
;
5959 if (mono_isnan (sp
[-1].data
.f_r4
) || mono_trunc (sp
[-1].data
.f_r4
) != res
)
5960 THROW_EX (mono_get_exception_overflow (), ip
);
5961 sp
[-1].data
.l
= res
;
5965 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
) {
5966 gint64 res
= (gint64
)sp
[-1].data
.f
;
5967 if (mono_isnan (sp
[-1].data
.f
) || mono_trunc (sp
[-1].data
.f
) != res
)
5968 THROW_EX (mono_get_exception_overflow (), ip
);
5969 sp
[-1].data
.l
= res
;
5973 MINT_IN_CASE(MINT_BOX
) {
5974 mono_interp_box (frame
, ip
, sp
, tmp_handle
);
5978 MINT_IN_CASE(MINT_BOX_VT
) {
5979 vt_sp
-= mono_interp_box_vt (frame
, ip
, sp
, tmp_handle
);
5983 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5984 vt_sp
-= mono_interp_box_nullable (frame
, ip
, sp
, error
);
5988 MINT_IN_CASE(MINT_NEWARR
) {
5989 MonoVTable
*vtable
= (MonoVTable
*)frame
->imethod
->data_items
[ip
[1]];
5990 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5991 if (!is_ok (error
)) {
5992 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5995 /*if (profiling_classes) {
5996 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5998 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
6003 MINT_IN_CASE(MINT_LDLEN
) {
6004 MonoObject
* const o
= sp
[-1].data
.o
;
6006 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
6010 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
6011 MonoObject
* const o
= sp
[-1].data
.o
;
6013 gsize offset_length
= (gsize
)(gint16
)ip
[1];
6014 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
6018 MINT_IN_CASE(MINT_GETCHR
) {
6020 s
= (MonoString
*)sp
[-2].data
.p
;
6022 int const i32
= sp
[-1].data
.i
;
6023 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
6024 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
6026 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
6030 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
6031 guint8
* const span
= (guint8
*) sp
[-2].data
.p
;
6032 const int index
= sp
[-1].data
.i
;
6037 const gsize offset_length
= (gsize
)(gint16
)ip
[2];
6039 const gint32 length
= *(gint32
*) (span
+ offset_length
);
6040 if (index
< 0 || index
>= length
)
6041 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
6043 const gsize element_size
= (gsize
)(gint16
)ip
[1];
6044 const gsize offset_pointer
= (gsize
)(gint16
)ip
[3];
6046 const gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
6047 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
6052 MINT_IN_CASE(MINT_STRLEN
) {
6054 MonoObject
* const o
= sp
[-1].data
.o
;
6056 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
6059 MINT_IN_CASE(MINT_ARRAY_RANK
) {
6060 MonoObject
* const o
= sp
[-1].data
.o
;
6062 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (o
));
6066 MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE
) {
6067 MonoObject
* const o
= sp
[-1].data
.o
;
6069 sp
[-1].data
.i
= mono_array_element_size (mono_object_class (o
));
6073 MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE
) {
6074 MonoObject
* const o
= sp
[-1].data
.o
;
6076 sp
[-1].data
.i
= m_class_is_primitive (m_class_get_element_class (mono_object_class (o
)));
6080 MINT_IN_CASE(MINT_LDELEMA1
) {
6081 /* No bounds, one direction */
6082 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
6084 gint32
const index
= sp
[-1].data
.i
;
6085 if (index
>= ao
->max_length
)
6086 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
6087 gint32
const size
= READ32 (ip
+ 1);
6088 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
6094 MINT_IN_CASE(MINT_LDELEMA
) {
6095 guint16 rank
= ip
[1];
6096 gint32
const esize
= READ32 (ip
+ 2);
6100 MonoArray
* const ao
= (MonoArray
*) sp
[-1].data
.o
;
6103 g_assert (ao
->bounds
);
6105 for (int i
= 0; i
< rank
; i
++) {
6106 gint32 idx
= sp
[i
].data
.i
;
6107 gint32 lower
= ao
->bounds
[i
].lower_bound
;
6108 guint32 len
= ao
->bounds
[i
].length
;
6109 if (idx
< lower
|| (guint32
)(idx
- lower
) >= len
)
6110 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
6111 pos
= (pos
* len
) + (guint32
)(idx
- lower
);
6114 sp
[-1].data
.p
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
6117 MINT_IN_CASE(MINT_LDELEMA_TC
) {
6118 guint16 rank
= ip
[1];
6122 MonoObject
* const o
= sp
[-1].data
.o
;
6125 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[-3 + 2]];
6126 const gboolean needs_typecheck
= ip
[-3] == MINT_LDELEMA_TC
;
6127 MonoException
*ex
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, sp
, needs_typecheck
);
6133 #define LDELEM(datamem,elemtype) do { \
6135 MonoArray *o = (MonoArray*)sp [-1].data.p; \
6137 gint32 aindex = sp [0].data.i; \
6138 if (aindex >= mono_array_length_internal (o)) \
6139 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
6140 sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \
6143 MINT_IN_CASE(MINT_LDELEM_I1
) LDELEM(i
, gint8
); MINT_IN_BREAK
;
6144 MINT_IN_CASE(MINT_LDELEM_U1
) LDELEM(i
, guint8
); MINT_IN_BREAK
;
6145 MINT_IN_CASE(MINT_LDELEM_I2
) LDELEM(i
, gint16
); MINT_IN_BREAK
;
6146 MINT_IN_CASE(MINT_LDELEM_U2
) LDELEM(i
, guint16
); MINT_IN_BREAK
;
6147 MINT_IN_CASE(MINT_LDELEM_I4
) LDELEM(i
, gint32
); MINT_IN_BREAK
;
6148 MINT_IN_CASE(MINT_LDELEM_U4
) LDELEM(i
, guint32
); MINT_IN_BREAK
;
6149 MINT_IN_CASE(MINT_LDELEM_I8
) LDELEM(l
, guint64
); MINT_IN_BREAK
;
6150 MINT_IN_CASE(MINT_LDELEM_I
) LDELEM(nati
, mono_i
); MINT_IN_BREAK
;
6151 MINT_IN_CASE(MINT_LDELEM_R4
) LDELEM(f_r4
, float); MINT_IN_BREAK
;
6152 MINT_IN_CASE(MINT_LDELEM_R8
) LDELEM(f
, double); MINT_IN_BREAK
;
6153 MINT_IN_CASE(MINT_LDELEM_REF
) LDELEM(p
, gpointer
); MINT_IN_BREAK
;
6154 MINT_IN_CASE(MINT_LDELEM_VT
) {
6156 MonoArray
*o
= (MonoArray
*)sp
[-1].data
.p
;
6158 mono_u aindex
= sp
[0].data
.i
;
6159 if (aindex
>= mono_array_length_internal (o
))
6160 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
6162 int i32
= READ32 (ip
+ 1);
6163 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
6164 sp
[-1].data
.vt
= vt_sp
;
6165 // Copying to vtstack. No wbarrier needed
6166 memcpy (sp
[-1].data
.vt
, src_addr
, i32
);
6167 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6172 #define STELEM_PROLOG(o, aindex) do { \
6174 o = (MonoArray*)sp [0].data.p; \
6176 aindex = sp [1].data.i; \
6177 if (aindex >= mono_array_length_internal (o)) \
6178 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
6181 #define STELEM(datamem,elemtype) do { \
6184 STELEM_PROLOG(o, aindex); \
6185 mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \
6188 MINT_IN_CASE(MINT_STELEM_I1
) STELEM(i
, gint8
); MINT_IN_BREAK
;
6189 MINT_IN_CASE(MINT_STELEM_U1
) STELEM(i
, guint8
); MINT_IN_BREAK
;
6190 MINT_IN_CASE(MINT_STELEM_I2
) STELEM(i
, gint16
); MINT_IN_BREAK
;
6191 MINT_IN_CASE(MINT_STELEM_U2
) STELEM(i
, guint16
); MINT_IN_BREAK
;
6192 MINT_IN_CASE(MINT_STELEM_I4
) STELEM(i
, gint32
); MINT_IN_BREAK
;
6193 MINT_IN_CASE(MINT_STELEM_I8
) STELEM(l
, gint64
); MINT_IN_BREAK
;
6194 MINT_IN_CASE(MINT_STELEM_I
) STELEM(nati
, mono_i
); MINT_IN_BREAK
;
6195 MINT_IN_CASE(MINT_STELEM_R4
) STELEM(f_r4
, float); MINT_IN_BREAK
;
6196 MINT_IN_CASE(MINT_STELEM_R8
) STELEM(f
, double); MINT_IN_BREAK
;
6197 MINT_IN_CASE(MINT_STELEM_REF
) {
6200 STELEM_PROLOG(o
, aindex
);
6202 if (sp
[2].data
.o
) {
6203 gboolean isinst
= mono_interp_isinst (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)));
6205 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
6207 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
6212 MINT_IN_CASE(MINT_STELEM_VT
) {
6215 STELEM_PROLOG(o
, aindex
);
6217 MonoClass
*klass_vt
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6218 int const i32
= READ32 (ip
+ 2);
6219 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
6221 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
6222 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6226 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
6227 if (sp
[-1].data
.i
< 0)
6228 THROW_EX (mono_get_exception_overflow (), ip
);
6231 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
6232 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
6233 THROW_EX (mono_get_exception_overflow (), ip
);
6234 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
6237 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
6238 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
6239 THROW_EX (mono_get_exception_overflow (), ip
);
6240 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
6243 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
) {
6244 gint32 res
= (gint32
)sp
[-1].data
.f_r4
;
6245 if (mono_isnan (sp
[-1].data
.f_r4
) || mono_trunc (sp
[-1].data
.f_r4
) != res
)
6246 THROW_EX (mono_get_exception_overflow (), ip
);
6247 sp
[-1].data
.i
= res
;
6251 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
6252 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
|| isnan (sp
[-1].data
.f
))
6253 THROW_EX (mono_get_exception_overflow (), ip
);
6254 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
6257 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
6258 if (sp
[-1].data
.i
< 0)
6259 THROW_EX (mono_get_exception_overflow (), ip
);
6262 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
6263 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
6264 THROW_EX (mono_get_exception_overflow (), ip
);
6265 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
6268 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
) {
6269 guint32 res
= (guint32
)sp
[-1].data
.f_r4
;
6270 if (mono_isnan (sp
[-1].data
.f_r4
) || mono_trunc (sp
[-1].data
.f_r4
) != res
)
6271 THROW_EX (mono_get_exception_overflow (), ip
);
6272 sp
[-1].data
.i
= res
;
6276 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
6277 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
|| isnan (sp
[-1].data
.f
))
6278 THROW_EX (mono_get_exception_overflow (), ip
);
6279 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
6282 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
6283 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
6284 THROW_EX (mono_get_exception_overflow (), ip
);
6287 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
6288 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
6289 THROW_EX (mono_get_exception_overflow (), ip
);
6292 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
6293 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
6294 THROW_EX (mono_get_exception_overflow (), ip
);
6295 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
6298 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
6299 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
6300 THROW_EX (mono_get_exception_overflow (), ip
);
6301 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
6304 MINT_IN_CASE(MINT_CONV_OVF_I2_R4
)
6305 if (sp
[-1].data
.f_r4
< G_MININT16
|| sp
[-1].data
.f_r4
> G_MAXINT16
|| isnan (sp
[-1].data
.f_r4
))
6306 THROW_EX (mono_get_exception_overflow (), ip
);
6307 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f_r4
;
6310 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
6311 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
|| isnan (sp
[-1].data
.f
))
6312 THROW_EX (mono_get_exception_overflow (), ip
);
6313 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
6316 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4
)
6317 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT16
|| isnan (sp
[-1].data
.f_r4
))
6318 THROW_EX (mono_get_exception_overflow (), ip
);
6319 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f_r4
;
6322 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
6323 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
|| isnan (sp
[-1].data
.f
))
6324 THROW_EX (mono_get_exception_overflow (), ip
);
6325 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
6328 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
6329 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
6330 THROW_EX (mono_get_exception_overflow (), ip
);
6333 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
6334 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
6335 THROW_EX (mono_get_exception_overflow (), ip
);
6336 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
6339 MINT_IN_CASE(MINT_CONV_OVF_U2_R4
)
6340 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT16
|| isnan (sp
[-1].data
.f_r4
))
6341 THROW_EX (mono_get_exception_overflow (), ip
);
6342 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f_r4
;
6345 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
6346 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
|| isnan (sp
[-1].data
.f
))
6347 THROW_EX (mono_get_exception_overflow (), ip
);
6348 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
6351 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
6352 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
6353 THROW_EX (mono_get_exception_overflow (), ip
);
6356 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
6357 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
6358 THROW_EX (mono_get_exception_overflow (), ip
);
6361 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
6362 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
6363 THROW_EX (mono_get_exception_overflow (), ip
);
6364 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
6367 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
6368 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
6369 THROW_EX (mono_get_exception_overflow (), ip
);
6370 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
6373 MINT_IN_CASE(MINT_CONV_OVF_I1_R4
)
6374 if (sp
[-1].data
.f_r4
< G_MININT8
|| sp
[-1].data
.f_r4
> G_MAXINT8
|| isnan (sp
[-1].data
.f_r4
))
6375 THROW_EX (mono_get_exception_overflow (), ip
);
6376 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f_r4
;
6379 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
6380 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
|| isnan (sp
[-1].data
.f
))
6381 THROW_EX (mono_get_exception_overflow (), ip
);
6382 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
6385 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4
)
6386 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT8
|| isnan (sp
[-1].data
.f_r4
))
6387 THROW_EX (mono_get_exception_overflow (), ip
);
6388 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f_r4
;
6391 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
6392 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
|| isnan (sp
[-1].data
.f
))
6393 THROW_EX (mono_get_exception_overflow (), ip
);
6394 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
6397 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
6398 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
6399 THROW_EX (mono_get_exception_overflow (), ip
);
6402 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
6403 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
6404 THROW_EX (mono_get_exception_overflow (), ip
);
6405 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
6408 MINT_IN_CASE(MINT_CONV_OVF_U1_R4
)
6409 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT8
|| isnan (sp
[-1].data
.f_r4
))
6410 THROW_EX (mono_get_exception_overflow (), ip
);
6411 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f_r4
;
6414 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
6415 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
|| isnan (sp
[-1].data
.f
))
6416 THROW_EX (mono_get_exception_overflow (), ip
);
6417 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
6420 MINT_IN_CASE(MINT_CKFINITE
)
6421 if (!mono_isfinite (sp
[-1].data
.f
))
6422 THROW_EX (mono_get_exception_arithmetic (), ip
);
6425 MINT_IN_CASE(MINT_MKREFANY
) {
6426 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6428 /* The value address is on the stack */
6429 gpointer addr
= sp
[-1].data
.p
;
6430 /* Push the typedref value on the stack */
6431 sp
[-1].data
.p
= vt_sp
;
6432 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6434 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6436 tref
->type
= m_class_get_byval_arg (c
);
6442 MINT_IN_CASE(MINT_REFANYTYPE
) {
6443 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6444 MonoType
*type
= tref
->type
;
6446 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6447 sp
[-1].data
.p
= vt_sp
;
6449 *(gpointer
*)sp
[-1].data
.p
= type
;
6453 MINT_IN_CASE(MINT_REFANYVAL
) {
6454 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
6455 gpointer addr
= tref
->value
;
6457 MonoClass
* const c
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
6458 if (c
!= tref
->klass
)
6459 THROW_EX (mono_get_exception_invalid_cast (), ip
);
6461 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
6463 sp
[-1].data
.p
= addr
;
6467 MINT_IN_CASE(MINT_LDTOKEN
)
6470 * (gpointer
*)sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6474 MINT_IN_CASE(MINT_ADD_OVF_I4
)
6475 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6476 THROW_EX (mono_get_exception_overflow (), ip
);
6479 MINT_IN_CASE(MINT_ADD_OVF_I8
)
6480 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6481 THROW_EX (mono_get_exception_overflow (), ip
);
6484 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
6485 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6486 THROW_EX (mono_get_exception_overflow (), ip
);
6487 BINOP_CAST(i
, +, guint32
);
6489 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
6490 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6491 THROW_EX (mono_get_exception_overflow (), ip
);
6492 BINOP_CAST(l
, +, guint64
);
6494 MINT_IN_CASE(MINT_MUL_OVF_I4
)
6495 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6496 THROW_EX (mono_get_exception_overflow (), ip
);
6499 MINT_IN_CASE(MINT_MUL_OVF_I8
)
6500 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6501 THROW_EX (mono_get_exception_overflow (), ip
);
6504 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
6505 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6506 THROW_EX (mono_get_exception_overflow (), ip
);
6507 BINOP_CAST(i
, *, guint32
);
6509 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
6510 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6511 THROW_EX (mono_get_exception_overflow (), ip
);
6512 BINOP_CAST(l
, *, guint64
);
6514 MINT_IN_CASE(MINT_SUB_OVF_I4
)
6515 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
6516 THROW_EX (mono_get_exception_overflow (), ip
);
6519 MINT_IN_CASE(MINT_SUB_OVF_I8
)
6520 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
6521 THROW_EX (mono_get_exception_overflow (), ip
);
6524 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
6525 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
6526 THROW_EX (mono_get_exception_overflow (), ip
);
6527 BINOP_CAST(i
, -, guint32
);
6529 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
6530 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
6531 THROW_EX (mono_get_exception_overflow (), ip
);
6532 BINOP_CAST(l
, -, guint64
);
6534 MINT_IN_CASE(MINT_START_ABORT_PROT
)
6535 mono_threads_begin_abort_protected_block ();
6538 MINT_IN_CASE(MINT_ENDFINALLY
) {
6539 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
6542 // After mono_threads_end_abort_protected_block to conserve stack.
6543 const int clause_index
= *ip
;
6545 // clause_args stores the clause args only for the first frame that
6546 // we started executing in interp_exec_method. If we are exiting the
6547 // current frame at this finally clause, we need to make sure that
6548 // this is the first frame invoked with interp_exec_method.
6549 if (clause_args
&& clause_args
->exec_frame
== frame
&& clause_index
== clause_args
->exit_clause
)
6552 // endfinally empties the stack
6553 vt_sp
= (guchar
*)frame
->stack
+ frame
->imethod
->total_locals_size
;
6554 sp
= (stackval
*)(vt_sp
+ frame
->imethod
->vt_stack_size
);
6557 ip
= (const guint16
*)finally_ips
->data
;
6558 finally_ips
= g_slist_remove (finally_ips
, ip
);
6559 /* Throw abort after the last finally block to avoid confusing EH */
6560 if (pending_abort
&& !finally_ips
)
6561 EXCEPTION_CHECKPOINT
;
6562 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6563 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6570 MINT_IN_CASE(MINT_LEAVE
)
6571 MINT_IN_CASE(MINT_LEAVE_S
)
6572 MINT_IN_CASE(MINT_LEAVE_CHECK
)
6573 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
6574 guint32 ip_offset
= ip
- frame
->imethod
->code
;
6575 // leave empties the stack
6576 vt_sp
= (guchar
*)frame
->stack
+ frame
->imethod
->total_locals_size
;
6577 sp
= (stackval
*)(vt_sp
+ frame
->imethod
->vt_stack_size
);
6580 gboolean
const check
= opcode
== MINT_LEAVE_CHECK
|| opcode
== MINT_LEAVE_S_CHECK
;
6582 if (check
&& frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
6583 MonoException
*abort_exc
= mono_interp_leave (frame
);
6585 THROW_EX (abort_exc
, ip
);
6588 opcode
= *ip
; // Refetch to avoid register/stack pressure.
6589 gboolean
const short_offset
= opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
;
6590 ip
+= short_offset
? (short)*(ip
+ 1) : (gint32
)READ32 (ip
+ 1);
6591 const guint16
*endfinally_ip
= ip
;
6592 GSList
*old_list
= finally_ips
;
6595 g_print ("* Handle finally IL_%04x\n", endfinally_ip
- frame
->imethod
->code
);
6597 finally_ips
= g_slist_prepend (finally_ips
, (void *)endfinally_ip
);
6599 for (int i
= frame
->imethod
->num_clauses
- 1; i
>= 0; i
--) {
6600 MonoExceptionClause
* const clause
= &frame
->imethod
->clauses
[i
];
6601 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- frame
->imethod
->code
))) {
6602 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6603 ip
= frame
->imethod
->code
+ clause
->handler_offset
;
6604 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
6607 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, context
->has_resume_state
? "yes": "no");
6613 if (old_list
!= finally_ips
&& finally_ips
) {
6614 ip
= (const guint16
*)finally_ips
->data
;
6615 finally_ips
= g_slist_remove (finally_ips
, ip
);
6616 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6617 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6624 MINT_IN_CASE(MINT_ICALL_V_V
)
6625 MINT_IN_CASE(MINT_ICALL_V_P
)
6626 MINT_IN_CASE(MINT_ICALL_P_V
)
6627 MINT_IN_CASE(MINT_ICALL_P_P
)
6628 MINT_IN_CASE(MINT_ICALL_PP_V
)
6629 MINT_IN_CASE(MINT_ICALL_PP_P
)
6630 MINT_IN_CASE(MINT_ICALL_PPP_V
)
6631 MINT_IN_CASE(MINT_ICALL_PPP_P
)
6632 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
6633 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
6634 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
6635 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
6636 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
6637 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
6638 frame
->state
.ip
= ip
+ 2;
6639 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, frame
->imethod
->data_items
[ip
[1]], FALSE
);
6640 EXCEPTION_CHECKPOINT_GC_UNSAFE
;
6641 CHECK_RESUME_STATE (context
);
6644 MINT_IN_CASE(MINT_MONO_LDPTR
)
6645 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6649 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
6650 sp
->data
.o
= mono_interp_new (frame
->imethod
->domain
, (MonoClass
*)frame
->imethod
->data_items
[ip
[1]]); // FIXME: do not swallow the error
6654 MINT_IN_CASE(MINT_MONO_RETOBJ
)
6657 stackval_from_data (mono_method_signature_internal (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
6658 mono_method_signature_internal (frame
->imethod
->method
)->pinvoke
);
6659 if (sp
> frame
->stack
)
6660 g_warning_d ("retobj: more values on stack: %d", sp
- frame
->stack
);
6661 frame_data_allocator_pop (&context
->data_stack
, frame
);
6663 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
6664 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
6668 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
6670 mono_memory_barrier ();
6673 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
6674 sp
->data
.p
= mono_domain_get ();
6678 MINT_IN_CASE(MINT_MONO_GET_SP
)
6683 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
6684 if (G_UNLIKELY (ss_enabled
)) {
6685 typedef void (*T
) (void);
6689 void *tramp
= mini_get_single_step_trampoline ();
6690 mono_memory_barrier ();
6691 ss_tramp
= (T
)tramp
;
6695 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6696 * the address of that instruction is stored as the seq point address. Add also
6697 * 1 to offset subtraction from interp_frame_get_ip.
6699 frame
->state
.ip
= ip
+ 2;
6702 * Use the same trampoline as the JIT. This ensures that
6703 * the debugger has the context for the last interpreter
6706 do_debugger_tramp (ss_tramp
, frame
);
6708 CHECK_RESUME_STATE (context
);
6712 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
6713 /* Just a placeholder for a breakpoint */
6716 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
6717 typedef void (*T
) (void);
6720 void *tramp
= mini_get_breakpoint_trampoline ();
6721 mono_memory_barrier ();
6722 bp_tramp
= (T
)tramp
;
6725 /* Add 1 to offset subtraction from interp_frame_get_ip */
6726 frame
->state
.ip
= ip
+ 1;
6728 /* Use the same trampoline as the JIT */
6729 do_debugger_tramp (bp_tramp
, frame
);
6731 CHECK_RESUME_STATE (context
);
6737 #define RELOP(datamem, op) \
6739 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6742 #define RELOP_FP(datamem, op, noorder) \
6744 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6745 sp [-1].data.i = noorder; \
6747 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6750 MINT_IN_CASE(MINT_CEQ_I4
)
6753 MINT_IN_CASE(MINT_CEQ0_I4
)
6754 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
6757 MINT_IN_CASE(MINT_CEQ_I8
)
6760 MINT_IN_CASE(MINT_CEQ_R4
)
6761 RELOP_FP(f_r4
, ==, 0);
6763 MINT_IN_CASE(MINT_CEQ_R8
)
6766 MINT_IN_CASE(MINT_CNE_I4
)
6769 MINT_IN_CASE(MINT_CNE_I8
)
6772 MINT_IN_CASE(MINT_CNE_R4
)
6773 RELOP_FP(f_r4
, !=, 1);
6775 MINT_IN_CASE(MINT_CNE_R8
)
6778 MINT_IN_CASE(MINT_CGT_I4
)
6781 MINT_IN_CASE(MINT_CGT_I8
)
6784 MINT_IN_CASE(MINT_CGT_R4
)
6785 RELOP_FP(f_r4
, >, 0);
6787 MINT_IN_CASE(MINT_CGT_R8
)
6790 MINT_IN_CASE(MINT_CGE_I4
)
6793 MINT_IN_CASE(MINT_CGE_I8
)
6796 MINT_IN_CASE(MINT_CGE_R4
)
6797 RELOP_FP(f_r4
, >=, 0);
6799 MINT_IN_CASE(MINT_CGE_R8
)
6803 #define RELOP_CAST(datamem, op, type) \
6805 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6808 MINT_IN_CASE(MINT_CGE_UN_I4
)
6809 RELOP_CAST(l
, >=, guint32
);
6811 MINT_IN_CASE(MINT_CGE_UN_I8
)
6812 RELOP_CAST(l
, >=, guint64
);
6815 MINT_IN_CASE(MINT_CGT_UN_I4
)
6816 RELOP_CAST(i
, >, guint32
);
6818 MINT_IN_CASE(MINT_CGT_UN_I8
)
6819 RELOP_CAST(l
, >, guint64
);
6821 MINT_IN_CASE(MINT_CGT_UN_R4
)
6822 RELOP_FP(f_r4
, >, 1);
6824 MINT_IN_CASE(MINT_CGT_UN_R8
)
6827 MINT_IN_CASE(MINT_CLT_I4
)
6830 MINT_IN_CASE(MINT_CLT_I8
)
6833 MINT_IN_CASE(MINT_CLT_R4
)
6834 RELOP_FP(f_r4
, <, 0);
6836 MINT_IN_CASE(MINT_CLT_R8
)
6839 MINT_IN_CASE(MINT_CLT_UN_I4
)
6840 RELOP_CAST(i
, <, guint32
);
6842 MINT_IN_CASE(MINT_CLT_UN_I8
)
6843 RELOP_CAST(l
, <, guint64
);
6845 MINT_IN_CASE(MINT_CLT_UN_R4
)
6846 RELOP_FP(f_r4
, <, 1);
6848 MINT_IN_CASE(MINT_CLT_UN_R8
)
6851 MINT_IN_CASE(MINT_CLE_I4
)
6854 MINT_IN_CASE(MINT_CLE_I8
)
6857 MINT_IN_CASE(MINT_CLE_UN_I4
)
6858 RELOP_CAST(l
, <=, guint32
);
6860 MINT_IN_CASE(MINT_CLE_UN_I8
)
6861 RELOP_CAST(l
, <=, guint64
);
6863 MINT_IN_CASE(MINT_CLE_R4
)
6864 RELOP_FP(f_r4
, <=, 0);
6866 MINT_IN_CASE(MINT_CLE_R8
)
6874 MINT_IN_CASE(MINT_LDFTN
) {
6875 sp
->data
.p
= frame
->imethod
->data_items
[ip
[1]];
6880 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6881 InterpMethod
*m
= (InterpMethod
*)frame
->imethod
->data_items
[ip
[1]];
6883 NULL_CHECK (sp
->data
.p
);
6885 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6890 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6891 error_init_reuse (error
);
6892 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6893 mono_error_assert_ok (error
);
6899 MINT_IN_CASE(MINT_LDARG_VT
) {
6901 int const i32
= READ32 (ip
+ 2);
6902 memcpy(sp
->data
.p
, frame
->stack
[ip
[1]].data
.p
, i32
);
6903 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6909 MINT_IN_CASE(MINT_STARG_VT
) {
6910 int const i32
= READ32 (ip
+ 2);
6912 memcpy(frame
->stack
[ip
[1]].data
.p
, sp
->data
.p
, i32
);
6913 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6918 MINT_IN_CASE(MINT_PROF_ENTER
) {
6919 guint16 flag
= ip
[1];
6922 if ((flag
& TRACING_FLAG
) || ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
) &&
6923 (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
))) {
6924 MonoProfilerCallContext
*prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6925 prof_ctx
->interp_frame
= frame
;
6926 prof_ctx
->method
= frame
->imethod
->method
;
6927 if (flag
& TRACING_FLAG
)
6928 mono_trace_enter_method (frame
->imethod
->method
, frame
->imethod
->jinfo
, prof_ctx
);
6929 if (flag
& PROFILING_FLAG
)
6930 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
6932 } else if ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
)) {
6933 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, NULL
));
6938 MINT_IN_CASE(MINT_PROF_EXIT
)
6939 MINT_IN_CASE(MINT_PROF_EXIT_VOID
) {
6940 guint16 flag
= ip
[1];
6942 int const i32
= READ32 (ip
+ 2);
6946 if (frame
->parent
) {
6947 gpointer dest_vt
= frame
->parent
->state
.vt_sp
;
6948 /* Push the valuetype in the parent frame */
6949 memcpy (dest_vt
, sp
->data
.p
, i32
);
6950 frame
->parent
->state
.sp
[0].data
.p
= dest_vt
;
6951 frame
->parent
->state
.sp
++;
6952 frame
->parent
->state
.vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6954 memcpy (frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6958 if (frame
->parent
) {
6959 frame
->parent
->state
.sp
[0] = *sp
;
6960 frame
->parent
->state
.sp
++;
6962 *frame
->retval
= *sp
;
6966 if ((flag
& TRACING_FLAG
) || ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_leave
) &&
6967 (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
))) {
6968 MonoProfilerCallContext
*prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6969 prof_ctx
->interp_frame
= frame
;
6970 prof_ctx
->method
= frame
->imethod
->method
;
6974 prof_ctx
->return_value
= frame
->parent
->state
.sp
[-1].data
.p
;
6976 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6979 prof_ctx
->return_value
= frame
->parent
->state
.sp
- 1;
6981 prof_ctx
->return_value
= frame
->retval
;
6984 if (flag
& TRACING_FLAG
)
6985 mono_trace_leave_method (frame
->imethod
->method
, frame
->imethod
->jinfo
, prof_ctx
);
6986 if (flag
& PROFILING_FLAG
)
6987 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
6989 } else if ((flag
& PROFILING_FLAG
) && MONO_PROFILER_ENABLED (method_enter
)) {
6990 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, NULL
));
6994 frame_data_allocator_pop (&context
->data_stack
, frame
);
6997 MINT_IN_CASE(MINT_PROF_COVERAGE_STORE
) {
6999 guint32
*p
= (guint32
*)GINT_TO_POINTER (READ64 (ip
));
7005 MINT_IN_CASE(MINT_LDARGA_VT
)
7006 sp
->data
.p
= frame
->stack
[ip
[1]].data
.p
;
7011 #define LDLOC(datamem, argtype) \
7012 sp->data.datamem = * (argtype *)(locals + ip [1]); \
7016 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
7017 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
7018 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
7019 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
7020 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
7021 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
7022 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
7023 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
7024 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
7026 MINT_IN_CASE(MINT_LDLOC_VT
) {
7028 int const i32
= READ32 (ip
+ 2);
7029 memcpy(sp
->data
.p
, locals
+ ip
[1], i32
);
7030 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
7035 MINT_IN_CASE(MINT_LDLOCA_S
)
7036 sp
->data
.p
= locals
+ ip
[1];
7041 #define STLOC(datamem, argtype) \
7043 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
7046 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
7047 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
7048 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
7049 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
7050 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
7051 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
7052 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
7053 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
7054 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
7056 #define STLOC_NP(datamem, argtype) \
7057 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
7060 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
7061 MINT_IN_CASE(MINT_STLOC_NP_I8
) STLOC_NP(l
, gint64
); MINT_IN_BREAK
;
7062 MINT_IN_CASE(MINT_STLOC_NP_R4
) STLOC_NP(f_r4
, float); MINT_IN_BREAK
;
7063 MINT_IN_CASE(MINT_STLOC_NP_R8
) STLOC_NP(f
, double); MINT_IN_BREAK
;
7064 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
7066 MINT_IN_CASE(MINT_STLOC_VT
) {
7067 int const i32
= READ32 (ip
+ 2);
7069 memcpy(locals
+ ip
[1], sp
->data
.p
, i32
);
7070 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
7075 #define MOVLOC(argtype) \
7076 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
7079 MINT_IN_CASE(MINT_MOVLOC_1
) MOVLOC(guint8
); MINT_IN_BREAK
;
7080 MINT_IN_CASE(MINT_MOVLOC_2
) MOVLOC(guint16
); MINT_IN_BREAK
;
7081 MINT_IN_CASE(MINT_MOVLOC_4
) MOVLOC(guint32
); MINT_IN_BREAK
;
7082 MINT_IN_CASE(MINT_MOVLOC_8
) MOVLOC(guint64
); MINT_IN_BREAK
;
7084 MINT_IN_CASE(MINT_MOVLOC_VT
) {
7085 int const i32
= READ32(ip
+ 3);
7086 memcpy (locals
+ ip
[2], locals
+ ip
[1], i32
);
7091 MINT_IN_CASE(MINT_LOCALLOC
) {
7092 stackval
*sp_start
= (stackval
*)(locals
+ frame
->imethod
->total_locals_size
+ frame
->imethod
->vt_stack_size
);
7093 if (sp
!= sp_start
+ 1) /*FIX?*/
7094 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
7096 int len
= sp
[-1].data
.i
;
7097 // FIXME we need a separate allocator for localloc sections
7098 sp
[-1].data
.p
= frame_data_allocator_alloc (&context
->data_stack
, frame
, ALIGN_TO (len
, MINT_VT_ALIGNMENT
));
7100 if (frame
->imethod
->init_locals
)
7101 memset (sp
[-1].data
.p
, 0, len
);
7105 MINT_IN_CASE(MINT_ENDFILTER
)
7106 /* top of stack is result of filter */
7107 frame
->retval
->data
.i
= sp
[-1].data
.i
;
7109 MINT_IN_CASE(MINT_INITOBJ
)
7111 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
7114 MINT_IN_CASE(MINT_CPBLK
)
7116 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
7117 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
7119 /* FIXME: value and size may be int64... */
7120 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
7123 MINT_IN_CASE(MINT_CONSTRAINED_
) {
7125 /* FIXME: implement */
7127 token
= READ32 (ip
);
7132 MINT_IN_CASE(MINT_INITBLK
)
7134 NULL_CHECK (sp
[0].data
.p
);
7136 /* FIXME: value and size may be int64... */
7137 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
7140 MINT_IN_CASE(MINT_NO_
)
7141 /* FIXME: implement */
7145 MINT_IN_CASE(MINT_RETHROW
) {
7146 int exvar_offset
= ip
[1];
7147 THROW_EX_GENERAL (*(MonoException
**)(frame_locals (frame
) + exvar_offset
), ip
, TRUE
);
7150 MINT_IN_CASE(MINT_MONO_RETHROW
) {
7152 * need to clarify what this should actually do:
7154 * Takes an exception from the stack and rethrows it.
7155 * This is useful for wrappers that don't want to have to
7156 * use CEE_THROW and lose the exception stacktrace.
7161 sp
->data
.p
= mono_get_exception_null_reference ();
7163 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
7166 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
7170 del
= (MonoDelegate
*)sp
->data
.p
;
7171 if (!del
->interp_method
) {
7172 /* Not created from interpreted code */
7173 error_init_reuse (error
);
7174 g_assert (del
->method
);
7175 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
7176 mono_error_assert_ok (error
);
7178 g_assert (del
->interp_method
);
7179 sp
->data
.p
= del
->interp_method
;
7184 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
7187 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
7188 if (!del
->interp_invoke_impl
) {
7190 * First time we are called. Set up the invoke wrapper. We might be able to do this
7191 * in ctor but we would need to handle AllocDelegateLike_internal separately
7193 error_init_reuse (error
);
7194 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
7195 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
7196 mono_error_assert_ok (error
);
7199 sp
[-1].data
.p
= del
->interp_invoke_impl
;
7204 #define MATH_UNOP(mathfunc) \
7205 sp [-1].data.f = mathfunc (sp [-1].data.f); \
7208 #define MATH_BINOP(mathfunc) \
7210 sp [-1].data.f = mathfunc (sp [-1].data.f, sp [0].data.f); \
7213 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
7214 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
7215 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
7216 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
7217 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
7218 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
7219 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
7220 MINT_IN_CASE(MINT_CEILING
) MATH_UNOP(ceil
); MINT_IN_BREAK
;
7221 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
7222 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
7223 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
7224 MINT_IN_CASE(MINT_EXP
) MATH_UNOP(exp
); MINT_IN_BREAK
;
7225 MINT_IN_CASE(MINT_FLOOR
) MATH_UNOP(floor
); MINT_IN_BREAK
;
7226 MINT_IN_CASE(MINT_LOG
) MATH_UNOP(log
); MINT_IN_BREAK
;
7227 MINT_IN_CASE(MINT_LOG2
) MATH_UNOP(log2
); MINT_IN_BREAK
;
7228 MINT_IN_CASE(MINT_LOG10
) MATH_UNOP(log10
); MINT_IN_BREAK
;
7229 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
7230 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
7231 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
7232 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
7233 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
7235 MINT_IN_CASE(MINT_ATAN2
) MATH_BINOP(atan2
); MINT_IN_BREAK
;
7236 MINT_IN_CASE(MINT_POW
) MATH_BINOP(pow
); MINT_IN_BREAK
;
7237 MINT_IN_CASE(MINT_FMA
)
7239 sp
[-1].data
.f
= fma (sp
[-1].data
.f
, sp
[0].data
.f
, sp
[1].data
.f
);
7242 MINT_IN_CASE(MINT_SCALEB
)
7244 sp
[-1].data
.f
= scalbn (sp
[-1].data
.f
, sp
[0].data
.i
);
7247 MINT_IN_CASE(MINT_ILOGB
) {
7249 double x
= sp
[-1].data
.f
;
7250 if (FP_ILOGB0
!= INT_MIN
&& x
== 0.0)
7252 else if (FP_ILOGBNAN
!= INT_MAX
&& isnan(x
))
7256 sp
[-1].data
.i
= result
;
7261 #define MATH_UNOPF(mathfunc) \
7262 sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4); \
7265 #define MATH_BINOPF(mathfunc) \
7267 sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4, sp [0].data.f_r4); \
7269 MINT_IN_CASE(MINT_ABSF
) MATH_UNOPF(fabsf
); MINT_IN_BREAK
;
7270 MINT_IN_CASE(MINT_ASINF
) MATH_UNOPF(asinf
); MINT_IN_BREAK
;
7271 MINT_IN_CASE(MINT_ASINHF
) MATH_UNOPF(asinhf
); MINT_IN_BREAK
;
7272 MINT_IN_CASE(MINT_ACOSF
) MATH_UNOPF(acosf
); MINT_IN_BREAK
;
7273 MINT_IN_CASE(MINT_ACOSHF
) MATH_UNOPF(acoshf
); MINT_IN_BREAK
;
7274 MINT_IN_CASE(MINT_ATANF
) MATH_UNOPF(atanf
); MINT_IN_BREAK
;
7275 MINT_IN_CASE(MINT_ATANHF
) MATH_UNOPF(atanhf
); MINT_IN_BREAK
;
7276 MINT_IN_CASE(MINT_CEILINGF
) MATH_UNOPF(ceilf
); MINT_IN_BREAK
;
7277 MINT_IN_CASE(MINT_COSF
) MATH_UNOPF(cosf
); MINT_IN_BREAK
;
7278 MINT_IN_CASE(MINT_CBRTF
) MATH_UNOPF(cbrtf
); MINT_IN_BREAK
;
7279 MINT_IN_CASE(MINT_COSHF
) MATH_UNOPF(coshf
); MINT_IN_BREAK
;
7280 MINT_IN_CASE(MINT_EXPF
) MATH_UNOPF(expf
); MINT_IN_BREAK
;
7281 MINT_IN_CASE(MINT_FLOORF
) MATH_UNOPF(floorf
); MINT_IN_BREAK
;
7282 MINT_IN_CASE(MINT_LOGF
) MATH_UNOPF(logf
); MINT_IN_BREAK
;
7283 MINT_IN_CASE(MINT_LOG2F
) MATH_UNOPF(log2f
); MINT_IN_BREAK
;
7284 MINT_IN_CASE(MINT_LOG10F
) MATH_UNOPF(log10f
); MINT_IN_BREAK
;
7285 MINT_IN_CASE(MINT_SINF
) MATH_UNOPF(sinf
); MINT_IN_BREAK
;
7286 MINT_IN_CASE(MINT_SQRTF
) MATH_UNOPF(sqrtf
); MINT_IN_BREAK
;
7287 MINT_IN_CASE(MINT_SINHF
) MATH_UNOPF(sinhf
); MINT_IN_BREAK
;
7288 MINT_IN_CASE(MINT_TANF
) MATH_UNOPF(tanf
); MINT_IN_BREAK
;
7289 MINT_IN_CASE(MINT_TANHF
) MATH_UNOPF(tanhf
); MINT_IN_BREAK
;
7291 MINT_IN_CASE(MINT_ATAN2F
) MATH_BINOPF(atan2f
); MINT_IN_BREAK
;
7292 MINT_IN_CASE(MINT_POWF
) MATH_BINOPF(powf
); MINT_IN_BREAK
;
7293 MINT_IN_CASE(MINT_FMAF
)
7295 sp
[-1].data
.f_r4
= fmaf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
, sp
[1].data
.f_r4
);
7298 MINT_IN_CASE(MINT_SCALEBF
)
7300 sp
[-1].data
.f_r4
= scalbnf (sp
[-1].data
.f_r4
, sp
[0].data
.i
);
7303 MINT_IN_CASE(MINT_ILOGBF
) {
7305 float x
= sp
[-1].data
.f_r4
;
7306 if (FP_ILOGB0
!= INT_MIN
&& x
== 0.0)
7308 else if (FP_ILOGBNAN
!= INT_MAX
&& isnan(x
))
7311 result
= ilogbf (x
);
7312 sp
[-1].data
.i
= result
;
7317 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
7318 MonoClass
*klass
= (MonoClass
*)frame
->imethod
->data_items
[ip
[1]];
7319 mono_interp_enum_hasflag (sp
, klass
);
7324 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
7325 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
7329 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
7330 NULL_CHECK (sp
[-1].data
.p
);
7331 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
7336 #if !USE_COMPUTED_GOTO
7338 interp_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname (*ip
), ip
- frame
->imethod
->code
);
7343 g_assert_not_reached ();
7346 g_assert (context
->has_resume_state
);
7347 g_assert (frame
->imethod
);
7349 if (frame
== context
->handler_frame
) {
7351 * When running finally blocks, we can have the same frame twice on the stack. If we have
7352 * clause_args information, we need to check whether resuming should happen inside this
7353 * finally block, or in some other part of the method, in which case we need to exit.
7355 if (clause_args
&& frame
== clause_args
->exec_frame
&& context
->handler_ip
>= clause_args
->end_at_ip
) {
7358 /* Set the current execution state to the resume state in context */
7359 ip
= context
->handler_ip
;
7360 /* spec says stack should be empty at endfinally so it should be at the start too */
7361 locals
= (guchar
*)frame
->stack
;
7362 vt_sp
= locals
+ frame
->imethod
->total_locals_size
;
7363 sp
= (stackval
*)(vt_sp
+ frame
->imethod
->vt_stack_size
);
7364 g_assert (context
->exc_gchandle
);
7365 sp
->data
.p
= mono_gchandle_get_target_internal (context
->exc_gchandle
);
7368 finally_ips
= clear_resume_state (context
, finally_ips
);
7369 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
7370 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
7373 } else if (clause_args
&& frame
== clause_args
->exec_frame
) {
7375 * This frame doesn't handle the resume state and it is the first frame invoked from EH.
7376 * We can't just return to parent. We must first exit the EH mechanism and start resuming
7377 * again from the original frame.
7381 // Because we are resuming in another frame, bypassing a normal ret opcode,
7382 // we need to make sure to reset the localloc stack
7383 frame_data_allocator_pop (&context
->data_stack
, frame
);
7386 g_assert_checked (frame
->imethod
);
7388 if (frame
->parent
&& frame
->parent
->state
.ip
) {
7389 /* Return to the main loop after a non-recursive interpreter call */
7390 //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);
7391 g_assert_checked (frame
->stack
);
7392 frame
= frame
->parent
;
7394 * FIXME We should be able to avoid dereferencing imethod here, if we will have
7395 * a param_area and all calls would inherit the same sp, or if we are full coop.
7397 context
->stack_pointer
= (guchar
*)frame
->stack
+ frame
->imethod
->alloca_size
;
7398 LOAD_INTERP_STATE (frame
);
7400 CHECK_RESUME_STATE (context
);
7406 context
->stack_pointer
= (guchar
*)frame
->stack
;
7410 HANDLE_FUNCTION_RETURN ();
7414 interp_parse_options (const char *options
)
7421 args
= g_strsplit (options
, ",", -1);
7422 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
7425 if (strncmp (arg
, "jit=", 4) == 0)
7426 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
7427 else if (strncmp (arg
, "interp-only=", strlen ("interp-only=")) == 0)
7428 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
7429 else if (strncmp (arg
, "-inline", 7) == 0)
7430 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
7431 else if (strncmp (arg
, "-cprop", 6) == 0)
7432 mono_interp_opt
&= ~INTERP_OPT_CPROP
;
7433 else if (strncmp (arg
, "-super", 6) == 0)
7434 mono_interp_opt
&= ~INTERP_OPT_SUPER_INSTRUCTIONS
;
7435 else if (strncmp (arg
, "-bblocks", 8) == 0)
7436 mono_interp_opt
&= ~INTERP_OPT_BBLOCKS
;
7437 else if (strncmp (arg
, "-all", 4) == 0)
7438 mono_interp_opt
= INTERP_OPT_NONE
;
7443 * interp_set_resume_state:
7445 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
7448 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoObject
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
7450 ThreadContext
*context
;
7453 context
= (ThreadContext
*)jit_tls
->interp_context
;
7456 context
->has_resume_state
= TRUE
;
7457 context
->handler_frame
= (InterpFrame
*)interp_frame
;
7458 context
->handler_ei
= ei
;
7459 if (context
->exc_gchandle
)
7460 mono_gchandle_free_internal (context
->exc_gchandle
);
7461 context
->exc_gchandle
= mono_gchandle_new_internal ((MonoObject
*)ex
, FALSE
);
7464 *(MonoObject
**)(frame_locals (context
->handler_frame
) + ei
->exvar_offset
) = ex
;
7465 context
->handler_ip
= (const guint16
*)handler_ip
;
7469 interp_get_resume_state (const MonoJitTlsData
*jit_tls
, gboolean
*has_resume_state
, MonoInterpFrameHandle
*interp_frame
, gpointer
*handler_ip
)
7472 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
7474 *has_resume_state
= context
? context
->has_resume_state
: FALSE
;
7475 if (!*has_resume_state
)
7478 *interp_frame
= context
->handler_frame
;
7479 *handler_ip
= (gpointer
)context
->handler_ip
;
7483 * interp_run_finally:
7485 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
7486 * frame->interp_frame.
7487 * Return TRUE if the finally clause threw an exception.
7490 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
7492 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
7493 ThreadContext
*context
= get_context ();
7494 FrameClauseArgs clause_args
;
7495 const guint16
*state_ip
;
7497 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
7498 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
7499 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
7500 clause_args
.exit_clause
= clause_index
;
7501 clause_args
.exec_frame
= iframe
;
7503 state_ip
= iframe
->state
.ip
;
7504 iframe
->state
.ip
= NULL
;
7506 InterpFrame
* const next_free
= iframe
->next_free
;
7507 iframe
->next_free
= NULL
;
7509 interp_exec_method (iframe
, context
, &clause_args
);
7511 iframe
->next_free
= next_free
;
7512 iframe
->state
.ip
= state_ip
;
7513 if (context
->has_resume_state
) {
7521 * interp_run_filter:
7523 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
7524 * frame->interp_frame.
7526 // Do not inline in case order of frame addresses matters.
7527 static MONO_NEVER_INLINE gboolean
7528 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
7530 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
7531 ThreadContext
*context
= get_context ();
7533 FrameClauseArgs clause_args
;
7536 * Have to run the clause in a new frame which is a copy of IFRAME, since
7537 * during debugging, there are two copies of the frame on the stack.
7539 InterpFrame child_frame
= {0};
7540 child_frame
.parent
= iframe
;
7541 child_frame
.imethod
= iframe
->imethod
;
7542 child_frame
.stack
= (stackval
*)context
->stack_pointer
;
7543 child_frame
.retval
= &retval
;
7545 /* Copy the stack frame of the original method */
7546 memcpy (child_frame
.stack
, iframe
->stack
, iframe
->imethod
->total_locals_size
);
7547 context
->stack_pointer
+= iframe
->imethod
->alloca_size
;
7549 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
7550 clause_args
.start_with_ip
= (const guint16
*)handler_ip
;
7551 clause_args
.end_at_ip
= (const guint16
*)handler_ip_end
;
7552 clause_args
.filter_exception
= ex
;
7553 clause_args
.exec_frame
= &child_frame
;
7555 interp_exec_method (&child_frame
, context
, &clause_args
);
7557 /* Copy back the updated frame */
7558 memcpy (iframe
->stack
, child_frame
.stack
, iframe
->imethod
->total_locals_size
);
7560 context
->stack_pointer
= (guchar
*)child_frame
.stack
;
7562 /* ENDFILTER stores the result into child_frame->retval */
7563 return retval
.data
.i
? TRUE
: FALSE
;
7567 InterpFrame
*current
;
7571 interp_frame_get_ip (MonoInterpFrameHandle frame
)
7573 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7575 g_assert (iframe
->imethod
);
7577 * For calls, state.ip points to the instruction following the call, so we need to subtract
7578 * in order to get inside the call instruction range. Other instructions that set the IP for
7579 * the rest of the runtime to see, like throws and sdb breakpoints, will need to account for
7580 * this subtraction that we are doing here.
7582 return (gpointer
)(iframe
->state
.ip
- 1);
7586 * interp_frame_iter_init:
7588 * Initialize an iterator for iterating through interpreted frames.
7591 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
7593 StackIter
*stack_iter
= (StackIter
*)iter
;
7595 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
7599 * interp_frame_iter_next:
7601 * Fill out FRAME with date for the next interpreter frame.
7604 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
7606 StackIter
*stack_iter
= (StackIter
*)iter
;
7607 InterpFrame
*iframe
= stack_iter
->current
;
7609 memset (frame
, 0, sizeof (StackFrameInfo
));
7610 /* pinvoke frames doesn't have imethod set */
7611 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
7612 iframe
= iframe
->parent
;
7616 MonoMethod
*method
= iframe
->imethod
->method
;
7617 frame
->domain
= iframe
->imethod
->domain
;
7618 frame
->interp_frame
= iframe
;
7619 frame
->method
= method
;
7620 frame
->actual_method
= method
;
7621 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
7622 frame
->native_offset
= -1;
7623 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
7625 frame
->type
= FRAME_TYPE_INTERP
;
7626 /* This is the offset in the interpreter IR. */
7627 frame
->native_offset
= (guint8
*)interp_frame_get_ip (iframe
) - (guint8
*)iframe
->imethod
->code
;
7628 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
7629 frame
->managed
= TRUE
;
7631 frame
->ji
= iframe
->imethod
->jinfo
;
7632 frame
->frame_addr
= iframe
;
7634 stack_iter
->current
= iframe
->parent
;
7640 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
7642 InterpMethod
* imethod
;
7644 imethod
= lookup_imethod (domain
, method
);
7646 return imethod
->jinfo
;
7652 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
7654 guint16
*code
= (guint16
*)ip
;
7655 g_assert (*code
== MINT_SDB_SEQ_POINT
);
7656 *code
= MINT_SDB_BREAKPOINT
;
7660 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
7662 guint16
*code
= (guint16
*)ip
;
7663 g_assert (*code
== MINT_SDB_BREAKPOINT
);
7664 *code
= MINT_SDB_SEQ_POINT
;
7668 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
7670 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7672 g_assert (iframe
->imethod
);
7673 return iframe
->imethod
->jinfo
;
7677 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
7679 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7680 MonoMethodSignature
*sig
;
7682 g_assert (iframe
->imethod
);
7684 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
7685 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack
[pos
+ !!iframe
->imethod
->hasthis
]);
7689 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
7691 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7693 g_assert (iframe
->imethod
);
7695 return frame_locals (iframe
) + iframe
->imethod
->local_offsets
[pos
];
7699 interp_frame_get_this (MonoInterpFrameHandle frame
)
7701 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7703 g_assert (iframe
->imethod
);
7704 g_assert (iframe
->imethod
->hasthis
);
7705 return &iframe
->stack
[0].data
.p
;
7708 static MonoInterpFrameHandle
7709 interp_frame_get_parent (MonoInterpFrameHandle frame
)
7711 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7713 return iframe
->parent
;
7717 interp_frame_get_res (MonoInterpFrameHandle frame
)
7719 InterpFrame
*iframe
= (InterpFrame
*)frame
;
7720 MonoMethodSignature
*sig
;
7722 g_assert (iframe
->imethod
);
7723 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
7724 if (sig
->ret
->type
== MONO_TYPE_VOID
)
7726 else if (iframe
->parent
)
7727 return stackval_to_data_addr (sig
->ret
, iframe
->parent
->state
.sp
- 1);
7729 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
7733 interp_start_single_stepping (void)
7739 interp_stop_single_stepping (void)
7745 * interp_mark_stack:
7747 * Mark the interpreter stack frames for a thread.
7751 interp_mark_stack (gpointer thread_data
, GcScanFunc func
, gpointer gc_data
, gboolean precise
)
7753 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread_data
;
7755 if (!mono_use_interpreter
)
7761 * We explicitly mark the frames instead of registering the stack fragments as GC roots, so
7762 * we have to process less data and avoid false pinning from data which is above 'pos'.
7764 * The stack frame handling code uses compiler write barriers only, but the calling code
7765 * in sgen-mono.c already did a mono_memory_barrier_process_wide () so we can
7766 * process these data structures normally.
7768 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)info
->tls
[TLS_KEY_JIT_TLS
];
7772 ThreadContext
*context
= (ThreadContext
*)jit_tls
->interp_context
;
7773 if (!context
|| !context
->stack_start
)
7776 // FIXME: Scan the whole area with 1 call
7777 for (gpointer
*p
= (gpointer
*)context
->stack_start
; p
< (gpointer
*)context
->stack_pointer
; p
++)
7780 FrameDataFragment
*frag
;
7781 for (frag
= context
->data_stack
.first
; frag
; frag
= frag
->next
) {
7782 // FIXME: Scan the whole area with 1 call
7783 for (gpointer
*p
= (gpointer
*)&frag
->data
; p
< (gpointer
*)frag
->pos
; ++p
)
7785 if (frag
== context
->data_stack
.current
)
7793 opcode_count_comparer (const void * pa
, const void * pb
)
7795 long counta
= opcode_counts
[*(int*)pa
];
7796 long countb
= opcode_counts
[*(int*)pb
];
7798 if (counta
< countb
)
7800 else if (counta
> countb
)
7807 interp_print_op_count (void)
7809 int ordered_ops
[MINT_LASTOP
];
7813 for (i
= 0; i
< MINT_LASTOP
; i
++) {
7814 ordered_ops
[i
] = i
;
7815 total_ops
+= opcode_counts
[i
];
7817 qsort (ordered_ops
, MINT_LASTOP
, sizeof (int), opcode_count_comparer
);
7819 g_print ("total ops %ld\n", total_ops
);
7820 for (i
= 0; i
< MINT_LASTOP
; i
++) {
7821 long count
= opcode_counts
[ordered_ops
[i
]];
7822 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops
[i
]), count
, (double)count
/ total_ops
* 100);
7829 static InterpMethod
**imethods
;
7830 static int num_methods
;
7831 const int opcount_threshold
= 100000;
7834 interp_add_imethod (gpointer method
)
7836 InterpMethod
*imethod
= (InterpMethod
*) method
;
7837 if (imethod
->opcounts
> opcount_threshold
)
7838 imethods
[num_methods
++] = imethod
;
7842 imethod_opcount_comparer (gconstpointer m1
, gconstpointer m2
)
7844 return (*(InterpMethod
**)m2
)->opcounts
- (*(InterpMethod
**)m1
)->opcounts
;
7848 interp_print_method_counts (void)
7850 MonoDomain
*domain
= mono_get_root_domain ();
7851 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
7853 mono_domain_jit_code_hash_lock (domain
);
7854 imethods
= (InterpMethod
**) malloc (info
->interp_code_hash
.num_entries
* sizeof (InterpMethod
*));
7855 mono_internal_hash_table_apply (&info
->interp_code_hash
, interp_add_imethod
);
7856 mono_domain_jit_code_hash_unlock (domain
);
7858 qsort (imethods
, num_methods
, sizeof (InterpMethod
*), imethod_opcount_comparer
);
7860 printf ("Total executed opcodes %ld\n", total_executed_opcodes
);
7861 long cumulative_executed_opcodes
= 0;
7862 for (int i
= 0; i
< num_methods
; i
++) {
7863 cumulative_executed_opcodes
+= imethods
[i
]->opcounts
;
7864 printf ("%d%% Opcounts %ld, calls %ld, Method %s, imethod ptr %p\n", (int)(cumulative_executed_opcodes
* 100 / total_executed_opcodes
), imethods
[i
]->opcounts
, imethods
[i
]->calls
, mono_method_full_name (imethods
[i
]->method
, TRUE
), imethods
[i
]);
7870 interp_set_optimizations (guint32 opts
)
7872 mono_interp_opt
= opts
;
7876 invalidate_transform (gpointer imethod_
)
7878 InterpMethod
*imethod
= (InterpMethod
*) imethod_
;
7879 imethod
->transformed
= FALSE
;
7883 interp_invalidate_transformed (MonoDomain
*domain
)
7885 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
7886 mono_domain_jit_code_hash_lock (domain
);
7887 mono_internal_hash_table_apply (&info
->interp_code_hash
, invalidate_transform
);
7888 mono_domain_jit_code_hash_unlock (domain
);
7892 interp_cleanup (void)
7895 interp_print_op_count ();
7898 interp_print_method_counts ();
7903 register_interp_stats (void)
7905 mono_counters_init ();
7906 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
7907 mono_counters_register ("Methods transformed", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
, &mono_interp_stats
.methods_transformed
);
7908 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.cprop_time
);
7909 mono_counters_register ("Total super instructions time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.super_instructions_time
);
7910 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.stloc_nps
);
7911 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.movlocs
);
7912 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.copy_propagations
);
7913 mono_counters_register ("Added pop count", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.added_pop_count
);
7914 mono_counters_register ("Constant folds", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.constant_folds
);
7915 mono_counters_register ("Ldlocas removed", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.ldlocas_removed
);
7916 mono_counters_register ("Super instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.super_instructions
);
7917 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.killed_instructions
);
7918 mono_counters_register ("Emitted instructions", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.emitted_instructions
);
7919 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
7920 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
7923 #undef MONO_EE_CALLBACK
7924 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
7926 static const MonoEECallbacks mono_interp_callbacks
= {
7931 mono_ee_interp_init (const char *opts
)
7933 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
7934 g_assert (!interp_init_done
);
7935 interp_init_done
= TRUE
;
7937 mono_native_tls_alloc (&thread_context_id
, NULL
);
7940 interp_parse_options (opts
);
7941 /* Don't do any optimizations if running under debugger */
7942 if (mini_get_debug_options ()->mdb_optimizations
)
7943 mono_interp_opt
= 0;
7944 mono_interp_transform_init ();
7946 mini_install_interp_callbacks (&mono_interp_callbacks
);
7948 register_interp_stats ();