3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001, 2002 Ximian, Inc.
27 #include <mono/utils/gc_wrapper.h>
28 #include <mono/utils/mono-math.h>
29 #include <mono/utils/mono-counters.h>
35 # define alloca __builtin_alloca
39 /* trim excessive headers */
40 #include <mono/metadata/image.h>
41 #include <mono/metadata/assembly-internals.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/metadata/mono-endian.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/loader.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/profiler-private.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/reflection.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/utils/atomic.h>
64 #include "interp-internals.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/mini-runtime.h>
69 #include <mono/mini/aot-runtime.h>
70 #include <mono/mini/llvm-runtime.h>
71 #include <mono/mini/llvmonly-runtime.h>
72 #include <mono/mini/jit-icalls.h>
73 #include <mono/mini/debugger-agent.h>
74 #include <mono/mini/ee.h>
75 #include <mono/mini/trace.h>
78 #include <mono/mini/mini-arm.h>
80 #include <mono/metadata/icall-decl.h>
83 #pragma warning(disable:4102) // label' : unreferenced label
86 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
88 /* Where we start the frame execution from */
89 guint16
*start_with_ip
;
91 * End ip of the exit_clause. We need it so we know whether the resume
92 * state is for this frame (which is called from EH) or for the original
93 * frame further down the stack.
96 /* When exiting this clause we also exit the frame */
98 /* Exception that we are filtering */
99 MonoException
*filter_exception
;
100 InterpFrame
*base_frame
;
104 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
106 frame
->parent
= parent_frame
;
107 frame
->stack_args
= method_args
;
108 frame
->retval
= method_retval
;
109 frame
->imethod
= rmethod
;
112 frame
->invoke_trap
= 0;
115 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
116 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
117 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
120 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL)
123 * List of classes whose methods will be executed by transitioning to JITted code.
126 GSList
*mono_interp_jit_classes
;
127 /* Optimizations enabled with interpreter */
128 int mono_interp_opt
= INTERP_OPT_INLINE
;
129 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
130 static gboolean ss_enabled
;
132 static gboolean interp_init_done
= FALSE
;
134 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
);
135 static InterpMethod
* lookup_method_pointer (gpointer addr
);
137 typedef void (*ICallMethod
) (InterpFrame
*frame
);
139 static MonoNativeTlsKey thread_context_id
;
141 #define DEBUG_INTERP 0
144 int mono_interp_traceopt
= 2;
145 /* If true, then we output the opcodes as we interpret them */
146 static int global_tracing
= 2;
148 static int debug_indent_level
= 0;
150 static int break_on_method
= 0;
151 static int nested_trace
= 0;
152 static GList
*db_methods
= NULL
;
153 static char* dump_args (InterpFrame
*inv
);
160 for (h
= 0; h
< debug_indent_level
; h
++)
165 db_match_method (gpointer data
, gpointer user_data
)
167 MonoMethod
*m
= (MonoMethod
*)user_data
;
168 MonoMethodDesc
*desc
= data
;
170 if (mono_method_desc_full_match (desc
, m
))
175 debug_enter (InterpFrame
*frame
, int *tracing
)
178 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
180 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
184 MonoMethod
*method
= frame
->imethod
->method
;
185 char *mn
, *args
= dump_args (frame
);
186 debug_indent_level
++;
188 mn
= mono_method_full_name (method
, FALSE
);
189 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
191 g_print ("%s)\n", args
);
197 #define DEBUG_LEAVE() \
200 args = dump_retval (frame); \
202 mn = mono_method_full_name (frame->imethod->method, FALSE); \
203 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
205 g_print (" => %s\n", args); \
207 debug_indent_level--; \
208 if (tracing == 3) global_tracing = 0; \
213 int mono_interp_traceopt
= 0;
214 static void debug_enter (InterpFrame
*frame
, int *tracing
)
217 #define DEBUG_LEAVE()
222 set_resume_state (ThreadContext
*context
, InterpFrame
*frame
)
225 context
->has_resume_state
= 0;
226 context
->handler_frame
= NULL
;
227 context
->handler_ei
= NULL
;
230 /* Set the current execution state to the resume state in context */
231 #define SET_RESUME_STATE(context) do { \
232 ip = (const guint16*)(context)->handler_ip; \
233 /* spec says stack should be empty at endfinally so it should be at the start too */ \
235 vt_sp = (unsigned char *) sp + imethod->stack_size; \
237 sp->data.p = frame->ex; \
240 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
241 while (finally_ips && \
242 finally_ips->data >= (context)->handler_ei->try_start && \
243 finally_ips->data < (context)->handler_ei->try_end) \
244 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
245 set_resume_state ((context), (frame)); \
250 * If this bit is set, it means the call has thrown the exception, and we
251 * reached this point because the EH code in mono_handle_exception ()
252 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
253 * has set the fields in context to indicate where we have to resume execution.
255 #define CHECK_RESUME_STATE(context) do { \
256 if ((context)->has_resume_state) { \
257 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
258 SET_RESUME_STATE (context); \
265 set_context (ThreadContext
*context
)
267 mono_native_tls_set_value (thread_context_id
, context
);
272 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
273 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
275 /* jit_tls assumes ownership of 'context' */
276 jit_tls
->interp_context
= context
;
279 static ThreadContext
*
282 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
283 if (context
== NULL
) {
284 context
= g_new0 (ThreadContext
, 1);
285 set_context (context
);
291 ves_real_abort (int line
, MonoMethod
*mh
,
292 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
295 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
296 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
297 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
298 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
299 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
300 mono_metadata_free_mh (header
);
303 #define ves_abort() \
305 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
306 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
310 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
312 InterpMethod
*imethod
;
313 MonoJitDomainInfo
*info
;
315 info
= domain_jit_info (domain
);
316 mono_domain_jit_code_hash_lock (domain
);
317 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
318 mono_domain_jit_code_hash_unlock (domain
);
323 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
325 #ifndef DISABLE_REMOTING
326 InterpMethod
*imethod
;
329 imethod
= lookup_method_pointer (addr
);
332 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
333 return_val_if_nok (error
, NULL
);
336 g_assert (mono_use_interpreter
);
338 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
339 return_val_if_nok (error
, NULL
);
340 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
342 g_assert_not_reached ();
348 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
350 InterpMethod
*imethod
;
351 MonoJitDomainInfo
*info
;
352 MonoMethodSignature
*sig
;
357 info
= domain_jit_info (domain
);
358 mono_domain_jit_code_hash_lock (domain
);
359 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
360 mono_domain_jit_code_hash_unlock (domain
);
364 sig
= mono_method_signature_internal (method
);
366 imethod
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
367 imethod
->method
= method
;
368 imethod
->domain
= domain
;
369 imethod
->param_count
= sig
->param_count
;
370 imethod
->hasthis
= sig
->hasthis
;
371 imethod
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
372 imethod
->rtype
= mini_get_underlying_type (sig
->ret
);
373 imethod
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
374 for (i
= 0; i
< sig
->param_count
; ++i
)
375 imethod
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
377 mono_domain_jit_code_hash_lock (domain
);
378 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
379 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, imethod
);
380 mono_domain_jit_code_hash_unlock (domain
);
382 imethod
->prof_flags
= mono_profiler_get_call_instrumentation_flags (imethod
->method
);
387 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM) || defined (_MSC_VER)
388 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
389 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
391 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
392 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
393 * (registers are not accurate), thus resuming to the label does not work. */
394 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
395 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
397 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
398 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
399 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
400 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
401 MONO_CONTEXT_SET_IP (&(ext).ctx, (exit_addr)); \
402 mono_arch_do_ip_adjustment (&(ext).ctx);
404 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) g_error ("requires working mono-context");
407 /* INTERP_PUSH_LMF_WITH_CTX:
409 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
410 * This is needed to resume into the interp when the exception is thrown from
411 * native code (see ./mono/tests/install_eh_callback.exe).
413 * This must be a macro in order to retrieve the right register values for
416 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_addr) \
417 memset (&(ext), 0, sizeof (MonoLMFExt)); \
418 (ext).interp_exit_data = (frame); \
419 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), (exit_addr)); \
420 mono_push_lmf (&(ext));
425 * Push an LMF frame on the LMF stack
426 * to mark the transition to native code.
427 * This is needed for the native code to
428 * be able to do stack walks.
431 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
433 memset (ext
, 0, sizeof (MonoLMFExt
));
434 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
435 ext
->interp_exit_data
= frame
;
441 interp_pop_lmf (MonoLMFExt
*ext
)
443 mono_pop_lmf (&ext
->lmf
);
447 get_virtual_method (InterpMethod
*imethod
, MonoObject
*obj
)
449 MonoMethod
*m
= imethod
->method
;
450 MonoDomain
*domain
= imethod
->domain
;
451 InterpMethod
*ret
= NULL
;
454 #ifndef DISABLE_REMOTING
455 if (mono_object_is_transparent_proxy (obj
)) {
456 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
457 mono_error_assert_ok (error
);
458 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
459 mono_error_assert_ok (error
);
464 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
465 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
466 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
467 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
474 mono_class_setup_vtable (obj
->vtable
->klass
);
476 int slot
= mono_method_get_vtable_slot (m
);
477 if (mono_class_is_interface (m
->klass
)) {
478 g_assert (obj
->vtable
->klass
!= m
->klass
);
479 /* TODO: interface offset lookup is slow, go through IMT instead */
480 gboolean non_exact_match
;
481 slot
+= mono_class_interface_offset_with_variance (obj
->vtable
->klass
, m
->klass
, &non_exact_match
);
484 MonoMethod
*virtual_method
= m_class_get_vtable (mono_object_class (obj
)) [slot
];
485 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
486 MonoGenericContext context
= { NULL
, NULL
};
488 if (mono_class_is_ginst (virtual_method
->klass
))
489 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
490 else if (mono_class_is_gtd (virtual_method
->klass
))
491 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
492 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
494 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
495 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
498 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
499 virtual_method
= mono_marshal_get_native_wrapper (virtual_method
, FALSE
, FALSE
);
502 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
503 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
506 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
507 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
508 return virtual_imethod
;
512 InterpMethod
*imethod
;
513 InterpMethod
*target_imethod
;
516 /* domain lock must be held */
518 append_imethod (MonoDomain
*domain
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
521 InterpVTableEntry
*entry
;
523 entry
= (InterpVTableEntry
*) mono_mempool_alloc (domain
->mp
, sizeof (InterpVTableEntry
));
524 entry
->imethod
= imethod
;
525 entry
->target_imethod
= target_imethod
;
526 ret
= g_slist_append_mempool (domain
->mp
, list
, entry
);
532 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
534 while (list
!= NULL
) {
535 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
536 if (entry
->imethod
== imethod
)
537 return entry
->target_imethod
;
544 get_method_table (MonoObject
*obj
, int offset
)
547 return obj
->vtable
->interp_vtable
;
549 return (gpointer
*)obj
->vtable
;
554 alloc_method_table (MonoObject
*obj
, int offset
)
559 table
= mono_domain_alloc0 (obj
->vtable
->domain
, m_class_get_vtable_size (obj
->vtable
->klass
) * sizeof (gpointer
));
560 obj
->vtable
->interp_vtable
= table
;
562 table
= (gpointer
*)obj
->vtable
;
569 get_virtual_method_fast (MonoObject
*obj
, InterpMethod
*imethod
, int offset
)
573 #ifndef DISABLE_REMOTING
575 if (mono_object_is_transparent_proxy (obj
))
576 return get_virtual_method (imethod
, obj
);
579 table
= get_method_table (obj
, offset
);
582 /* Lazily allocate method table */
583 mono_domain_lock (obj
->vtable
->domain
);
584 table
= get_method_table (obj
, offset
);
586 table
= alloc_method_table (obj
, offset
);
587 mono_domain_unlock (obj
->vtable
->domain
);
590 if (!table
[offset
]) {
591 InterpMethod
*target_imethod
= get_virtual_method (imethod
, obj
);
592 /* Lazily initialize the method table slot */
593 mono_domain_lock (obj
->vtable
->domain
);
594 if (!table
[offset
]) {
595 if (imethod
->method
->is_inflated
|| offset
< 0)
596 table
[offset
] = append_imethod (obj
->vtable
->domain
, NULL
, imethod
, target_imethod
);
598 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
600 mono_domain_unlock (obj
->vtable
->domain
);
603 if ((gsize
)table
[offset
] & 0x1) {
604 /* Non generic virtual call. Only one method in slot */
605 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
607 /* Virtual generic or interface call. Multiple methods in slot */
608 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
610 if (!target_imethod
) {
611 target_imethod
= get_virtual_method (imethod
, obj
);
612 mono_domain_lock (obj
->vtable
->domain
);
613 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
614 table
[offset
] = append_imethod (obj
->vtable
->domain
, (GSList
*)table
[offset
], imethod
, target_imethod
);
615 mono_domain_unlock (obj
->vtable
->domain
);
617 return target_imethod
;
622 stackval_from_data (MonoType
*type_
, stackval
*result
, void *data
, gboolean pinvoke
)
624 MonoType
*type
= mini_native_type_replace_type (type_
);
626 switch (type
->type
) {
627 case MONO_TYPE_OBJECT
:
628 case MONO_TYPE_CLASS
:
629 case MONO_TYPE_STRING
:
630 case MONO_TYPE_ARRAY
:
631 case MONO_TYPE_SZARRAY
:
636 result
->data
.p
= *(gpointer
*)data
;
639 switch (type
->type
) {
643 result
->data
.i
= *(gint8
*)data
;
646 case MONO_TYPE_BOOLEAN
:
647 result
->data
.i
= *(guint8
*)data
;
650 result
->data
.i
= *(gint16
*)data
;
654 result
->data
.i
= *(guint16
*)data
;
657 result
->data
.i
= *(gint32
*)data
;
661 result
->data
.nati
= *(mono_i
*)data
;
664 result
->data
.p
= *(gpointer
*)data
;
667 result
->data
.i
= *(guint32
*)data
;
670 /* memmove handles unaligned case */
671 memmove (&result
->data
.f_r4
, data
, sizeof (float));
675 memmove (&result
->data
.l
, data
, sizeof (gint64
));
678 memmove (&result
->data
.f
, data
, sizeof (double));
680 case MONO_TYPE_STRING
:
681 case MONO_TYPE_SZARRAY
:
682 case MONO_TYPE_CLASS
:
683 case MONO_TYPE_OBJECT
:
684 case MONO_TYPE_ARRAY
:
685 result
->data
.p
= *(gpointer
*)data
;
687 case MONO_TYPE_VALUETYPE
:
688 if (m_class_is_enumtype (type
->data
.klass
)) {
689 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
691 } else if (pinvoke
) {
692 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
694 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
697 case MONO_TYPE_GENERICINST
: {
698 if (mono_type_generic_inst_is_valuetype (type
)) {
699 mono_value_copy_internal (result
->data
.vt
, data
, mono_class_from_mono_type_internal (type
));
702 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
706 g_error ("got type 0x%02x", type
->type
);
711 stackval_to_data (MonoType
*type_
, stackval
*val
, void *data
, gboolean pinvoke
)
713 MonoType
*type
= mini_native_type_replace_type (type_
);
715 gpointer
*p
= (gpointer
*)data
;
719 /* printf ("TODAT0 %p\n", data); */
720 switch (type
->type
) {
723 guint8
*p
= (guint8
*)data
;
727 case MONO_TYPE_BOOLEAN
: {
728 guint8
*p
= (guint8
*)data
;
729 *p
= (val
->data
.i
!= 0);
734 case MONO_TYPE_CHAR
: {
735 guint16
*p
= (guint16
*)data
;
740 mono_i
*p
= (mono_i
*)data
;
741 /* In theory the value used by stloc should match the local var type
742 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
743 a native int - both by csc and mcs). Not sure what to do about sign extension
744 as it is outside the spec... doing the obvious */
745 *p
= (mono_i
)val
->data
.nati
;
749 mono_u
*p
= (mono_u
*)data
;
751 *p
= (mono_u
)val
->data
.nati
;
756 gint32
*p
= (gint32
*)data
;
762 memmove (data
, &val
->data
.l
, sizeof (gint64
));
766 /* memmove handles unaligned case */
767 memmove (data
, &val
->data
.f_r4
, sizeof (float));
771 memmove (data
, &val
->data
.f
, sizeof (double));
774 case MONO_TYPE_STRING
:
775 case MONO_TYPE_SZARRAY
:
776 case MONO_TYPE_CLASS
:
777 case MONO_TYPE_OBJECT
:
778 case MONO_TYPE_ARRAY
: {
779 gpointer
*p
= (gpointer
*) data
;
780 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
783 case MONO_TYPE_PTR
: {
784 gpointer
*p
= (gpointer
*) data
;
788 case MONO_TYPE_VALUETYPE
:
789 if (m_class_is_enumtype (type
->data
.klass
)) {
790 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
792 } else if (pinvoke
) {
793 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
795 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
798 case MONO_TYPE_GENERICINST
: {
799 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
801 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
802 mono_value_copy_internal (data
, val
->data
.vt
, mono_class_from_mono_type_internal (type
));
805 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
809 g_error ("got type %x", type
->type
);
814 * Same as stackval_to_data but return address of storage instead
815 * of copying the value.
818 stackval_to_data_addr (MonoType
*type_
, stackval
*val
)
820 MonoType
*type
= mini_native_type_replace_type (type_
);
824 switch (type
->type
) {
827 case MONO_TYPE_BOOLEAN
:
836 return &val
->data
.nati
;
841 return &val
->data
.f_r4
;
844 case MONO_TYPE_STRING
:
845 case MONO_TYPE_SZARRAY
:
846 case MONO_TYPE_CLASS
:
847 case MONO_TYPE_OBJECT
:
848 case MONO_TYPE_ARRAY
:
851 case MONO_TYPE_VALUETYPE
:
852 if (m_class_is_enumtype (type
->data
.klass
))
853 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
856 case MONO_TYPE_TYPEDBYREF
:
858 case MONO_TYPE_GENERICINST
: {
859 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
861 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
863 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
866 g_error ("got type %x", type
->type
);
872 * Throw an exception from the interpreter.
874 static MONO_NEVER_INLINE
void
875 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, gconstpointer ip
, gboolean rethrow
)
880 interp_push_lmf (&ext
, frame
);
881 frame
->ip
= (const guint16
*)ip
;
884 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
885 MonoException
*mono_ex
= (MonoException
*) ex
;
887 mono_ex
->stack_trace
= NULL
;
888 mono_ex
->trace_ips
= NULL
;
891 mono_error_assert_ok (error
);
894 memset (&ctx
, 0, sizeof (MonoContext
));
895 MONO_CONTEXT_SET_SP (&ctx
, frame
);
898 * Call the JIT EH code. The EH code will call back to us using:
899 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
900 * Since ctx.ip is 0, this will start unwinding from the LMF frame
901 * pushed above, which points to our frames.
903 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
904 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
905 /* We need to unwind into non-interpreter code */
906 mono_restore_context (&ctx
);
907 g_assert_not_reached ();
910 interp_pop_lmf (&ext
);
912 g_assert (context
->has_resume_state
);
915 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
917 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
918 CHECK_RESUME_STATE(context); \
921 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
923 #define EXCEPTION_CHECKPOINT \
925 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
926 MonoException *exc = mono_thread_interruption_checkpoint (); \
928 THROW_EX (exc, ip); \
934 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
937 intptr_t *lower_bounds
;
941 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
942 for (i
= 0; i
< param_count
; ++i
) {
943 lengths
[i
] = values
->data
.i
;
946 if (m_class_get_rank (klass
) == param_count
) {
947 /* Only lengths provided. */
950 /* lower bounds are first. */
951 lower_bounds
= (intptr_t *) lengths
;
952 lengths
+= m_class_get_rank (klass
);
954 obj
= (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
959 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
961 g_assert (!frame
->ex
);
962 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
966 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
967 guint32 idx
= sp
[i
].data
.i
;
968 guint32 lower
= ao
->bounds
[i
].lower_bound
;
969 guint32 len
= ao
->bounds
[i
].length
;
970 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
971 frame
->ex
= mono_get_exception_index_out_of_range ();
974 pos
= (pos
* len
) + idx
- lower
;
978 if (safe
&& pos
>= ao
->max_length
) {
979 frame
->ex
= mono_get_exception_index_out_of_range ();
987 ves_array_set (InterpFrame
*frame
, stackval
*sp
, MonoMethodSignature
*sig
)
989 MonoObject
*o
= sp
->data
.o
;
990 MonoArray
*ao
= (MonoArray
*) o
;
991 MonoClass
*ac
= o
->vtable
->klass
;
993 g_assert (m_class_get_rank (ac
) >= 1);
995 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, TRUE
);
999 int val_index
= 1 + m_class_get_rank (ac
);
1000 if (sp
[val_index
].data
.p
&& !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o
)))) {
1002 MonoObject
*isinst
= mono_object_isinst_checked (sp
[val_index
].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
1003 mono_error_cleanup (error
);
1005 frame
->ex
= mono_get_exception_array_type_mismatch ();
1010 gint32 esize
= mono_array_element_size (ac
);
1011 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1013 MonoType
*mt
= sig
->params
[m_class_get_rank (ac
)];
1014 stackval_to_data (mt
, &sp
[val_index
], ea
, FALSE
);
1018 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1020 MonoObject
*o
= sp
->data
.o
;
1021 MonoArray
*ao
= (MonoArray
*) o
;
1022 MonoClass
*ac
= o
->vtable
->klass
;
1024 g_assert (m_class_get_rank (ac
) >= 1);
1026 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, safe
);
1030 gint32 esize
= mono_array_element_size (ac
);
1031 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1033 MonoType
*mt
= sig
->ret
;
1034 stackval_from_data (mt
, retval
, ea
, FALSE
);
1038 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1040 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1042 g_assert (m_class_get_rank (ac
) >= 1);
1044 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
1048 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
)) {
1049 frame
->ex
= mono_get_exception_array_type_mismatch ();
1052 gint32 esize
= mono_array_element_size (ac
);
1053 return mono_array_addr_with_size_fast (ao
, esize
, pos
);
1056 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1057 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1060 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1061 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1063 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1066 g_assert (mono_arm_eabi_supported ());
1067 int i8_align
= mono_arm_i8_align ();
1077 for (int i
= 0; i
< sig
->param_count
; i
++) {
1078 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1080 case MONO_TYPE_BOOLEAN
:
1081 case MONO_TYPE_CHAR
:
1091 case MONO_TYPE_SZARRAY
:
1092 case MONO_TYPE_CLASS
:
1093 case MONO_TYPE_OBJECT
:
1094 case MONO_TYPE_STRING
:
1095 case MONO_TYPE_VALUETYPE
:
1096 case MONO_TYPE_GENERICINST
:
1097 #if SIZEOF_VOID_P == 8
1103 #if SIZEOF_VOID_P == 4
1107 /* pairs begin at even registers */
1108 if (i8_align
== 8 && margs
->ilen
& 1)
1115 #if SIZEOF_VOID_P == 8
1120 #if SIZEOF_VOID_P == 4
1126 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1130 if (margs
->ilen
> 0)
1131 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1133 if (margs
->flen
> 0)
1134 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1136 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1137 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1139 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1140 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1147 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1151 for (int i
= 0; i
< sig
->param_count
; i
++) {
1152 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1154 case MONO_TYPE_BOOLEAN
:
1155 case MONO_TYPE_CHAR
:
1165 case MONO_TYPE_SZARRAY
:
1166 case MONO_TYPE_CLASS
:
1167 case MONO_TYPE_OBJECT
:
1168 case MONO_TYPE_STRING
:
1169 case MONO_TYPE_VALUETYPE
:
1170 case MONO_TYPE_GENERICINST
:
1171 #if SIZEOF_VOID_P == 8
1175 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1177 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1181 #if SIZEOF_VOID_P == 4
1183 case MONO_TYPE_U8
: {
1184 stackval
*sarg
= &frame
->stack_args
[i
];
1186 /* pairs begin at even registers */
1187 if (i8_align
== 8 && int_i
& 1)
1190 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1192 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1194 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i
- 1, int_i
, *((guint64
*) &margs
->iargs
[int_i
- 1]), sarg
->data
.pair
.hi
, sarg
->data
.pair
.lo
, i
);
1202 if (ptype
== MONO_TYPE_R4
)
1203 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1205 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1207 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
);
1209 #if SIZEOF_VOID_P == 4
1216 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1220 switch (sig
->ret
->type
) {
1221 case MONO_TYPE_BOOLEAN
:
1222 case MONO_TYPE_CHAR
:
1232 case MONO_TYPE_SZARRAY
:
1233 case MONO_TYPE_CLASS
:
1234 case MONO_TYPE_OBJECT
:
1235 case MONO_TYPE_STRING
:
1238 case MONO_TYPE_VALUETYPE
:
1239 case MONO_TYPE_GENERICINST
:
1240 margs
->retval
= &(frame
->retval
->data
.p
);
1241 margs
->is_float_ret
= 0;
1245 margs
->retval
= &(frame
->retval
->data
.p
);
1246 margs
->is_float_ret
= 1;
1248 case MONO_TYPE_VOID
:
1249 margs
->retval
= NULL
;
1252 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1260 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1262 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1265 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1267 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1271 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1273 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1276 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1277 else if (sig
->hasthis
&& index
== 0)
1278 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1280 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1284 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1286 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1289 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1291 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1295 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1297 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1298 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1299 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1301 switch (type
->type
) {
1302 case MONO_TYPE_GENERICINST
:
1303 if (!MONO_TYPE_IS_REFERENCE (type
))
1304 val
->data
.vt
= storage
;
1306 case MONO_TYPE_VALUETYPE
:
1307 val
->data
.vt
= storage
;
1310 g_assert_not_reached ();
1315 get_interp_to_native_trampoline (void)
1317 static MonoPIFunc trampoline
= NULL
;
1320 if (mono_ee_features
.use_aot_trampolines
) {
1321 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1323 MonoTrampInfo
*info
;
1324 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1326 // mono_tramp_info_register (info, NULL);
1328 mono_memory_barrier ();
1334 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1336 get_interp_to_native_trampoline () (addr
, ccontext
);
1339 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1340 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1341 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
)
1348 g_assert (!frame
->imethod
);
1350 static MonoPIFunc entry_func
= NULL
;
1352 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1354 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
);
1355 mono_error_assert_ok (error
);
1357 entry_func
= get_interp_to_native_trampoline ();
1359 mono_memory_barrier ();
1362 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1363 CallContext ccontext
;
1364 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1367 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1371 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, &&exit_pinvoke
);
1372 entry_func ((gpointer
) addr
, args
);
1373 interp_pop_lmf (&ext
);
1375 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1377 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1379 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1380 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1382 g_free (margs
->iargs
);
1383 g_free (margs
->fargs
);
1386 goto exit_pinvoke
; // prevent unused label warning in some configurations
1392 * interp_init_delegate:
1394 * Initialize del->interp_method.
1397 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1401 if (del
->interp_method
) {
1402 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1403 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1404 } else if (del
->method
) {
1405 /* Delegate created dynamically */
1406 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1408 /* Created from JITted code */
1409 g_assert_not_reached ();
1412 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1415 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1416 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1417 mono_class_is_abstract (method
->klass
))
1418 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
);
1420 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1421 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1422 const char *name
= method
->name
;
1423 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1425 * When invoking the delegate interp_method is executed directly. If it's an
1426 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1428 * FIXME We should do this later, when we also know the delegate on which the
1429 * target method is called.
1431 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1432 mono_error_assert_ok (error
);
1436 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1437 /* Return any errors from method compilation */
1438 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1439 return_if_nok (error
);
1444 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1447 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1449 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1451 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1452 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1453 /* virtual invoke delegates must not have null check */
1454 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1455 && MONO_HANDLE_IS_NULL (target
)) {
1456 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1461 g_assert (imethod
->method
);
1462 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1463 return_if_nok (error
);
1465 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1467 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1472 * runtime specifies that the implementation of the method is automatically
1473 * provided by the runtime and is primarily used for the methods of delegates.
1475 static MONO_NEVER_INLINE
void
1476 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1478 const char *name
= method
->name
;
1479 mono_class_init_internal (method
->klass
);
1481 if (method
->klass
== mono_defaults
.array_class
) {
1482 if (!strcmp (name
, "UnsafeMov")) {
1483 /* TODO: layout checks */
1484 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1487 if (!strcmp (name
, "UnsafeLoad")) {
1488 ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1491 } else if (mini_class_is_system_array (method
->klass
)) {
1492 MonoObject
*obj
= (MonoObject
*) sp
->data
.p
;
1494 frame
->ex
= mono_get_exception_null_reference ();
1497 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1498 ves_array_set (frame
, sp
, sig
);
1501 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1502 ves_array_get (frame
, sp
, retval
, sig
, TRUE
);
1507 g_error ("Don't know how to exec runtime method %s.%s::%s",
1508 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1514 dump_stack (stackval
*stack
, stackval
*sp
)
1516 stackval
*s
= stack
;
1517 GString
*str
= g_string_new ("");
1520 return g_string_free (str
, FALSE
);
1523 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1526 return g_string_free (str
, FALSE
);
1530 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1532 switch (type
->type
) {
1539 case MONO_TYPE_CHAR
:
1540 case MONO_TYPE_BOOLEAN
:
1541 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1543 case MONO_TYPE_STRING
:
1544 case MONO_TYPE_SZARRAY
:
1545 case MONO_TYPE_CLASS
:
1546 case MONO_TYPE_OBJECT
:
1547 case MONO_TYPE_ARRAY
:
1551 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1553 case MONO_TYPE_VALUETYPE
:
1554 if (m_class_is_enumtype (type
->data
.klass
))
1555 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1557 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1560 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1563 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1568 GString
*res
= g_string_new ("");
1569 mono_type_get_desc (res
, type
, TRUE
);
1570 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1571 g_string_free (res
, TRUE
);
1578 dump_retval (InterpFrame
*inv
)
1580 GString
*str
= g_string_new ("");
1581 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1583 if (ret
->type
!= MONO_TYPE_VOID
)
1584 dump_stackval (str
, inv
->retval
, ret
);
1586 return g_string_free (str
, FALSE
);
1590 dump_args (InterpFrame
*inv
)
1592 GString
*str
= g_string_new ("");
1594 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1596 if (signature
->param_count
== 0 && !signature
->hasthis
)
1597 return g_string_free (str
, FALSE
);
1599 if (signature
->hasthis
) {
1600 MonoMethod
*method
= inv
->imethod
->method
;
1601 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1604 for (i
= 0; i
< signature
->param_count
; ++i
)
1605 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1607 return g_string_free (str
, FALSE
);
1611 #define CHECK_ADD_OVERFLOW(a,b) \
1612 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1613 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1615 #define CHECK_SUB_OVERFLOW(a,b) \
1616 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1617 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1619 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1620 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1622 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1623 (guint32)(a) < (guint32)(b) ? -1 : 0
1625 #define CHECK_ADD_OVERFLOW64(a,b) \
1626 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1627 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1629 #define CHECK_SUB_OVERFLOW64(a,b) \
1630 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1631 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1633 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1634 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1636 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1637 (guint64)(a) < (guint64)(b) ? -1 : 0
1639 #if SIZEOF_VOID_P == 4
1640 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1641 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1643 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1644 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1647 /* Resolves to TRUE if the operands would overflow */
1648 #define CHECK_MUL_OVERFLOW(a,b) \
1649 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1650 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1651 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1652 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1653 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1654 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1655 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1657 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1658 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1659 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1661 #define CHECK_MUL_OVERFLOW64(a,b) \
1662 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1663 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1664 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1665 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1666 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1667 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1668 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1670 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1671 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1672 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1674 #if SIZEOF_VOID_P == 4
1675 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1676 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1678 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1679 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1683 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1686 ThreadContext
*context
= get_context ();
1687 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1688 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1690 MonoMethod
*target_method
= method
;
1698 MonoDomain
*domain
= mono_domain_get ();
1700 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1701 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1702 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1704 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1706 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1710 args
[0].data
.p
= obj
;
1712 args
[0].data
.p
= NULL
;
1713 args
[1].data
.p
= params
;
1714 args
[2].data
.p
= exc
;
1715 args
[3].data
.p
= target_method
;
1717 INIT_FRAME (&frame
, NULL
, args
, &result
, domain
, invoke_wrapper
, error
);
1720 frame
.invoke_trap
= 1;
1722 interp_exec_method (&frame
, context
);
1726 *exc
= (MonoObject
*) frame
.ex
;
1729 mono_error_set_exception_instance (error
, frame
.ex
);
1732 return (MonoObject
*)result
.data
.p
;
1736 InterpMethod
*rmethod
;
1740 gpointer
*many_args
;
1743 /* Main function for entering the interpreter from compiled code */
1745 interp_entry (InterpEntryData
*data
)
1748 InterpMethod
*rmethod
;
1749 ThreadContext
*context
;
1753 MonoMethodSignature
*sig
;
1755 gpointer orig_domain
, attach_cookie
;
1758 if ((gsize
)data
->rmethod
& 1) {
1760 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1761 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1763 rmethod
= data
->rmethod
;
1765 if (rmethod
->needs_thread_attach
)
1766 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1768 context
= get_context ();
1770 method
= rmethod
->method
;
1771 sig
= mono_method_signature_internal (method
);
1773 // FIXME: Optimize this
1775 //printf ("%s\n", mono_method_full_name (method, 1));
1779 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1781 args
[0].data
.p
= data
->this_arg
;
1784 if (data
->many_args
)
1785 params
= data
->many_args
;
1787 params
= data
->args
;
1788 for (i
= 0; i
< sig
->param_count
; ++i
) {
1789 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1790 if (sig
->params
[i
]->byref
) {
1791 args
[a_index
].data
.p
= params
[i
];
1794 type
= rmethod
->param_types
[i
];
1795 switch (type
->type
) {
1796 case MONO_TYPE_VALUETYPE
:
1797 args
[a_index
].data
.p
= params
[i
];
1799 case MONO_TYPE_GENERICINST
:
1800 if (MONO_TYPE_IS_REFERENCE (type
))
1801 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1803 args
[a_index
].data
.vt
= params
[i
];
1806 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1811 memset (&result
, 0, sizeof (result
));
1812 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1814 type
= rmethod
->rtype
;
1815 switch (type
->type
) {
1816 case MONO_TYPE_GENERICINST
:
1817 if (!MONO_TYPE_IS_REFERENCE (type
))
1818 frame
.retval
->data
.vt
= data
->res
;
1820 case MONO_TYPE_VALUETYPE
:
1821 frame
.retval
->data
.vt
= data
->res
;
1827 interp_exec_method (&frame
, context
);
1829 if (rmethod
->needs_thread_attach
)
1830 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
1832 if (mono_llvm_only
) {
1834 mono_llvm_reraise_exception (frame
.ex
);
1836 g_assert (frame
.ex
== NULL
);
1839 type
= rmethod
->rtype
;
1840 switch (type
->type
) {
1841 case MONO_TYPE_VOID
:
1843 case MONO_TYPE_OBJECT
:
1844 /* No need for a write barrier */
1845 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1847 case MONO_TYPE_GENERICINST
:
1848 if (MONO_TYPE_IS_REFERENCE (type
)) {
1849 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1851 /* Already set before the call */
1854 case MONO_TYPE_VALUETYPE
:
1855 /* Already set before the call */
1858 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1864 do_icall (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
)
1867 case MINT_ICALL_V_V
: {
1868 typedef void (*T
)(void);
1873 case MINT_ICALL_V_P
: {
1874 typedef gpointer (*T
)(void);
1877 sp
[-1].data
.p
= func ();
1880 case MINT_ICALL_P_V
: {
1881 typedef void (*T
)(gpointer
);
1883 func (sp
[-1].data
.p
);
1887 case MINT_ICALL_P_P
: {
1888 typedef gpointer (*T
)(gpointer
);
1890 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1893 case MINT_ICALL_PP_V
: {
1894 typedef void (*T
)(gpointer
,gpointer
);
1897 func (sp
[0].data
.p
, sp
[1].data
.p
);
1900 case MINT_ICALL_PP_P
: {
1901 typedef gpointer (*T
)(gpointer
,gpointer
);
1904 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1907 case MINT_ICALL_PPP_V
: {
1908 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
1911 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1914 case MINT_ICALL_PPP_P
: {
1915 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
1918 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
1921 case MINT_ICALL_PPPP_V
: {
1922 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1925 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1928 case MINT_ICALL_PPPP_P
: {
1929 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1932 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1935 case MINT_ICALL_PPPPP_V
: {
1936 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1939 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
1942 case MINT_ICALL_PPPPP_P
: {
1943 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1946 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
);
1949 case MINT_ICALL_PPPPPP_V
: {
1950 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1953 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
);
1956 case MINT_ICALL_PPPPPP_P
: {
1957 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1960 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
);
1964 g_assert_not_reached ();
1967 /* convert the native representation to the stackval representation */
1969 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
1974 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1975 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
1976 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
)
1979 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, &&exit_icall
);
1981 sp
= do_icall (frame
, sig
, op
, sp
, ptr
);
1983 interp_pop_lmf (&ext
);
1985 goto exit_icall
; // prevent unused label warning in some configurations
1992 gpointer jit_wrapper
;
1994 MonoFtnDesc
*ftndesc
;
1998 jit_call_cb (gpointer arg
)
2000 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2001 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2002 int pindex
= cb_data
->pindex
;
2003 gpointer
*args
= cb_data
->args
;
2004 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2008 typedef void (*T
)(gpointer
);
2009 T func
= (T
)jit_wrapper
;
2015 typedef void (*T
)(gpointer
, gpointer
);
2016 T func
= (T
)jit_wrapper
;
2018 func (args
[0], &ftndesc
);
2022 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2023 T func
= (T
)jit_wrapper
;
2025 func (args
[0], args
[1], &ftndesc
);
2029 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2030 T func
= (T
)jit_wrapper
;
2032 func (args
[0], args
[1], args
[2], &ftndesc
);
2036 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2037 T func
= (T
)jit_wrapper
;
2039 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2043 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2044 T func
= (T
)jit_wrapper
;
2046 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2050 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2051 T func
= (T
)jit_wrapper
;
2053 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2057 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2058 T func
= (T
)jit_wrapper
;
2060 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2064 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2065 T func
= (T
)jit_wrapper
;
2067 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2071 g_assert_not_reached ();
2076 static MONO_NEVER_INLINE stackval
*
2077 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2079 MonoMethodSignature
*sig
;
2080 MonoFtnDesc ftndesc
;
2081 guint8 res_buf
[256];
2085 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2088 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2089 * by ref and return a return value using an explicit return value argument.
2091 if (!rmethod
->jit_wrapper
) {
2092 MonoMethod
*method
= rmethod
->method
;
2094 sig
= mono_method_signature_internal (method
);
2097 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2098 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2100 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2101 mono_error_assert_ok (error
);
2103 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2104 return_val_if_nok (error
, NULL
);
2107 rmethod
->jit_addr
= addr
;
2108 rmethod
->jit_sig
= sig
;
2109 mono_memory_barrier ();
2110 rmethod
->jit_wrapper
= jit_wrapper
;
2113 sig
= rmethod
->jit_sig
;
2116 sp
-= sig
->param_count
;
2120 ftndesc
.addr
= rmethod
->jit_addr
;
2123 // FIXME: Optimize this
2127 int stack_index
= 0;
2128 if (rmethod
->hasthis
) {
2129 args
[pindex
++] = sp
[0].data
.p
;
2132 type
= rmethod
->rtype
;
2133 if (type
->type
!= MONO_TYPE_VOID
) {
2134 if (MONO_TYPE_ISSTRUCT (type
))
2135 args
[pindex
++] = vt_sp
;
2137 args
[pindex
++] = res_buf
;
2139 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2140 MonoType
*t
= rmethod
->param_types
[i
];
2141 stackval
*sval
= &sp
[stack_index
+ i
];
2142 if (sig
->params
[i
]->byref
) {
2143 args
[pindex
++] = sval
->data
.p
;
2144 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2145 args
[pindex
++] = sval
->data
.p
;
2146 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2147 args
[pindex
++] = &sval
->data
.p
;
2156 case MONO_TYPE_VALUETYPE
:
2157 args
[pindex
++] = &sval
->data
.i
;
2160 case MONO_TYPE_FNPTR
:
2163 case MONO_TYPE_OBJECT
:
2164 args
[pindex
++] = &sval
->data
.p
;
2168 args
[pindex
++] = &sval
->data
.l
;
2171 args
[pindex
++] = &sval
->data
.f_r4
;
2174 args
[pindex
++] = &sval
->data
.f
;
2177 printf ("%s\n", mono_type_full_name (t
));
2178 g_assert_not_reached ();
2183 interp_push_lmf (&ext
, frame
);
2185 JitCallCbData cb_data
;
2186 memset (&cb_data
, 0, sizeof (cb_data
));
2187 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2188 cb_data
.pindex
= pindex
;
2189 cb_data
.args
= args
;
2190 cb_data
.ftndesc
= &ftndesc
;
2192 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2193 /* Catch the exception thrown by the native code using a try-catch */
2194 gboolean thrown
= FALSE
;
2195 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2196 interp_pop_lmf (&ext
);
2198 MonoObject
*obj
= mono_llvm_load_exception ();
2200 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2204 jit_call_cb (&cb_data
);
2205 interp_pop_lmf (&ext
);
2208 MonoType
*rtype
= rmethod
->rtype
;
2209 switch (rtype
->type
) {
2210 case MONO_TYPE_VOID
:
2211 case MONO_TYPE_OBJECT
:
2212 case MONO_TYPE_STRING
:
2213 case MONO_TYPE_CLASS
:
2214 case MONO_TYPE_ARRAY
:
2215 case MONO_TYPE_SZARRAY
:
2219 sp
->data
.p
= *(gpointer
*)res_buf
;
2222 sp
->data
.i
= *(gint8
*)res_buf
;
2225 sp
->data
.i
= *(guint8
*)res_buf
;
2228 sp
->data
.i
= *(gint16
*)res_buf
;
2231 sp
->data
.i
= *(guint16
*)res_buf
;
2234 sp
->data
.i
= *(gint32
*)res_buf
;
2237 sp
->data
.i
= *(guint32
*)res_buf
;
2240 sp
->data
.l
= *(gint64
*)res_buf
;
2243 sp
->data
.l
= *(guint64
*)res_buf
;
2246 sp
->data
.f_r4
= *(float*)res_buf
;
2249 sp
->data
.f
= *(double*)res_buf
;
2251 case MONO_TYPE_TYPEDBYREF
:
2252 case MONO_TYPE_VALUETYPE
:
2253 /* The result was written to vt_sp */
2256 case MONO_TYPE_GENERICINST
:
2257 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2258 sp
->data
.p
= *(gpointer
*)res_buf
;
2260 /* The result was written to vt_sp */
2265 g_print ("%s\n", mono_type_full_name (rtype
));
2266 g_assert_not_reached ();
2273 static MONO_NEVER_INLINE
void
2274 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2277 interp_push_lmf (&ext
, frame
);
2279 interp_pop_lmf (&ext
);
2282 static MONO_NEVER_INLINE
void
2283 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2286 /* Don't push lmf if we have no interp data */
2287 gboolean push_lmf
= frame
->parent
!= NULL
;
2290 /* Use the parent frame as the current frame is not complete yet */
2292 interp_push_lmf (&ext
, frame
->parent
);
2294 mono_interp_transform_method (frame
->imethod
, context
, error
);
2295 frame
->ex
= mono_error_convert_to_exception (error
);
2298 interp_pop_lmf (&ext
);
2302 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, unsigned char **vt_sp
)
2304 char *vt
= *(char**)vt_sp
;
2305 stackval
*first_arg
= sp
- csig
->param_count
;
2308 * We need to have the varargs linearly on the stack so the ArgIterator
2309 * can iterate over them. We pass the signature first and then copy them
2310 * one by one on the vtstack.
2312 *(gpointer
*)vt
= csig
;
2313 vt
+= sizeof (gpointer
);
2315 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2316 int align
, arg_size
;
2317 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2318 vt
= (char*)ALIGN_PTR_TO (vt
, align
);
2320 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt
, FALSE
);
2324 vt
= (char*)ALIGN_PTR_TO (vt
, MINT_VT_ALIGNMENT
);
2326 *(char**)vt_sp
= vt
;
2330 * These functions are the entry points into the interpreter from compiled code.
2331 * They are called by the interp_in wrappers. They have the following signature:
2332 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2333 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2334 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2335 * more wrappers then these functions.
2336 * this/static * ret/void * 16 arguments -> 64 functions.
2339 #define MAX_INTERP_ENTRY_ARGS 8
2341 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2342 InterpEntryData data; \
2343 (data).rmethod = (_method); \
2344 (data).res = (_res); \
2345 (data).this_arg = (_this_arg); \
2346 (data).many_args = NULL;
2348 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2349 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2350 interp_entry (&data); \
2352 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2353 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2354 (data).args [0] = arg1; \
2355 interp_entry (&data); \
2357 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2358 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2359 (data).args [0] = arg1; \
2360 (data).args [1] = arg2; \
2361 interp_entry (&data); \
2363 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2364 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2365 (data).args [0] = arg1; \
2366 (data).args [1] = arg2; \
2367 (data).args [2] = arg3; \
2368 interp_entry (&data); \
2370 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2371 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2372 (data).args [0] = arg1; \
2373 (data).args [1] = arg2; \
2374 (data).args [2] = arg3; \
2375 (data).args [3] = arg4; \
2376 interp_entry (&data); \
2378 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2379 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2380 (data).args [0] = arg1; \
2381 (data).args [1] = arg2; \
2382 (data).args [2] = arg3; \
2383 (data).args [3] = arg4; \
2384 (data).args [4] = arg5; \
2385 interp_entry (&data); \
2387 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2388 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2389 (data).args [0] = arg1; \
2390 (data).args [1] = arg2; \
2391 (data).args [2] = arg3; \
2392 (data).args [3] = arg4; \
2393 (data).args [4] = arg5; \
2394 (data).args [5] = arg6; \
2395 interp_entry (&data); \
2397 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2398 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2399 (data).args [0] = arg1; \
2400 (data).args [1] = arg2; \
2401 (data).args [2] = arg3; \
2402 (data).args [3] = arg4; \
2403 (data).args [4] = arg5; \
2404 (data).args [5] = arg6; \
2405 (data).args [6] = arg7; \
2406 interp_entry (&data); \
2408 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2409 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2410 (data).args [0] = arg1; \
2411 (data).args [1] = arg2; \
2412 (data).args [2] = arg3; \
2413 (data).args [3] = arg4; \
2414 (data).args [4] = arg5; \
2415 (data).args [5] = arg6; \
2416 (data).args [6] = arg7; \
2417 (data).args [7] = arg8; \
2418 interp_entry (&data); \
2421 #define ARGLIST0 InterpMethod *rmethod
2422 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2423 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2424 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2425 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2426 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2427 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2428 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2429 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2431 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2432 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2433 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2434 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2435 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2436 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2437 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2438 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2439 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2440 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2441 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2442 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2443 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2444 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2445 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2446 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2447 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2448 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2449 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2450 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2451 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2452 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2453 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2454 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2455 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2456 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2457 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2458 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2459 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2460 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2461 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2462 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2463 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2464 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2465 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2466 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2468 #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
2470 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2471 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2472 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2473 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2475 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2477 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2479 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2480 data
.many_args
= args
;
2481 interp_entry (&data
);
2484 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2486 // inline so we can alloc on stack
2487 #define alloc_storage_for_stackval(s, t, p) do { \
2488 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2489 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2490 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2492 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2494 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2499 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2502 ThreadContext
*context
;
2506 MonoMethodSignature
*sig
;
2507 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2508 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2509 gpointer orig_domain
= NULL
, attach_cookie
;
2512 if (rmethod
->needs_thread_attach
)
2513 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2515 context
= get_context ();
2517 method
= rmethod
->method
;
2518 sig
= mono_method_signature_internal (method
);
2522 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2524 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2526 /* Allocate storage for value types */
2527 for (i
= 0; i
< sig
->param_count
; i
++) {
2528 MonoType
*type
= sig
->params
[i
];
2529 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2532 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2533 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2535 /* Copy the args saved in the trampoline to the frame stack */
2536 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2538 interp_exec_method (&frame
, context
);
2540 if (rmethod
->needs_thread_attach
)
2541 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2544 g_assert (frame
.ex
== NULL
);
2546 /* Write back the return value */
2547 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2549 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2551 static InterpMethod
*
2552 lookup_method_pointer (gpointer addr
)
2554 MonoDomain
*domain
= mono_domain_get ();
2555 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2556 InterpMethod
*res
= NULL
;
2558 mono_domain_lock (domain
);
2559 if (info
->interp_method_pointer_hash
)
2560 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2561 mono_domain_unlock (domain
);
2566 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2568 interp_no_native_to_managed (void)
2570 g_error ("interpreter: native-to-managed transition not available on this platform");
2575 no_llvmonly_interp_method_pointer (void)
2577 g_assert_not_reached ();
2581 * interp_create_method_pointer_llvmonly:
2583 * Return an ftndesc for entering the interpreter and executing METHOD.
2586 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2588 MonoDomain
*domain
= mono_domain_get ();
2589 gpointer addr
, entry_func
, entry_wrapper
;
2590 MonoMethodSignature
*sig
;
2591 MonoMethod
*wrapper
;
2592 MonoJitDomainInfo
*info
;
2593 InterpMethod
*imethod
;
2595 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2596 return_val_if_nok (error
, NULL
);
2599 if (imethod
->llvmonly_unbox_entry
)
2600 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2602 if (imethod
->jit_entry
)
2603 return (MonoFtnDesc
*)imethod
->jit_entry
;
2606 sig
= mono_method_signature_internal (method
);
2609 * The entry functions need access to the method to call, so we have
2610 * to use a ftndesc. The caller uses a normal signature, while the
2611 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2612 * a gsharedvt_in_sig wrapper.
2614 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2616 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2617 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2618 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2619 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2621 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2622 g_assert_not_reached ();
2623 //entry_func = (gpointer)interp_entry_general;
2624 } else if (sig
->hasthis
) {
2625 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2626 entry_func
= entry_funcs_instance
[sig
->param_count
];
2628 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2630 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2631 entry_func
= entry_funcs_static
[sig
->param_count
];
2633 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2635 g_assert (entry_func
);
2637 /* Encode unbox in the lower bit of imethod */
2638 gpointer entry_arg
= imethod
;
2640 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2641 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2643 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2645 info
= domain_jit_info (domain
);
2646 mono_domain_lock (domain
);
2647 if (!info
->interp_method_pointer_hash
)
2648 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2649 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2650 mono_domain_unlock (domain
);
2652 mono_memory_barrier ();
2654 imethod
->llvmonly_unbox_entry
= addr
;
2656 imethod
->jit_entry
= addr
;
2658 return (MonoFtnDesc
*)addr
;
2662 * interp_create_method_pointer:
2664 * Return a function pointer which can be used to call METHOD using the
2665 * interpreter. Return NULL for methods which are not supported.
2668 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2670 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2672 return (gpointer
)no_llvmonly_interp_method_pointer
;
2673 return (gpointer
)interp_no_native_to_managed
;
2675 gpointer addr
, entry_func
, entry_wrapper
;
2676 MonoDomain
*domain
= mono_domain_get ();
2677 MonoJitDomainInfo
*info
;
2678 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2681 return (gpointer
)no_llvmonly_interp_method_pointer
;
2683 if (imethod
->jit_entry
)
2684 return imethod
->jit_entry
;
2686 if (compile
&& !imethod
->transformed
) {
2687 /* Return any errors from method compilation */
2688 mono_interp_transform_method (imethod
, get_context (), error
);
2689 return_val_if_nok (error
, NULL
);
2692 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2695 /* The caller should call interp_create_method_pointer_llvmonly */
2696 g_assert_not_reached ();
2698 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2701 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2702 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2704 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2705 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2706 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2707 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2709 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2710 entry_func
= (gpointer
)interp_entry_general
;
2711 } else if (sig
->hasthis
) {
2712 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2713 entry_func
= entry_funcs_instance
[sig
->param_count
];
2715 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2717 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2718 entry_func
= entry_funcs_static
[sig
->param_count
];
2720 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2722 g_assert (entry_func
);
2724 if (!mono_native_to_interp_trampoline
) {
2725 if (mono_aot_only
) {
2726 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2728 MonoTrampInfo
*info
;
2729 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2730 mono_tramp_info_register (info
, NULL
);
2733 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2734 /* We need the lmf wrapper only when being called from mixed mode */
2736 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2738 static gpointer cached_func
= NULL
;
2740 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
);
2741 mono_memory_barrier ();
2743 entry_func
= cached_func
;
2746 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2747 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2748 ftndesc
->addr
= entry_func
;
2749 ftndesc
->arg
= imethod
;
2750 mono_error_assert_ok (error
);
2753 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2754 * rgctx register using a trampoline.
2757 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2759 info
= domain_jit_info (domain
);
2760 mono_domain_lock (domain
);
2761 if (!info
->interp_method_pointer_hash
)
2762 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2763 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2764 mono_domain_unlock (domain
);
2766 mono_memory_barrier ();
2767 imethod
->jit_entry
= addr
;
2774 static int opcode_counts
[512];
2776 #define COUNT_OP(op) opcode_counts[op]++
2778 #define COUNT_OP(op)
2782 #define DUMP_INSTR() \
2783 if (tracing > 1) { \
2785 if (sp > frame->stack) { \
2786 ins = dump_stack (frame->stack, sp); \
2788 ins = g_strdup (""); \
2792 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2793 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2794 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2800 #define DUMP_INSTR()
2804 #define USE_COMPUTED_GOTO 1
2806 #if USE_COMPUTED_GOTO
2807 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2808 #define MINT_IN_CASE(x) LAB_ ## x:
2810 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2812 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2814 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2816 #define MINT_IN_SWITCH(op) switch (op)
2817 #define MINT_IN_CASE(x) case x:
2818 #define MINT_IN_BREAK break
2819 #define MINT_IN_DEFAULT default:
2822 #define INIT_VTABLE(vtable) do { \
2823 if (G_UNLIKELY (!(vtable)->initialized)) { \
2824 mono_runtime_class_init_full ((vtable), error); \
2825 if (!mono_error_ok (error)) \
2826 THROW_EX (mono_error_convert_to_exception (error), ip); \
2831 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2832 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2835 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
)
2837 InterpFrame child_frame
;
2838 GSList
*finally_ips
= NULL
;
2839 const unsigned short *endfinally_ip
= NULL
;
2840 const unsigned short *ip
= NULL
;
2842 InterpMethod
*imethod
= NULL
;
2844 gint tracing
= global_tracing
;
2845 unsigned char *vtalloc
;
2850 unsigned char *vt_sp
;
2851 unsigned char *locals
= NULL
;
2853 MonoObject
*o
= NULL
;
2855 #if USE_COMPUTED_GOTO
2856 static void *in_labels
[] = {
2857 #define OPDEF(a,b,c,d) \
2859 #include "mintops.def"
2864 debug_enter (frame
, &tracing
);
2866 imethod
= frame
->imethod
;
2867 if (!imethod
->transformed
) {
2869 char *mn
= mono_method_full_name (imethod
->method
, TRUE
);
2870 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2875 do_transform_method (frame
, context
);
2877 THROW_EX (frame
->ex
, NULL
);
2878 EXCEPTION_CHECKPOINT
;
2882 frame
->args
= g_newa (char, imethod
->alloca_size
);
2885 ip
= clause_args
->start_with_ip
;
2886 if (clause_args
->base_frame
) {
2887 frame
->args
= g_newa (char, imethod
->alloca_size
);
2888 memcpy (frame
->args
, clause_args
->base_frame
->args
, imethod
->alloca_size
);
2891 sp
= frame
->stack
= (stackval
*) (char *) frame
->args
;
2892 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
2896 locals
= (unsigned char *) vt_sp
+ imethod
->vt_stack_size
;
2897 frame
->locals
= locals
;
2898 child_frame
.parent
= frame
;
2900 if (clause_args
&& clause_args
->filter_exception
) {
2901 sp
->data
.p
= clause_args
->filter_exception
;
2905 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2908 * using while (ip < end) may result in a 15% performance drop,
2909 * but it may be useful for debug
2913 /* g_assert (sp >= frame->stack); */
2914 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
2916 MINT_IN_SWITCH (*ip
) {
2917 MINT_IN_CASE(MINT_INITLOCALS
)
2918 memset (locals
, 0, imethod
->locals_size
);
2921 MINT_IN_CASE(MINT_NOP
)
2924 MINT_IN_CASE(MINT_NIY
)
2925 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2927 MINT_IN_CASE(MINT_BREAK
)
2929 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
2931 MINT_IN_CASE(MINT_BREAKPOINT
)
2935 MINT_IN_CASE(MINT_LDNULL
)
2940 MINT_IN_CASE(MINT_ARGLIST
)
2941 g_assert (frame
->varargs
);
2943 *(gpointer
*)sp
->data
.p
= frame
->varargs
;
2944 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
2948 MINT_IN_CASE(MINT_VTRESULT
) {
2949 int ret_size
= * (guint16
*)(ip
+ 1);
2950 unsigned char *ret_vt_sp
= vt_sp
;
2951 vt_sp
-= READ32(ip
+ 2);
2953 memmove (vt_sp
, ret_vt_sp
, ret_size
);
2954 sp
[-1].data
.p
= vt_sp
;
2955 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
2960 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2961 MINT_IN_CASE(MINT_LDC_I4_M1
)
2964 MINT_IN_CASE(MINT_LDC_I4_0
)
2967 MINT_IN_CASE(MINT_LDC_I4_1
)
2970 MINT_IN_CASE(MINT_LDC_I4_2
)
2973 MINT_IN_CASE(MINT_LDC_I4_3
)
2976 MINT_IN_CASE(MINT_LDC_I4_4
)
2979 MINT_IN_CASE(MINT_LDC_I4_5
)
2982 MINT_IN_CASE(MINT_LDC_I4_6
)
2985 MINT_IN_CASE(MINT_LDC_I4_7
)
2988 MINT_IN_CASE(MINT_LDC_I4_8
)
2991 MINT_IN_CASE(MINT_LDC_I4_S
)
2992 sp
->data
.i
= *(const short *)(ip
+ 1);
2996 MINT_IN_CASE(MINT_LDC_I4
)
2998 sp
->data
.i
= READ32 (ip
);
3002 MINT_IN_CASE(MINT_LDC_I8
)
3004 sp
->data
.l
= READ64 (ip
);
3008 MINT_IN_CASE(MINT_LDC_I8_S
)
3009 sp
->data
.l
= *(const short *)(ip
+ 1);
3013 MINT_IN_CASE(MINT_LDC_R4
) {
3017 sp
->data
.f_r4
= * (float *)&val
;
3022 MINT_IN_CASE(MINT_LDC_R8
)
3023 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3027 MINT_IN_CASE(MINT_DUP
)
3032 MINT_IN_CASE(MINT_DUP_VT
)
3033 i32
= READ32 (ip
+ 1);
3035 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3036 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3040 MINT_IN_CASE(MINT_POP
) {
3041 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
3043 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
3048 MINT_IN_CASE(MINT_JMP
) {
3049 InterpMethod
*new_method
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3050 gboolean realloc_frame
= new_method
->alloca_size
> imethod
->alloca_size
;
3052 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3053 MONO_PROFILER_RAISE (method_tail_call
, (imethod
->method
, new_method
->method
));
3055 if (!new_method
->transformed
) {
3059 mono_interp_transform_method (new_method
, context
, error
);
3060 frame
->ex
= mono_error_convert_to_exception (error
);
3065 imethod
= frame
->imethod
= new_method
;
3067 * We allocate the stack frame from scratch and store the arguments in the
3068 * locals again since it's possible for the caller stack frame to be smaller
3069 * than the callee stack frame (at the interp level)
3071 if (realloc_frame
) {
3072 frame
->args
= g_newa (char, imethod
->alloca_size
);
3073 memset (frame
->args
, 0, imethod
->alloca_size
);
3074 sp
= frame
->stack
= (stackval
*) frame
->args
;
3076 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
3080 locals
= vt_sp
+ imethod
->vt_stack_size
;
3081 frame
->locals
= locals
;
3085 MINT_IN_CASE(MINT_CALLI
) {
3086 MonoMethodSignature
*csignature
;
3087 stackval
*endsp
= sp
;
3091 csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3095 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
3098 child_frame
.retval
= sp
;
3099 /* decrement by the actual number of args */
3100 sp
-= csignature
->param_count
;
3101 if (csignature
->hasthis
)
3103 child_frame
.stack_args
= sp
;
3105 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3106 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
3107 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3110 if (csignature
->hasthis
) {
3111 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3113 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3114 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3115 sp
[0].data
.p
= unboxed
;
3119 interp_exec_method (&child_frame
, context
);
3121 CHECK_RESUME_STATE (context
);
3123 /* need to handle typedbyref ... */
3124 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3130 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3131 gpointer target_ip
= sp
[-1].data
.p
;
3132 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3133 int opcode
= *(guint16
*)(ip
+ 2);
3138 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
);
3139 EXCEPTION_CHECKPOINT
;
3140 CHECK_RESUME_STATE (context
);
3144 MINT_IN_CASE(MINT_CALLI_NAT
) {
3145 MonoMethodSignature
*csignature
;
3146 stackval
*endsp
= sp
;
3147 unsigned char *code
= NULL
;
3151 csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3155 code
= (guchar
*)sp
->data
.p
;
3156 child_frame
.imethod
= NULL
;
3159 child_frame
.retval
= sp
;
3160 /* decrement by the actual number of args */
3161 sp
-= csignature
->param_count
;
3162 if (csignature
->hasthis
)
3164 child_frame
.stack_args
= sp
;
3165 if (imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3166 MonoMarshalSpec
**mspecs
;
3167 MonoMethodPInvoke piinfo
;
3170 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3171 mspecs
= g_new0 (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3172 memset (&piinfo
, 0, sizeof (piinfo
));
3174 m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, &piinfo
, mspecs
, code
);
3176 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3178 mono_metadata_free_marshal_spec (mspecs
[i
]);
3181 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
3182 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3184 interp_exec_method (&child_frame
, context
);
3186 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
);
3189 CHECK_RESUME_STATE (context
);
3191 /* need to handle typedbyref ... */
3192 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3198 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3199 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3200 MonoObject
*this_arg
;
3201 MonoClass
*this_class
;
3202 gboolean is_void
= *ip
== MINT_VCALLVIRT_FAST
;
3203 InterpMethod
*target_imethod
;
3204 stackval
*endsp
= sp
;
3207 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3211 target_imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3212 slot
= *(gint16
*)(ip
+ 2);
3215 child_frame
.retval
= sp
;
3217 /* decrement by the actual number of args */
3218 sp
-= target_imethod
->param_count
+ target_imethod
->hasthis
;
3219 child_frame
.stack_args
= sp
;
3221 this_arg
= (MonoObject
*)sp
->data
.p
;
3222 this_class
= this_arg
->vtable
->klass
;
3224 child_frame
.imethod
= get_virtual_method_fast (this_arg
, target_imethod
, slot
);
3225 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3227 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3228 sp
[0].data
.p
= unboxed
;
3231 interp_exec_method (&child_frame
, context
);
3233 CHECK_RESUME_STATE (context
);
3236 /* need to handle typedbyref ... */
3242 MINT_IN_CASE(MINT_CALL_VARARG
) {
3243 stackval
*endsp
= sp
;
3244 int num_varargs
= 0;
3245 MonoMethodSignature
*csig
;
3249 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3250 /* The real signature for vararg calls */
3251 csig
= (MonoMethodSignature
*) imethod
->data_items
[* (guint16
*) (ip
+ 2)];
3252 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3253 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
3254 child_frame
.varargs
= (char*) vt_sp
;
3255 copy_varargs_vtstack (csig
, sp
, &vt_sp
);
3259 child_frame
.retval
= sp
;
3261 /* decrement by the actual number of args */
3262 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
3263 child_frame
.stack_args
= sp
;
3265 interp_exec_method (&child_frame
, context
);
3267 CHECK_RESUME_STATE (context
);
3269 if (csig
->ret
->type
!= MONO_TYPE_VOID
) {
3275 MINT_IN_CASE(MINT_CALL
)
3276 MINT_IN_CASE(MINT_VCALL
)
3277 MINT_IN_CASE(MINT_CALLVIRT
)
3278 MINT_IN_CASE(MINT_VCALLVIRT
) {
3279 gboolean is_void
= *ip
== MINT_VCALL
|| *ip
== MINT_VCALLVIRT
;
3280 gboolean is_virtual
= *ip
== MINT_CALLVIRT
|| *ip
== MINT_VCALLVIRT
;
3281 stackval
*endsp
= sp
;
3285 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3288 child_frame
.retval
= sp
;
3290 /* decrement by the actual number of args */
3291 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
;
3292 child_frame
.stack_args
= sp
;
3295 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3296 MonoClass
*this_class
= this_arg
->vtable
->klass
;
3298 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
3299 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3301 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3302 sp
[0].data
.p
= unboxed
;
3306 interp_exec_method (&child_frame
, context
);
3308 CHECK_RESUME_STATE (context
);
3311 /* need to handle typedbyref ... */
3317 MINT_IN_CASE(MINT_JIT_CALL
) {
3318 InterpMethod
*rmethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3321 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3322 if (!is_ok (error
)) {
3323 MonoException
*ex
= mono_error_convert_to_exception (error
);
3328 CHECK_RESUME_STATE (context
);
3330 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3335 MINT_IN_CASE(MINT_CALLRUN
) {
3336 MonoMethod
*target_method
= (MonoMethod
*) imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3337 MonoMethodSignature
*sig
= (MonoMethodSignature
*) imethod
->data_items
[* (guint16
*)(ip
+ 2)];
3343 sp
-= sig
->param_count
;
3347 ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3349 THROW_EX (frame
->ex
, ip
);
3351 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3358 MINT_IN_CASE(MINT_RET
)
3360 *frame
->retval
= *sp
;
3361 if (sp
> frame
->stack
)
3362 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3364 MINT_IN_CASE(MINT_RET_VOID
)
3365 if (sp
> frame
->stack
)
3366 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (imethod
->method
, TRUE
));
3368 MINT_IN_CASE(MINT_RET_VT
)
3369 i32
= READ32(ip
+ 1);
3371 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3372 if (sp
> frame
->stack
)
3373 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3375 MINT_IN_CASE(MINT_BR_S
)
3376 ip
+= (short) *(ip
+ 1);
3378 MINT_IN_CASE(MINT_BR
)
3379 ip
+= (gint32
) READ32(ip
+ 1);
3381 #define ZEROP_S(datamem, op) \
3383 if (sp->data.datamem op 0) \
3384 ip += * (gint16 *)(ip + 1); \
3388 #define ZEROP(datamem, op) \
3390 if (sp->data.datamem op 0) \
3391 ip += (gint32)READ32(ip + 1); \
3395 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3398 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3401 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3404 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3407 MINT_IN_CASE(MINT_BRFALSE_I4
)
3410 MINT_IN_CASE(MINT_BRFALSE_I8
)
3413 MINT_IN_CASE(MINT_BRFALSE_R4
)
3416 MINT_IN_CASE(MINT_BRFALSE_R8
)
3419 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3422 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3425 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
3428 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3431 MINT_IN_CASE(MINT_BRTRUE_I4
)
3434 MINT_IN_CASE(MINT_BRTRUE_I8
)
3437 MINT_IN_CASE(MINT_BRTRUE_R4
)
3440 MINT_IN_CASE(MINT_BRTRUE_R8
)
3443 #define CONDBR_S(cond) \
3446 ip += * (gint16 *)(ip + 1); \
3449 #define BRELOP_S(datamem, op) \
3450 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3452 #define CONDBR(cond) \
3455 ip += (gint32)READ32(ip + 1); \
3459 #define BRELOP(datamem, op) \
3460 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3462 MINT_IN_CASE(MINT_BEQ_I4_S
)
3465 MINT_IN_CASE(MINT_BEQ_I8_S
)
3468 MINT_IN_CASE(MINT_BEQ_R4_S
)
3469 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3471 MINT_IN_CASE(MINT_BEQ_R8_S
)
3472 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3474 MINT_IN_CASE(MINT_BEQ_I4
)
3477 MINT_IN_CASE(MINT_BEQ_I8
)
3480 MINT_IN_CASE(MINT_BEQ_R4
)
3481 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3483 MINT_IN_CASE(MINT_BEQ_R8
)
3484 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3486 MINT_IN_CASE(MINT_BGE_I4_S
)
3489 MINT_IN_CASE(MINT_BGE_I8_S
)
3492 MINT_IN_CASE(MINT_BGE_R4_S
)
3493 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3495 MINT_IN_CASE(MINT_BGE_R8_S
)
3496 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3498 MINT_IN_CASE(MINT_BGE_I4
)
3501 MINT_IN_CASE(MINT_BGE_I8
)
3504 MINT_IN_CASE(MINT_BGE_R4
)
3505 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3507 MINT_IN_CASE(MINT_BGE_R8
)
3508 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3510 MINT_IN_CASE(MINT_BGT_I4_S
)
3513 MINT_IN_CASE(MINT_BGT_I8_S
)
3516 MINT_IN_CASE(MINT_BGT_R4_S
)
3517 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3519 MINT_IN_CASE(MINT_BGT_R8_S
)
3520 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3522 MINT_IN_CASE(MINT_BGT_I4
)
3525 MINT_IN_CASE(MINT_BGT_I8
)
3528 MINT_IN_CASE(MINT_BGT_R4
)
3529 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3531 MINT_IN_CASE(MINT_BGT_R8
)
3532 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3534 MINT_IN_CASE(MINT_BLT_I4_S
)
3537 MINT_IN_CASE(MINT_BLT_I8_S
)
3540 MINT_IN_CASE(MINT_BLT_R4_S
)
3541 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3543 MINT_IN_CASE(MINT_BLT_R8_S
)
3544 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3546 MINT_IN_CASE(MINT_BLT_I4
)
3549 MINT_IN_CASE(MINT_BLT_I8
)
3552 MINT_IN_CASE(MINT_BLT_R4
)
3553 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3555 MINT_IN_CASE(MINT_BLT_R8
)
3556 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3558 MINT_IN_CASE(MINT_BLE_I4_S
)
3561 MINT_IN_CASE(MINT_BLE_I8_S
)
3564 MINT_IN_CASE(MINT_BLE_R4_S
)
3565 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3567 MINT_IN_CASE(MINT_BLE_R8_S
)
3568 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3570 MINT_IN_CASE(MINT_BLE_I4
)
3573 MINT_IN_CASE(MINT_BLE_I8
)
3576 MINT_IN_CASE(MINT_BLE_R4
)
3577 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3579 MINT_IN_CASE(MINT_BLE_R8
)
3580 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3582 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3585 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3588 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
3589 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3591 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3592 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3594 MINT_IN_CASE(MINT_BNE_UN_I4
)
3597 MINT_IN_CASE(MINT_BNE_UN_I8
)
3600 MINT_IN_CASE(MINT_BNE_UN_R4
)
3601 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3603 MINT_IN_CASE(MINT_BNE_UN_R8
)
3604 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3607 #define BRELOP_S_CAST(datamem, op, type) \
3609 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3610 ip += * (gint16 *)(ip + 1); \
3614 #define BRELOP_CAST(datamem, op, type) \
3616 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3617 ip += (gint32)READ32(ip + 1); \
3621 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3622 BRELOP_S_CAST(i
, >=, guint32
);
3624 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3625 BRELOP_S_CAST(l
, >=, guint64
);
3627 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
3628 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3630 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3631 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3633 MINT_IN_CASE(MINT_BGE_UN_I4
)
3634 BRELOP_CAST(i
, >=, guint32
);
3636 MINT_IN_CASE(MINT_BGE_UN_I8
)
3637 BRELOP_CAST(l
, >=, guint64
);
3639 MINT_IN_CASE(MINT_BGE_UN_R4
)
3640 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3642 MINT_IN_CASE(MINT_BGE_UN_R8
)
3643 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3645 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3646 BRELOP_S_CAST(i
, >, guint32
);
3648 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3649 BRELOP_S_CAST(l
, >, guint64
);
3651 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
3652 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3654 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3655 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3657 MINT_IN_CASE(MINT_BGT_UN_I4
)
3658 BRELOP_CAST(i
, >, guint32
);
3660 MINT_IN_CASE(MINT_BGT_UN_I8
)
3661 BRELOP_CAST(l
, >, guint64
);
3663 MINT_IN_CASE(MINT_BGT_UN_R4
)
3664 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3666 MINT_IN_CASE(MINT_BGT_UN_R8
)
3667 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3669 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3670 BRELOP_S_CAST(i
, <=, guint32
);
3672 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3673 BRELOP_S_CAST(l
, <=, guint64
);
3675 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
3676 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3678 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3679 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3681 MINT_IN_CASE(MINT_BLE_UN_I4
)
3682 BRELOP_CAST(i
, <=, guint32
);
3684 MINT_IN_CASE(MINT_BLE_UN_I8
)
3685 BRELOP_CAST(l
, <=, guint64
);
3687 MINT_IN_CASE(MINT_BLE_UN_R4
)
3688 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3690 MINT_IN_CASE(MINT_BLE_UN_R8
)
3691 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3693 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3694 BRELOP_S_CAST(i
, <, guint32
);
3696 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3697 BRELOP_S_CAST(l
, <, guint64
);
3699 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
3700 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3702 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3703 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3705 MINT_IN_CASE(MINT_BLT_UN_I4
)
3706 BRELOP_CAST(i
, <, guint32
);
3708 MINT_IN_CASE(MINT_BLT_UN_I8
)
3709 BRELOP_CAST(l
, <, guint64
);
3711 MINT_IN_CASE(MINT_BLT_UN_R4
)
3712 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3714 MINT_IN_CASE(MINT_BLT_UN_R8
)
3715 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3717 MINT_IN_CASE(MINT_SWITCH
) {
3719 const unsigned short *st
;
3725 if ((guint32
)sp
->data
.i
< n
) {
3727 ip
+= 2 * (guint32
)sp
->data
.i
;
3728 offset
= READ32 (ip
);
3735 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
3737 THROW_EX (mono_get_exception_null_reference (), ip
);
3739 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3741 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
3743 THROW_EX (mono_get_exception_null_reference (), ip
);
3745 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3747 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
3749 THROW_EX (mono_get_exception_null_reference (), ip
);
3751 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3753 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
3755 THROW_EX (mono_get_exception_null_reference (), ip
);
3757 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3759 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
3760 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
3762 THROW_EX (mono_get_exception_null_reference (), ip
);
3764 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3766 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
3768 THROW_EX (mono_get_exception_null_reference (), ip
);
3770 #ifdef NO_UNALIGNED_ACCESS
3771 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
3772 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
3775 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
3777 MINT_IN_CASE(MINT_LDIND_I
) {
3778 guint16 offset
= * (guint16
*)(ip
+ 1);
3779 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3783 MINT_IN_CASE(MINT_LDIND_I8
) {
3784 guint16 offset
= * (guint16
*)(ip
+ 1);
3785 #ifdef NO_UNALIGNED_ACCESS
3786 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
3787 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
3790 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
3794 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
3796 THROW_EX (mono_get_exception_null_reference (), ip
);
3798 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
3800 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
3802 THROW_EX (mono_get_exception_null_reference (), ip
);
3804 #ifdef NO_UNALIGNED_ACCESS
3805 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
3806 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
3809 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3811 MINT_IN_CASE(MINT_LDIND_REF
)
3813 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3815 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
3816 if (!sp
[-1].data
.p
)
3817 THROW_EX (mono_get_exception_null_reference (), ip
);
3819 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3822 MINT_IN_CASE(MINT_STIND_REF
)
3825 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
3827 MINT_IN_CASE(MINT_STIND_I1
)
3830 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3832 MINT_IN_CASE(MINT_STIND_I2
)
3835 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3837 MINT_IN_CASE(MINT_STIND_I4
)
3840 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3842 MINT_IN_CASE(MINT_STIND_I
)
3845 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3847 MINT_IN_CASE(MINT_STIND_I8
)
3850 #ifdef NO_UNALIGNED_ACCESS
3851 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
3852 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
3855 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3857 MINT_IN_CASE(MINT_STIND_R4
)
3860 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
3862 MINT_IN_CASE(MINT_STIND_R8
)
3865 #ifdef NO_UNALIGNED_ACCESS
3866 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
3867 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
3870 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3872 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3875 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3877 #define BINOP(datamem, op) \
3879 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3881 MINT_IN_CASE(MINT_ADD_I4
)
3884 MINT_IN_CASE(MINT_ADD_I8
)
3887 MINT_IN_CASE(MINT_ADD_R4
)
3890 MINT_IN_CASE(MINT_ADD_R8
)
3893 MINT_IN_CASE(MINT_ADD1_I4
)
3897 MINT_IN_CASE(MINT_ADD1_I8
)
3901 MINT_IN_CASE(MINT_SUB_I4
)
3904 MINT_IN_CASE(MINT_SUB_I8
)
3907 MINT_IN_CASE(MINT_SUB_R4
)
3910 MINT_IN_CASE(MINT_SUB_R8
)
3913 MINT_IN_CASE(MINT_SUB1_I4
)
3917 MINT_IN_CASE(MINT_SUB1_I8
)
3921 MINT_IN_CASE(MINT_MUL_I4
)
3924 MINT_IN_CASE(MINT_MUL_I8
)
3927 MINT_IN_CASE(MINT_MUL_R4
)
3930 MINT_IN_CASE(MINT_MUL_R8
)
3933 MINT_IN_CASE(MINT_DIV_I4
)
3934 if (sp
[-1].data
.i
== 0)
3935 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3936 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
3937 THROW_EX (mono_get_exception_overflow (), ip
);
3940 MINT_IN_CASE(MINT_DIV_I8
)
3941 if (sp
[-1].data
.l
== 0)
3942 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3943 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
3944 THROW_EX (mono_get_exception_overflow (), ip
);
3947 MINT_IN_CASE(MINT_DIV_R4
)
3950 MINT_IN_CASE(MINT_DIV_R8
)
3954 #define BINOP_CAST(datamem, op, type) \
3956 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3958 MINT_IN_CASE(MINT_DIV_UN_I4
)
3959 if (sp
[-1].data
.i
== 0)
3960 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3961 BINOP_CAST(i
, /, guint32
);
3963 MINT_IN_CASE(MINT_DIV_UN_I8
)
3964 if (sp
[-1].data
.l
== 0)
3965 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3966 BINOP_CAST(l
, /, guint64
);
3968 MINT_IN_CASE(MINT_REM_I4
)
3969 if (sp
[-1].data
.i
== 0)
3970 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3971 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
3972 THROW_EX (mono_get_exception_overflow (), ip
);
3975 MINT_IN_CASE(MINT_REM_I8
)
3976 if (sp
[-1].data
.l
== 0)
3977 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3978 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
3979 THROW_EX (mono_get_exception_overflow (), ip
);
3982 MINT_IN_CASE(MINT_REM_R4
)
3983 /* FIXME: what do we actually do here? */
3985 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
3988 MINT_IN_CASE(MINT_REM_R8
)
3989 /* FIXME: what do we actually do here? */
3991 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
3994 MINT_IN_CASE(MINT_REM_UN_I4
)
3995 if (sp
[-1].data
.i
== 0)
3996 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3997 BINOP_CAST(i
, %, guint32
);
3999 MINT_IN_CASE(MINT_REM_UN_I8
)
4000 if (sp
[-1].data
.l
== 0)
4001 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
4002 BINOP_CAST(l
, %, guint64
);
4004 MINT_IN_CASE(MINT_AND_I4
)
4007 MINT_IN_CASE(MINT_AND_I8
)
4010 MINT_IN_CASE(MINT_OR_I4
)
4013 MINT_IN_CASE(MINT_OR_I8
)
4016 MINT_IN_CASE(MINT_XOR_I4
)
4019 MINT_IN_CASE(MINT_XOR_I8
)
4023 #define SHIFTOP(datamem, op) \
4025 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4028 MINT_IN_CASE(MINT_SHL_I4
)
4031 MINT_IN_CASE(MINT_SHL_I8
)
4034 MINT_IN_CASE(MINT_SHR_I4
)
4037 MINT_IN_CASE(MINT_SHR_I8
)
4040 MINT_IN_CASE(MINT_SHR_UN_I4
)
4042 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4045 MINT_IN_CASE(MINT_SHR_UN_I8
)
4047 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4050 MINT_IN_CASE(MINT_NEG_I4
)
4051 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4054 MINT_IN_CASE(MINT_NEG_I8
)
4055 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4058 MINT_IN_CASE(MINT_NEG_R4
)
4059 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4062 MINT_IN_CASE(MINT_NEG_R8
)
4063 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4066 MINT_IN_CASE(MINT_NOT_I4
)
4067 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4070 MINT_IN_CASE(MINT_NOT_I8
)
4071 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4074 MINT_IN_CASE(MINT_CONV_I1_I4
)
4075 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4078 MINT_IN_CASE(MINT_CONV_I1_I8
)
4079 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4082 MINT_IN_CASE(MINT_CONV_I1_R4
)
4083 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4086 MINT_IN_CASE(MINT_CONV_I1_R8
)
4087 /* without gint32 cast, C compiler is allowed to use undefined
4088 * behaviour if data.f is bigger than >255. See conv.fpint section
4090 * > The conversion truncates; that is, the fractional part
4091 * > is discarded. The behavior is undefined if the truncated
4092 * > value cannot be represented in the destination type.
4094 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4097 MINT_IN_CASE(MINT_CONV_U1_I4
)
4098 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4101 MINT_IN_CASE(MINT_CONV_U1_I8
)
4102 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4105 MINT_IN_CASE(MINT_CONV_U1_R4
)
4106 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4109 MINT_IN_CASE(MINT_CONV_U1_R8
)
4110 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4113 MINT_IN_CASE(MINT_CONV_I2_I4
)
4114 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4117 MINT_IN_CASE(MINT_CONV_I2_I8
)
4118 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4121 MINT_IN_CASE(MINT_CONV_I2_R4
)
4122 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4125 MINT_IN_CASE(MINT_CONV_I2_R8
)
4126 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4129 MINT_IN_CASE(MINT_CONV_U2_I4
)
4130 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4133 MINT_IN_CASE(MINT_CONV_U2_I8
)
4134 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4137 MINT_IN_CASE(MINT_CONV_U2_R4
)
4138 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4141 MINT_IN_CASE(MINT_CONV_U2_R8
)
4142 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4145 MINT_IN_CASE(MINT_CONV_I4_R4
)
4146 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4149 MINT_IN_CASE(MINT_CONV_I4_R8
)
4150 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4153 MINT_IN_CASE(MINT_CONV_U4_I8
)
4154 MINT_IN_CASE(MINT_CONV_I4_I8
)
4155 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4158 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4159 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4162 MINT_IN_CASE(MINT_CONV_U4_R4
)
4163 /* needed on arm64 */
4164 if (isinf (sp
[-1].data
.f_r4
))
4166 /* needed by wasm */
4167 else if (isnan (sp
[-1].data
.f_r4
))
4170 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4173 MINT_IN_CASE(MINT_CONV_U4_R8
)
4174 /* needed on arm64 */
4175 if (mono_isinf (sp
[-1].data
.f
))
4177 /* needed by wasm */
4178 else if (isnan (sp
[-1].data
.f
))
4181 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
4184 MINT_IN_CASE(MINT_CONV_I8_I4
)
4185 sp
[-1].data
.l
= sp
[-1].data
.i
;
4188 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4189 sp
[-2].data
.l
= sp
[-2].data
.i
;
4192 MINT_IN_CASE(MINT_CONV_I8_U4
)
4193 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4196 MINT_IN_CASE(MINT_CONV_I8_R4
)
4197 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4200 MINT_IN_CASE(MINT_CONV_I8_R8
)
4201 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4204 MINT_IN_CASE(MINT_CONV_R4_I4
)
4205 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4208 MINT_IN_CASE(MINT_CONV_R4_I8
)
4209 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4212 MINT_IN_CASE(MINT_CONV_R4_R8
)
4213 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4216 MINT_IN_CASE(MINT_CONV_R8_I4
)
4217 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4220 MINT_IN_CASE(MINT_CONV_R8_I8
)
4221 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4224 MINT_IN_CASE(MINT_CONV_R8_R4
)
4225 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4228 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4229 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4232 MINT_IN_CASE(MINT_CONV_U8_I4
)
4233 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
4236 MINT_IN_CASE(MINT_CONV_U8_R4
)
4237 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4240 MINT_IN_CASE(MINT_CONV_U8_R8
)
4241 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4244 MINT_IN_CASE(MINT_CPOBJ
) {
4245 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4246 g_assert (m_class_is_valuetype (c
));
4247 /* if this assertion fails, we need to add a write barrier */
4248 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4249 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4254 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4255 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4256 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4261 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4262 int size
= READ32(ip
+ 1);
4264 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4265 sp
[-1].data
.p
= vt_sp
;
4266 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4269 MINT_IN_CASE(MINT_LDSTR
)
4270 sp
->data
.p
= imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4274 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4275 MonoString
*s
= NULL
;
4276 guint32 strtoken
= (guint32
)(gsize
)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4278 MonoMethod
*method
= imethod
->method
;
4279 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4280 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4281 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4282 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4284 g_assert_not_reached ();
4291 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4292 MonoClass
*newobj_class
;
4293 guint32 token
= * (guint16
*)(ip
+ 1);
4294 guint16 param_count
= * (guint16
*)(ip
+ 2);
4296 newobj_class
= ((InterpMethod
*) imethod
->data_items
[token
])->method
->klass
;
4299 sp
->data
.p
= ves_array_create (imethod
->domain
, newobj_class
, param_count
, sp
, error
);
4300 if (!mono_error_ok (error
))
4301 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4307 MINT_IN_CASE(MINT_NEWOBJ_FAST
)
4308 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4309 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4310 guint16 param_count
;
4311 gboolean vt
= *ip
!= MINT_NEWOBJ_FAST
;
4312 stackval valuetype_this
;
4316 child_frame
.imethod
= (InterpMethod
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4317 param_count
= *(guint16
*)(ip
+ 2);
4321 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
4323 child_frame
.stack_args
= sp
;
4326 gboolean vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4328 memset (vt_sp
, 0, *(guint16
*)(ip
+ 3));
4330 valuetype_this
.data
.p
= vt_sp
;
4333 memset (&valuetype_this
, 0, sizeof (stackval
));
4334 sp
->data
.p
= &valuetype_this
;
4338 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 3)];
4339 if (G_UNLIKELY (!vtable
->initialized
)) {
4340 mono_runtime_class_init_full (vtable
, error
);
4341 if (!mono_error_ok (error
))
4342 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4344 o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4345 if (G_UNLIKELY (!o
)) {
4346 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4347 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4353 interp_exec_method (&child_frame
, context
);
4355 CHECK_RESUME_STATE (context
);
4358 *sp
= valuetype_this
;
4364 MINT_IN_CASE(MINT_NEWOBJ
) {
4365 MonoClass
*newobj_class
;
4366 MonoMethodSignature
*csig
;
4367 stackval valuetype_this
;
4373 token
= * (guint16
*)(ip
+ 1);
4376 child_frame
.ip
= NULL
;
4377 child_frame
.ex
= NULL
;
4379 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[token
];
4380 csig
= mono_method_signature_internal (child_frame
.imethod
->method
);
4381 newobj_class
= child_frame
.imethod
->method
->klass
;
4382 /*if (profiling_classes) {
4383 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4385 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4388 g_assert (csig
->hasthis
);
4389 if (csig
->param_count
) {
4390 sp
-= csig
->param_count
;
4391 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
4393 child_frame
.stack_args
= sp
;
4396 * First arg is the object.
4398 if (m_class_is_valuetype (newobj_class
)) {
4399 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
4400 memset (&valuetype_this
, 0, sizeof (stackval
));
4401 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
4403 valuetype_this
.data
.p
= vt_sp
;
4405 sp
->data
.p
= &valuetype_this
;
4408 if (newobj_class
!= mono_defaults
.string_class
) {
4409 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
4410 if (!mono_error_ok (error
) || !mono_runtime_class_init_full (vtable
, error
))
4411 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4412 o
= mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
4413 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4414 EXCEPTION_CHECKPOINT
;
4416 #ifndef DISABLE_REMOTING
4417 if (mono_object_is_transparent_proxy (o
)) {
4418 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
.imethod
->method
, error
);
4419 mono_error_assert_ok (error
);
4420 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
4421 mono_error_assert_ok (error
);
4426 child_frame
.retval
= &retval
;
4430 interp_exec_method (&child_frame
, context
);
4432 CHECK_RESUME_STATE (context
);
4435 * a constructor returns void, but we need to return the object we created
4437 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
4438 *sp
= valuetype_this
;
4439 } else if (newobj_class
== mono_defaults
.string_class
) {
4447 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
4453 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
4454 MonoMethodSignature
*csig
;
4458 token
= * (guint16
*)(ip
+ 1);
4461 InterpMethod
*cmethod
= (InterpMethod
*)imethod
->data_items
[token
];
4462 csig
= mono_method_signature_internal (cmethod
->method
);
4464 g_assert (csig
->hasthis
);
4465 sp
-= csig
->param_count
;
4467 gpointer arg0
= sp
[0].data
.p
;
4469 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
4470 *byreference_this
= arg0
;
4472 /* Followed by a VTRESULT opcode which will push the result on the stack */
4476 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4477 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4478 sp
[-1].data
.p
= *byreference_this
;
4482 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
4484 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.i
;
4489 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
4491 sp
[0].data
.i
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
4496 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
4498 MonoObject
*obj
= sp
[0].data
.o
;
4499 sp
[0].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
4504 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
4505 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
4506 gboolean isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
4507 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4508 if ((o
= sp
[-1].data
.o
)) {
4510 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
4512 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
4514 isinst
= mono_object_isinst_checked (o
, c
, error
) != NULL
;
4515 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4522 sp
[-1].data
.p
= NULL
;
4524 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4530 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
4531 MINT_IN_CASE(MINT_ISINST_COMMON
) {
4532 gboolean isinst_instr
= *ip
== MINT_ISINST_COMMON
;
4533 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4534 if ((o
= sp
[-1].data
.o
)) {
4535 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
4539 sp
[-1].data
.p
= NULL
;
4541 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4547 MINT_IN_CASE(MINT_CASTCLASS
)
4548 MINT_IN_CASE(MINT_ISINST
) {
4549 gboolean isinst_instr
= *ip
== MINT_ISINST
;
4550 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4551 if ((o
= sp
[-1].data
.o
)) {
4552 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4553 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4556 sp
[-1].data
.p
= NULL
;
4558 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4564 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4565 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4568 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4569 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4572 MINT_IN_CASE(MINT_UNBOX
)
4573 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4577 THROW_EX (mono_get_exception_null_reference (), ip
);
4579 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
4580 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4582 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
4585 MINT_IN_CASE(MINT_THROW
)
4588 sp
->data
.p
= mono_get_exception_null_reference ();
4590 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4592 MINT_IN_CASE(MINT_CHECKPOINT
)
4593 /* Do synchronous checking of abort requests */
4594 EXCEPTION_CHECKPOINT
;
4597 MINT_IN_CASE(MINT_SAFEPOINT
)
4598 /* Do synchronous checking of abort requests */
4599 EXCEPTION_CHECKPOINT
;
4600 /* Poll safepoint */
4601 mono_threads_safepoint ();
4604 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
4606 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4609 MINT_IN_CASE(MINT_LDFLDA
)
4612 THROW_EX (mono_get_exception_null_reference (), ip
);
4613 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4616 MINT_IN_CASE(MINT_CKNULL_N
) {
4617 /* Same as CKNULL, but further down the stack */
4618 int n
= *(guint16
*)(ip
+ 1);
4621 THROW_EX (mono_get_exception_null_reference (), ip
);
4626 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4627 o = sp [-1].data.o; \
4629 THROW_EX (mono_get_exception_null_reference (), ip); \
4631 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4633 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4636 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4638 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4639 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4640 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4641 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4642 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4643 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4644 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
4645 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4646 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4647 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4648 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4649 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4651 MINT_IN_CASE(MINT_LDFLD_VT
) {
4654 THROW_EX (mono_get_exception_null_reference (), ip
);
4656 int size
= READ32(ip
+ 2);
4657 sp
[-1].data
.p
= vt_sp
;
4658 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), size
);
4659 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4664 MINT_IN_CASE(MINT_LDRMFLD
) {
4665 MonoClassField
*field
;
4670 THROW_EX (mono_get_exception_null_reference (), ip
);
4671 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4673 #ifndef DISABLE_REMOTING
4674 if (mono_object_is_transparent_proxy (o
)) {
4676 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4678 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4679 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4682 addr
= (char*)o
+ field
->offset
;
4684 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
4688 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
4689 MonoClassField
*field
;
4694 THROW_EX (mono_get_exception_null_reference (), ip
);
4696 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4697 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4698 i32
= mono_class_value_size (klass
, NULL
);
4701 #ifndef DISABLE_REMOTING
4702 if (mono_object_is_transparent_proxy (o
)) {
4704 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4705 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4706 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4709 addr
= (char*)o
+ field
->offset
;
4711 sp
[-1].data
.p
= vt_sp
;
4712 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4713 memcpy(sp
[-1].data
.p
, addr
, i32
);
4717 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4718 o = sp [-2].data.o; \
4720 THROW_EX (mono_get_exception_null_reference (), ip); \
4723 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
4725 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4728 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4730 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
4731 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
4732 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
4733 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
4734 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
4735 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
4736 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
4737 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
4738 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
4739 MINT_IN_CASE(MINT_STFLD_O
)
4742 THROW_EX (mono_get_exception_null_reference (), ip
);
4744 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.o
);
4747 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4748 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4750 MINT_IN_CASE(MINT_STFLD_VT
) {
4753 THROW_EX (mono_get_exception_null_reference (), ip
);
4756 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 2)];
4757 i32
= mono_class_value_size (klass
, NULL
);
4759 guint16 offset
= * (guint16
*)(ip
+ 1);
4760 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
4762 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4766 MINT_IN_CASE(MINT_STRMFLD
) {
4767 MonoClassField
*field
;
4771 THROW_EX (mono_get_exception_null_reference (), ip
);
4773 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4776 #ifndef DISABLE_REMOTING
4777 if (mono_object_is_transparent_proxy (o
)) {
4778 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4779 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4780 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4783 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
4788 MINT_IN_CASE(MINT_STRMFLD_VT
) {
4789 MonoClassField
*field
;
4793 THROW_EX (mono_get_exception_null_reference (), ip
);
4794 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4795 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4796 i32
= mono_class_value_size (klass
, NULL
);
4799 #ifndef DISABLE_REMOTING
4800 if (mono_object_is_transparent_proxy (o
)) {
4801 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4802 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
4803 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4806 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
4809 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4812 MINT_IN_CASE(MINT_LDSFLDA
) {
4813 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4814 INIT_VTABLE (vtable
);
4815 sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
4821 MINT_IN_CASE(MINT_LDSSFLDA
) {
4822 guint32 offset
= READ32(ip
+ 1);
4823 sp
->data
.p
= mono_get_special_static_data (offset
);
4829 /* We init class here to preserve cctor order */
4830 #define LDSFLD(datamem, fieldtype) { \
4831 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4832 INIT_VTABLE (vtable); \
4833 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
4838 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
4839 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
4840 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
4841 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
4842 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
4843 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
4844 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
4845 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
4846 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
4847 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
4849 MINT_IN_CASE(MINT_LDSFLD_VT
) {
4850 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4851 gpointer addr
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
4852 i32
= READ32(ip
+ 3);
4853 INIT_VTABLE (vtable
);
4856 memcpy (vt_sp
, addr
, i32
);
4857 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4863 #define LDTSFLD(datamem, fieldtype) { \
4864 guint32 offset = READ32(ip + 1); \
4865 MonoInternalThread *thread = mono_thread_internal_current (); \
4866 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4867 sp[0].data.datamem = *(fieldtype*)addr; \
4871 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
4872 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
4873 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
4874 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
4875 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
4876 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
4877 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
4878 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
4879 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
4880 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
4882 MINT_IN_CASE(MINT_LDSSFLD
) {
4883 MonoClassField
*field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4884 guint32 offset
= READ32(ip
+ 2);
4885 gpointer addr
= mono_get_special_static_data (offset
);
4886 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
4891 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
4892 guint32 offset
= READ32(ip
+ 1);
4893 gpointer addr
= mono_get_special_static_data (offset
);
4895 int size
= READ32 (ip
+ 3);
4896 memcpy (vt_sp
, addr
, size
);
4898 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4903 #define STSFLD(datamem, fieldtype) { \
4904 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4905 INIT_VTABLE (vtable); \
4907 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
4911 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
4912 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
4913 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
4914 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
4915 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
4916 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
4917 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
4918 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
4919 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
4920 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
4922 MINT_IN_CASE(MINT_STSFLD_VT
) {
4923 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4924 gpointer addr
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
4925 i32
= READ32(ip
+ 3);
4926 INIT_VTABLE (vtable
);
4928 memcpy (addr
, sp
[-1].data
.vt
, i32
);
4929 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4935 #define STTSFLD(datamem, fieldtype) { \
4936 guint32 offset = READ32(ip + 1); \
4937 MonoInternalThread *thread = mono_thread_internal_current (); \
4938 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4940 *(fieldtype*)addr = sp[0].data.datamem; \
4944 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
4945 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
4946 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
4947 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
4948 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
4949 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
4950 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
4951 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
4952 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
4953 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
4955 MINT_IN_CASE(MINT_STSSFLD
) {
4956 MonoClassField
*field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4957 guint32 offset
= READ32(ip
+ 2);
4958 gpointer addr
= mono_get_special_static_data (offset
);
4960 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
4964 MINT_IN_CASE(MINT_STSSFLD_VT
) {
4965 guint32 offset
= READ32(ip
+ 1);
4966 gpointer addr
= mono_get_special_static_data (offset
);
4968 int size
= READ32 (ip
+ 3);
4969 memcpy (addr
, sp
->data
.vt
, size
);
4970 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4975 MINT_IN_CASE(MINT_STOBJ_VT
) {
4977 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4979 size
= mono_class_value_size (c
, NULL
);
4980 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
4981 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4985 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
4986 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
4987 THROW_EX (mono_get_exception_overflow (), ip
);
4988 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4991 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
4992 if (sp
[-1].data
.i
< 0)
4993 THROW_EX (mono_get_exception_overflow (), ip
);
4994 sp
[-1].data
.l
= sp
[-1].data
.i
;
4997 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
4998 if (sp
[-1].data
.l
< 0)
4999 THROW_EX (mono_get_exception_overflow (), ip
);
5002 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5003 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5004 THROW_EX (mono_get_exception_overflow (), ip
);
5007 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5008 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5009 THROW_EX (mono_get_exception_overflow (), ip
);
5010 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5013 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5014 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5015 THROW_EX (mono_get_exception_overflow (), ip
);
5016 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5019 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5020 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
5021 THROW_EX (mono_get_exception_overflow (), ip
);
5022 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5025 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5026 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5027 THROW_EX (mono_get_exception_overflow (), ip
);
5028 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5031 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5032 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5033 THROW_EX (mono_get_exception_overflow (), ip
);
5034 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5037 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5038 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5039 THROW_EX (mono_get_exception_overflow (), ip
);
5040 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5043 MINT_IN_CASE(MINT_BOX
) {
5044 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5045 guint16 offset
= * (guint16
*)(ip
+ 2);
5047 MonoObject
*obj
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5048 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (obj
), FALSE
);
5050 sp
[-1 - offset
].data
.p
= obj
;
5055 MINT_IN_CASE(MINT_BOX_VT
) {
5056 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5058 guint16 offset
= * (guint16
*)(ip
+ 2);
5059 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
5060 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
5062 int size
= mono_class_value_size (c
, NULL
);
5063 MonoObject
*obj
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5064 mono_value_copy_internal (mono_object_get_data (obj
), sp
[-1 - offset
].data
.p
, c
);
5066 sp
[-1 - offset
].data
.p
= obj
;
5067 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5074 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5075 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5076 guint16 offset
= * (guint16
*)(ip
+ 2);
5077 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
5078 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
5080 int size
= mono_class_value_size (c
, NULL
);
5082 sp
[-1 - offset
].data
.p
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
5083 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5085 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5092 MINT_IN_CASE(MINT_NEWARR
)
5093 sp
[-1].data
.p
= (MonoObject
*) mono_array_new_checked (imethod
->domain
, (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)], sp
[-1].data
.i
, error
);
5094 if (!mono_error_ok (error
)) {
5095 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5097 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5099 /*if (profiling_classes) {
5100 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5102 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5106 MINT_IN_CASE(MINT_LDLEN
)
5109 THROW_EX (mono_get_exception_null_reference (), ip
);
5110 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5113 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5115 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 1);
5117 THROW_EX (mono_get_exception_null_reference (), ip
);
5118 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5122 MINT_IN_CASE(MINT_GETCHR
) {
5124 s
= (MonoString
*)sp
[-2].data
.p
;
5126 THROW_EX (mono_get_exception_null_reference (), ip
);
5127 i32
= sp
[-1].data
.i
;
5128 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5129 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5131 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5135 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5136 guint8
*span
= (guint8
*) sp
[-2].data
.p
;
5137 int index
= sp
[-1].data
.i
;
5138 gsize element_size
= (gsize
) *(gint16
*) (ip
+ 1);
5139 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 2);
5140 gsize offset_pointer
= (gsize
) *(gint16
*) (ip
+ 3);
5144 THROW_EX (mono_get_exception_null_reference (), ip
);
5146 gint32 length
= *(gint32
*) (span
+ offset_length
);
5147 if (index
< 0 || index
>= length
)
5148 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5150 gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5151 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5156 MINT_IN_CASE(MINT_STRLEN
)
5160 THROW_EX (mono_get_exception_null_reference (), ip
);
5161 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5163 MINT_IN_CASE(MINT_ARRAY_RANK
)
5166 THROW_EX (mono_get_exception_null_reference (), ip
);
5167 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
5170 MINT_IN_CASE(MINT_LDELEMA
)
5171 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5172 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
5174 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[*(guint16
*) (ip
+ 1)];
5175 guint16 numargs
= *(guint16
*) (ip
+ 2);
5181 THROW_EX (mono_get_exception_null_reference (), ip
);
5182 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
5184 THROW_EX (frame
->ex
, ip
);
5189 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
5190 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
5191 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
5192 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
5193 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
5194 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
5195 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
5196 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
5197 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
5198 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
5199 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
5200 MINT_IN_CASE(MINT_LDELEM_VT
) {
5206 o
= (MonoArray
*)sp
[0].data
.p
;
5208 THROW_EX (mono_get_exception_null_reference (), ip
);
5210 aindex
= sp
[1].data
.i
;
5211 if (aindex
>= mono_array_length_internal (o
))
5212 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5215 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5218 case MINT_LDELEM_I1
:
5219 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
5221 case MINT_LDELEM_U1
:
5222 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
5224 case MINT_LDELEM_I2
:
5225 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
5227 case MINT_LDELEM_U2
:
5228 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
5231 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
5233 case MINT_LDELEM_I4
:
5234 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
5236 case MINT_LDELEM_U4
:
5237 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
5239 case MINT_LDELEM_I8
:
5240 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
5242 case MINT_LDELEM_R4
:
5243 sp
[0].data
.f_r4
= mono_array_get_fast (o
, float, aindex
);
5245 case MINT_LDELEM_R8
:
5246 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
5248 case MINT_LDELEM_REF
:
5249 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
5251 case MINT_LDELEM_VT
: {
5252 i32
= READ32 (ip
+ 1);
5253 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5254 sp
[0].data
.vt
= vt_sp
;
5255 // Copying to vtstack. No wbarrier needed
5256 memcpy (sp
[0].data
.vt
, src_addr
, i32
);
5257 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5269 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
5270 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
5271 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
5272 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
5273 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
5274 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
5275 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
5276 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
5277 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
5278 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
5279 MINT_IN_CASE(MINT_STELEM_VT
) {
5286 THROW_EX (mono_get_exception_null_reference (), ip
);
5288 aindex
= sp
[1].data
.i
;
5289 if (aindex
>= mono_array_length_internal ((MonoArray
*)o
))
5290 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5294 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
5296 case MINT_STELEM_I1
:
5297 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
5299 case MINT_STELEM_U1
:
5300 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
5302 case MINT_STELEM_I2
:
5303 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
5305 case MINT_STELEM_U2
:
5306 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
5308 case MINT_STELEM_I4
:
5309 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
5311 case MINT_STELEM_I8
:
5312 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
5314 case MINT_STELEM_R4
:
5315 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f_r4
);
5317 case MINT_STELEM_R8
:
5318 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
5320 case MINT_STELEM_REF
: {
5321 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
5322 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5323 if (sp
[2].data
.p
&& !isinst_obj
)
5324 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5325 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5328 case MINT_STELEM_VT
: {
5329 MonoClass
*klass_vt
= (MonoClass
*)imethod
->data_items
[*(guint16
*) (ip
+ 1)];
5330 i32
= READ32 (ip
+ 2);
5331 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5333 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5334 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5345 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5346 if (sp
[-1].data
.i
< 0)
5347 THROW_EX (mono_get_exception_overflow (), ip
);
5350 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5351 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5352 THROW_EX (mono_get_exception_overflow (), ip
);
5353 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5356 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5357 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5358 THROW_EX (mono_get_exception_overflow (), ip
);
5359 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5362 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5363 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
)
5364 THROW_EX (mono_get_exception_overflow (), ip
);
5365 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5368 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5369 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
5370 THROW_EX (mono_get_exception_overflow (), ip
);
5371 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5374 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5375 if (sp
[-1].data
.i
< 0)
5376 THROW_EX (mono_get_exception_overflow (), ip
);
5379 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5380 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5381 THROW_EX (mono_get_exception_overflow (), ip
);
5382 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5385 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5386 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
)
5387 THROW_EX (mono_get_exception_overflow (), ip
);
5388 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5391 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5392 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
5393 THROW_EX (mono_get_exception_overflow (), ip
);
5394 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5397 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5398 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5399 THROW_EX (mono_get_exception_overflow (), ip
);
5402 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
5403 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
5404 THROW_EX (mono_get_exception_overflow (), ip
);
5407 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
5408 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
5409 THROW_EX (mono_get_exception_overflow (), ip
);
5410 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5413 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
5414 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
5415 THROW_EX (mono_get_exception_overflow (), ip
);
5416 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5419 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
5420 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
5421 THROW_EX (mono_get_exception_overflow (), ip
);
5422 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5425 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
5426 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
5427 THROW_EX (mono_get_exception_overflow (), ip
);
5428 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5431 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
5432 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
5433 THROW_EX (mono_get_exception_overflow (), ip
);
5436 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
5437 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
5438 THROW_EX (mono_get_exception_overflow (), ip
);
5439 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
5442 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
5443 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
5444 THROW_EX (mono_get_exception_overflow (), ip
);
5445 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
5448 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
5449 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
5450 THROW_EX (mono_get_exception_overflow (), ip
);
5453 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
5454 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
5455 THROW_EX (mono_get_exception_overflow (), ip
);
5458 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
5459 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
5460 THROW_EX (mono_get_exception_overflow (), ip
);
5461 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5464 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
5465 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
5466 THROW_EX (mono_get_exception_overflow (), ip
);
5467 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5470 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
5471 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
5472 THROW_EX (mono_get_exception_overflow (), ip
);
5473 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5476 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
5477 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
5478 THROW_EX (mono_get_exception_overflow (), ip
);
5479 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5482 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
5483 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
5484 THROW_EX (mono_get_exception_overflow (), ip
);
5487 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
5488 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
5489 THROW_EX (mono_get_exception_overflow (), ip
);
5490 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
5493 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
5494 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
5495 THROW_EX (mono_get_exception_overflow (), ip
);
5496 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
5499 MINT_IN_CASE(MINT_CKFINITE
)
5500 if (!mono_isfinite (sp
[-1].data
.f
))
5501 THROW_EX (mono_get_exception_arithmetic (), ip
);
5504 MINT_IN_CASE(MINT_MKREFANY
) {
5505 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5507 /* The value address is on the stack */
5508 gpointer addr
= sp
[-1].data
.p
;
5509 /* Push the typedref value on the stack */
5510 sp
[-1].data
.p
= vt_sp
;
5511 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5513 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5515 tref
->type
= m_class_get_byval_arg (c
);
5521 MINT_IN_CASE(MINT_REFANYTYPE
) {
5522 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5523 MonoType
*type
= tref
->type
;
5525 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5526 sp
[-1].data
.p
= vt_sp
;
5528 *(gpointer
*)sp
[-1].data
.p
= type
;
5532 MINT_IN_CASE(MINT_REFANYVAL
) {
5533 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5534 gpointer addr
= tref
->value
;
5536 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5537 if (c
!= tref
->klass
)
5538 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5540 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5542 sp
[-1].data
.p
= addr
;
5546 MINT_IN_CASE(MINT_LDTOKEN
)
5549 * (gpointer
*)sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5553 MINT_IN_CASE(MINT_ADD_OVF_I4
)
5554 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5555 THROW_EX (mono_get_exception_overflow (), ip
);
5558 MINT_IN_CASE(MINT_ADD_OVF_I8
)
5559 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5560 THROW_EX (mono_get_exception_overflow (), ip
);
5563 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
5564 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5565 THROW_EX (mono_get_exception_overflow (), ip
);
5566 BINOP_CAST(i
, +, guint32
);
5568 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
5569 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5570 THROW_EX (mono_get_exception_overflow (), ip
);
5571 BINOP_CAST(l
, +, guint64
);
5573 MINT_IN_CASE(MINT_MUL_OVF_I4
)
5574 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5575 THROW_EX (mono_get_exception_overflow (), ip
);
5578 MINT_IN_CASE(MINT_MUL_OVF_I8
)
5579 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5580 THROW_EX (mono_get_exception_overflow (), ip
);
5583 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
5584 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5585 THROW_EX (mono_get_exception_overflow (), ip
);
5586 BINOP_CAST(i
, *, guint32
);
5588 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
5589 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5590 THROW_EX (mono_get_exception_overflow (), ip
);
5591 BINOP_CAST(l
, *, guint64
);
5593 MINT_IN_CASE(MINT_SUB_OVF_I4
)
5594 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5595 THROW_EX (mono_get_exception_overflow (), ip
);
5598 MINT_IN_CASE(MINT_SUB_OVF_I8
)
5599 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5600 THROW_EX (mono_get_exception_overflow (), ip
);
5603 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
5604 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5605 THROW_EX (mono_get_exception_overflow (), ip
);
5606 BINOP_CAST(i
, -, guint32
);
5608 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
5609 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5610 THROW_EX (mono_get_exception_overflow (), ip
);
5611 BINOP_CAST(l
, -, guint64
);
5613 MINT_IN_CASE(MINT_START_ABORT_PROT
)
5614 mono_threads_begin_abort_protected_block ();
5617 MINT_IN_CASE(MINT_ENDFINALLY
) {
5619 int clause_index
= *ip
;
5620 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
5622 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
5624 while (sp
> frame
->stack
) {
5628 ip
= (const guint16
*)finally_ips
->data
;
5629 finally_ips
= g_slist_remove (finally_ips
, ip
);
5630 /* Throw abort after the last finally block to avoid confusing EH */
5631 if (pending_abort
&& !finally_ips
)
5632 EXCEPTION_CHECKPOINT
;
5639 MINT_IN_CASE(MINT_LEAVE
) /* Fall through */
5640 MINT_IN_CASE(MINT_LEAVE_S
)
5641 while (sp
> frame
->stack
) {
5646 if (*ip
== MINT_LEAVE_S
) {
5647 ip
+= (short) *(ip
+ 1);
5649 ip
+= (gint32
) READ32 (ip
+ 1);
5652 goto handle_finally
;
5654 MINT_IN_CASE(MINT_LEAVE_CHECK
)
5655 MINT_IN_CASE(MINT_LEAVE_S_CHECK
)
5656 while (sp
> frame
->stack
) {
5661 if (imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
5664 child_frame
.parent
= frame
;
5665 child_frame
.imethod
= NULL
;
5667 * We need for mono_thread_get_undeniable_exception to be able to unwind
5668 * to check the abort threshold. For this to work we use child_frame as a
5669 * dummy frame that is stored in the lmf and serves as the transition frame
5671 do_icall_wrapper (&child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
);
5673 MonoException
*abort_exc
= (MonoException
*)tmp_sp
.data
.p
;
5675 THROW_EX (abort_exc
, frame
->ip
);
5678 if (*ip
== MINT_LEAVE_S_CHECK
) {
5679 ip
+= (short) *(ip
+ 1);
5681 ip
+= (gint32
) READ32 (ip
+ 1);
5684 goto handle_finally
;
5686 MINT_IN_CASE(MINT_ICALL_V_V
)
5687 MINT_IN_CASE(MINT_ICALL_V_P
)
5688 MINT_IN_CASE(MINT_ICALL_P_V
)
5689 MINT_IN_CASE(MINT_ICALL_P_P
)
5690 MINT_IN_CASE(MINT_ICALL_PP_V
)
5691 MINT_IN_CASE(MINT_ICALL_PP_P
)
5692 MINT_IN_CASE(MINT_ICALL_PPP_V
)
5693 MINT_IN_CASE(MINT_ICALL_PPP_P
)
5694 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
5695 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
5696 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
5697 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
5698 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
5699 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
5701 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, imethod
->data_items
[*(guint16
*)(ip
+ 1)]);
5702 EXCEPTION_CHECKPOINT
;
5703 CHECK_RESUME_STATE (context
);
5706 MINT_IN_CASE(MINT_MONO_LDPTR
)
5707 sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5711 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
5712 sp
->data
.p
= mono_object_new_checked (imethod
->domain
, (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)], error
);
5713 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5717 MINT_IN_CASE(MINT_MONO_FREE
)
5720 g_error ("that doesn't seem right");
5721 g_free (sp
->data
.p
);
5723 MINT_IN_CASE(MINT_MONO_RETOBJ
)
5726 stackval_from_data (mono_method_signature_internal (imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
5727 mono_method_signature_internal (imethod
->method
)->pinvoke
);
5728 if (sp
> frame
->stack
)
5729 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
5731 MINT_IN_CASE(MINT_MONO_TLS
) {
5732 MonoTlsKey key
= (MonoTlsKey
)*(gint32
*)(ip
+ 1);
5733 sp
->data
.p
= mono_tls_get_tls_getter (key
) (); // get function pointer and call it
5738 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
5740 mono_memory_barrier ();
5743 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
5744 sp
->data
.p
= mono_domain_get ();
5748 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
5749 if (G_UNLIKELY (ss_enabled
)) {
5750 typedef void (*T
) (void);
5754 void *tramp
= mini_get_single_step_trampoline ();
5755 mono_memory_barrier ();
5756 ss_tramp
= (T
)tramp
;
5760 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5761 * the address of that instruction is stored as the seq point address.
5766 * Use the same trampoline as the JIT. This ensures that
5767 * the debugger has the context for the last interpreter
5770 do_debugger_tramp (ss_tramp
, frame
);
5772 CHECK_RESUME_STATE (context
);
5776 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
5777 /* Just a placeholder for a breakpoint */
5780 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
5781 typedef void (*T
) (void);
5784 void *tramp
= mini_get_breakpoint_trampoline ();
5785 mono_memory_barrier ();
5786 bp_tramp
= (T
)tramp
;
5791 /* Use the same trampoline as the JIT */
5792 do_debugger_tramp (bp_tramp
, frame
);
5794 CHECK_RESUME_STATE (context
);
5800 #define RELOP(datamem, op) \
5802 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5805 #define RELOP_FP(datamem, op, noorder) \
5807 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5808 sp [-1].data.i = noorder; \
5810 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5813 MINT_IN_CASE(MINT_CEQ_I4
)
5816 MINT_IN_CASE(MINT_CEQ0_I4
)
5817 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
5820 MINT_IN_CASE(MINT_CEQ_I8
)
5823 MINT_IN_CASE(MINT_CEQ_R4
)
5824 RELOP_FP(f_r4
, ==, 0);
5826 MINT_IN_CASE(MINT_CEQ_R8
)
5829 MINT_IN_CASE(MINT_CNE_I4
)
5832 MINT_IN_CASE(MINT_CNE_I8
)
5835 MINT_IN_CASE(MINT_CNE_R4
)
5836 RELOP_FP(f_r4
, !=, 1);
5838 MINT_IN_CASE(MINT_CNE_R8
)
5841 MINT_IN_CASE(MINT_CGT_I4
)
5844 MINT_IN_CASE(MINT_CGT_I8
)
5847 MINT_IN_CASE(MINT_CGT_R4
)
5848 RELOP_FP(f_r4
, >, 0);
5850 MINT_IN_CASE(MINT_CGT_R8
)
5853 MINT_IN_CASE(MINT_CGE_I4
)
5856 MINT_IN_CASE(MINT_CGE_I8
)
5859 MINT_IN_CASE(MINT_CGE_R4
)
5860 RELOP_FP(f_r4
, >=, 0);
5862 MINT_IN_CASE(MINT_CGE_R8
)
5866 #define RELOP_CAST(datamem, op, type) \
5868 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5871 MINT_IN_CASE(MINT_CGE_UN_I4
)
5872 RELOP_CAST(l
, >=, guint32
);
5874 MINT_IN_CASE(MINT_CGE_UN_I8
)
5875 RELOP_CAST(l
, >=, guint64
);
5878 MINT_IN_CASE(MINT_CGT_UN_I4
)
5879 RELOP_CAST(i
, >, guint32
);
5881 MINT_IN_CASE(MINT_CGT_UN_I8
)
5882 RELOP_CAST(l
, >, guint64
);
5884 MINT_IN_CASE(MINT_CGT_UN_R4
)
5885 RELOP_FP(f_r4
, >, 1);
5887 MINT_IN_CASE(MINT_CGT_UN_R8
)
5890 MINT_IN_CASE(MINT_CLT_I4
)
5893 MINT_IN_CASE(MINT_CLT_I8
)
5896 MINT_IN_CASE(MINT_CLT_R4
)
5897 RELOP_FP(f_r4
, <, 0);
5899 MINT_IN_CASE(MINT_CLT_R8
)
5902 MINT_IN_CASE(MINT_CLT_UN_I4
)
5903 RELOP_CAST(i
, <, guint32
);
5905 MINT_IN_CASE(MINT_CLT_UN_I8
)
5906 RELOP_CAST(l
, <, guint64
);
5908 MINT_IN_CASE(MINT_CLT_UN_R4
)
5909 RELOP_FP(f_r4
, <, 1);
5911 MINT_IN_CASE(MINT_CLT_UN_R8
)
5914 MINT_IN_CASE(MINT_CLE_I4
)
5917 MINT_IN_CASE(MINT_CLE_I8
)
5920 MINT_IN_CASE(MINT_CLE_UN_I4
)
5921 RELOP_CAST(l
, <=, guint32
);
5923 MINT_IN_CASE(MINT_CLE_UN_I8
)
5924 RELOP_CAST(l
, <=, guint64
);
5926 MINT_IN_CASE(MINT_CLE_R4
)
5927 RELOP_FP(f_r4
, <=, 0);
5929 MINT_IN_CASE(MINT_CLE_R8
)
5937 MINT_IN_CASE(MINT_LDFTN
) {
5938 sp
->data
.p
= imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5943 MINT_IN_CASE(MINT_LDVIRTFTN
) {
5944 InterpMethod
*m
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5948 THROW_EX (mono_get_exception_null_reference (), ip
- 2);
5950 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
);
5954 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
5956 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
5957 mono_error_assert_ok (error
);
5963 #define LDARG(datamem, argtype) \
5964 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
5968 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
5969 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
5970 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
5971 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
5972 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
5973 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
5974 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
5975 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
5976 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
5977 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
5979 MINT_IN_CASE(MINT_LDARG_VT
)
5981 i32
= READ32(ip
+ 2);
5982 memcpy(sp
->data
.p
, frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
, i32
);
5983 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5988 #define STARG(datamem, argtype) \
5990 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
5993 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
5994 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
5995 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
5996 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
5997 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
5998 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
5999 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6000 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6001 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6002 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6004 MINT_IN_CASE(MINT_STARG_VT
)
6005 i32
= READ32(ip
+ 2);
6007 memcpy(frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
, sp
->data
.p
, i32
);
6008 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6012 MINT_IN_CASE(MINT_PROF_ENTER
) {
6015 if (MONO_PROFILER_ENABLED (method_enter
)) {
6016 MonoProfilerCallContext
*prof_ctx
= NULL
;
6018 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
6019 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6020 prof_ctx
->interp_frame
= frame
;
6021 prof_ctx
->method
= imethod
->method
;
6024 MONO_PROFILER_RAISE (method_enter
, (imethod
->method
, prof_ctx
));
6032 MINT_IN_CASE(MINT_TRACE_ENTER
) {
6035 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6036 prof_ctx
->interp_frame
= frame
;
6037 prof_ctx
->method
= imethod
->method
;
6039 mono_trace_enter_method (imethod
->method
, prof_ctx
);
6043 MINT_IN_CASE(MINT_TRACE_EXIT
) {
6046 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6047 prof_ctx
->interp_frame
= frame
;
6048 prof_ctx
->method
= imethod
->method
;
6050 mono_trace_leave_method (imethod
->method
, prof_ctx
);
6054 MINT_IN_CASE(MINT_LDARGA
)
6055 sp
->data
.p
= &frame
->stack_args
[* (guint16
*)(ip
+ 1)];
6060 MINT_IN_CASE(MINT_LDARGA_VT
)
6061 sp
->data
.p
= frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
;
6066 #define LDLOC(datamem, argtype) \
6067 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6071 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6072 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6073 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6074 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6075 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6076 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6077 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6078 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6079 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6080 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6082 MINT_IN_CASE(MINT_LDLOC_VT
)
6084 i32
= READ32(ip
+ 2);
6085 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
6086 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6091 MINT_IN_CASE(MINT_LDLOCA_S
)
6092 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
6097 #define STLOC(datamem, argtype) \
6099 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6102 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6103 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6104 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6105 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6106 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6107 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6108 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6109 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6110 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6111 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6113 #define STLOC_NP(datamem, argtype) \
6114 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6117 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6118 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6120 MINT_IN_CASE(MINT_STLOC_VT
)
6121 i32
= READ32(ip
+ 2);
6123 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
6124 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6128 MINT_IN_CASE(MINT_LOCALLOC
) {
6129 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6130 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6132 int len
= sp
[-1].data
.i
;
6133 sp
[-1].data
.p
= alloca (len
);
6135 if (imethod
->init_locals
)
6136 memset (sp
[-1].data
.p
, 0, len
);
6140 MINT_IN_CASE(MINT_ENDFILTER
)
6141 /* top of stack is result of filter */
6142 frame
->retval
= &sp
[-1];
6144 MINT_IN_CASE(MINT_INITOBJ
)
6146 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6149 MINT_IN_CASE(MINT_CPBLK
)
6151 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6152 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6154 /* FIXME: value and size may be int64... */
6155 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6158 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6160 /* FIXME: implement */
6162 token
= READ32 (ip
);
6167 MINT_IN_CASE(MINT_INITBLK
)
6170 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6172 /* FIXME: value and size may be int64... */
6173 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6176 MINT_IN_CASE(MINT_NO_
)
6177 /* FIXME: implement */
6181 MINT_IN_CASE(MINT_RETHROW
) {
6182 int exvar_offset
= *(guint16
*)(ip
+ 1);
6183 THROW_EX_GENERAL (*(MonoException
**)(frame
->locals
+ exvar_offset
), ip
, TRUE
);
6186 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6188 * need to clarify what this should actually do:
6190 * Takes an exception from the stack and rethrows it.
6191 * This is useful for wrappers that don't want to have to
6192 * use CEE_THROW and lose the exception stacktrace.
6197 sp
->data
.p
= mono_get_exception_null_reference ();
6199 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6202 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6206 del
= (MonoDelegate
*)sp
->data
.p
;
6207 if (!del
->interp_method
) {
6208 /* Not created from interpreted code */
6210 g_assert (del
->method
);
6211 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6212 mono_error_assert_ok (error
);
6214 g_assert (del
->interp_method
);
6215 sp
->data
.p
= del
->interp_method
;
6220 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6222 int n
= *(guint16
*)(ip
+ 1);
6223 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6224 if (!del
->interp_invoke_impl
) {
6226 * First time we are called. Set up the invoke wrapper. We might be able to do this
6227 * in ctor but we would need to handle AllocDelegateLike_internal separately
6230 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6231 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6232 mono_error_assert_ok (error
);
6235 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6240 #define MATH_UNOP(mathfunc) \
6241 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6244 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
6245 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
6246 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
6247 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
6248 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
6249 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
6250 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
6251 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
6252 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
6253 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
6254 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
6255 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
6256 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
6257 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
6258 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
6260 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
6261 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6262 guint64 a_val
= 0, b_val
= 0;
6264 stackval_to_data (m_class_get_byval_arg (klass
), &sp
[-2], &a_val
, FALSE
);
6265 stackval_to_data (m_class_get_byval_arg (klass
), &sp
[-1], &b_val
, FALSE
);
6267 sp
[-1].data
.i
= (a_val
& b_val
) == b_val
;
6271 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
6272 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
6276 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
6278 THROW_EX (mono_get_exception_null_reference (), ip
);
6279 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
6285 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-imethod
->code
);
6286 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip
);
6290 g_assert_not_reached ();
6295 MonoExceptionClause
*clause
;
6296 GSList
*old_list
= finally_ips
;
6297 MonoMethod
*method
= imethod
->method
;
6301 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- imethod
->code
);
6303 if (imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
6304 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
6307 ip_offset
= frame
->ip
- imethod
->code
;
6309 if (endfinally_ip
!= NULL
)
6310 finally_ips
= g_slist_prepend(finally_ips
, (void *)endfinally_ip
);
6312 for (i
= imethod
->num_clauses
- 1; i
>= 0; i
--) {
6313 clause
= &imethod
->clauses
[i
];
6314 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- imethod
->code
)))) {
6315 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6316 ip
= imethod
->code
+ clause
->handler_offset
;
6317 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
6320 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
6326 endfinally_ip
= NULL
;
6328 if (old_list
!= finally_ips
&& finally_ips
) {
6329 ip
= (const guint16
*)finally_ips
->data
;
6330 finally_ips
= g_slist_remove (finally_ips
, ip
);
6331 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
6332 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
6341 if (clause_args
&& clause_args
->base_frame
)
6342 memcpy (clause_args
->base_frame
->args
, frame
->args
, imethod
->alloca_size
);
6344 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
6345 imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
6346 MonoProfilerCallContext
*prof_ctx
= NULL
;
6348 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
6349 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6350 prof_ctx
->interp_frame
= frame
;
6351 prof_ctx
->method
= imethod
->method
;
6353 MonoType
*rtype
= mono_method_signature_internal (imethod
->method
)->ret
;
6355 switch (rtype
->type
) {
6356 case MONO_TYPE_VOID
:
6358 case MONO_TYPE_VALUETYPE
:
6359 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6362 prof_ctx
->return_value
= frame
->retval
;
6367 MONO_PROFILER_RAISE (method_leave
, (imethod
->method
, prof_ctx
));
6370 } else if (frame
->ex
&& imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
6371 MONO_PROFILER_RAISE (method_exception_leave
, (imethod
->method
, &frame
->ex
->object
));
6377 interp_parse_options (const char *options
)
6384 args
= g_strsplit (options
, ",", -1);
6385 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
6388 if (strncmp (arg
, "jit=", 4) == 0)
6389 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
6390 if (strncmp (arg
, "interp-only=", 4) == 0)
6391 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
6392 if (strncmp (arg
, "-inline", 7) == 0)
6393 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6397 typedef int (*TestMethod
) (void);
6400 * interp_set_resume_state:
6402 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6405 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
6407 ThreadContext
*context
;
6410 context
= (ThreadContext
*)jit_tls
->interp_context
;
6413 context
->has_resume_state
= TRUE
;
6414 context
->handler_frame
= (InterpFrame
*)interp_frame
;
6415 context
->handler_ei
= ei
;
6416 /* This is on the stack, so it doesn't need a wbarrier */
6417 context
->handler_frame
->ex
= ex
;
6420 *(MonoException
**)(context
->handler_frame
->locals
+ ei
->exvar_offset
) = ex
;
6421 context
->handler_ip
= (guint16
*) handler_ip
;
6425 * interp_run_finally:
6427 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6428 * frame->interp_frame.
6429 * Return TRUE if the finally clause threw an exception.
6432 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6434 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6435 ThreadContext
*context
= get_context ();
6436 const unsigned short *old_ip
= iframe
->ip
;
6437 FrameClauseArgs clause_args
;
6439 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6440 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6441 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6442 clause_args
.exit_clause
= clause_index
;
6444 interp_exec_method_full (iframe
, context
, &clause_args
);
6445 if (context
->has_resume_state
) {
6448 iframe
->ip
= old_ip
;
6454 * interp_run_filter:
6456 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6457 * frame->interp_frame.
6460 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6462 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6463 ThreadContext
*context
= get_context ();
6464 InterpFrame child_frame
;
6466 FrameClauseArgs clause_args
;
6469 * Have to run the clause in a new frame which is a copy of IFRAME, since
6470 * during debugging, there are two copies of the frame on the stack.
6472 memset (&child_frame
, 0, sizeof (InterpFrame
));
6473 child_frame
.imethod
= iframe
->imethod
;
6474 child_frame
.retval
= &retval
;
6475 child_frame
.parent
= iframe
;
6476 child_frame
.stack_args
= iframe
->stack_args
;
6478 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6479 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6480 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6481 clause_args
.filter_exception
= ex
;
6482 clause_args
.base_frame
= iframe
;
6484 interp_exec_method_full (&child_frame
, context
, &clause_args
);
6485 /* ENDFILTER stores the result into child_frame->retval */
6486 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
6490 InterpFrame
*current
;
6494 * interp_frame_iter_init:
6496 * Initialize an iterator for iterating through interpreted frames.
6499 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
6501 StackIter
*stack_iter
= (StackIter
*)iter
;
6503 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
6507 * interp_frame_iter_next:
6509 * Fill out FRAME with date for the next interpreter frame.
6512 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
6514 StackIter
*stack_iter
= (StackIter
*)iter
;
6515 InterpFrame
*iframe
= stack_iter
->current
;
6517 memset (frame
, 0, sizeof (StackFrameInfo
));
6518 /* pinvoke frames doesn't have imethod set */
6519 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
6520 iframe
= iframe
->parent
;
6524 MonoMethod
*method
= iframe
->imethod
->method
;
6525 frame
->domain
= iframe
->imethod
->domain
;
6526 frame
->interp_frame
= iframe
;
6527 frame
->method
= method
;
6528 frame
->actual_method
= method
;
6529 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
6530 frame
->native_offset
= -1;
6531 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
6533 frame
->type
= FRAME_TYPE_INTERP
;
6534 /* This is the offset in the interpreter IR */
6535 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
6536 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6537 frame
->managed
= TRUE
;
6539 frame
->ji
= iframe
->imethod
->jinfo
;
6540 frame
->frame_addr
= iframe
;
6542 stack_iter
->current
= iframe
->parent
;
6548 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
6550 InterpMethod
* imethod
;
6552 imethod
= lookup_imethod (domain
, method
);
6554 return imethod
->jinfo
;
6560 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6562 guint16
*code
= (guint16
*)ip
;
6563 g_assert (*code
== MINT_SDB_SEQ_POINT
);
6564 *code
= MINT_SDB_BREAKPOINT
;
6568 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6570 guint16
*code
= (guint16
*)ip
;
6571 g_assert (*code
== MINT_SDB_BREAKPOINT
);
6572 *code
= MINT_SDB_SEQ_POINT
;
6576 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
6578 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6580 g_assert (iframe
->imethod
);
6581 return iframe
->imethod
->jinfo
;
6585 interp_frame_get_ip (MonoInterpFrameHandle frame
)
6587 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6589 g_assert (iframe
->imethod
);
6590 return (gpointer
)iframe
->ip
;
6594 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
6596 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6597 MonoMethodSignature
*sig
;
6599 g_assert (iframe
->imethod
);
6601 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6602 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
6606 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
6608 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6610 g_assert (iframe
->imethod
);
6612 return iframe
->locals
+ iframe
->imethod
->local_offsets
[pos
];
6616 interp_frame_get_this (MonoInterpFrameHandle frame
)
6618 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6620 g_assert (iframe
->imethod
);
6621 g_assert (iframe
->imethod
->hasthis
);
6622 return &iframe
->stack_args
[0].data
.p
;
6625 static MonoInterpFrameHandle
6626 interp_frame_get_parent (MonoInterpFrameHandle frame
)
6628 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6630 return iframe
->parent
;
6634 interp_start_single_stepping (void)
6640 interp_stop_single_stepping (void)
6646 register_interp_stats (void)
6648 mono_counters_init ();
6649 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
6650 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
6651 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
6655 mono_ee_interp_init (const char *opts
)
6657 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
6658 g_assert (!interp_init_done
);
6659 interp_init_done
= TRUE
;
6661 mono_native_tls_alloc (&thread_context_id
, NULL
);
6664 interp_parse_options (opts
);
6665 if (mini_get_debug_options ()->mdb_optimizations
)
6666 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6667 mono_interp_transform_init ();
6670 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
6671 c
.entry_from_trampoline
= interp_entry_from_trampoline
;
6673 c
.to_native_trampoline
= interp_to_native_trampoline
;
6674 c
.create_method_pointer
= interp_create_method_pointer
;
6675 c
.create_method_pointer_llvmonly
= interp_create_method_pointer_llvmonly
;
6676 c
.runtime_invoke
= interp_runtime_invoke
;
6677 c
.init_delegate
= interp_init_delegate
;
6678 c
.delegate_ctor
= interp_delegate_ctor
;
6679 c
.get_remoting_invoke
= interp_get_remoting_invoke
;
6680 c
.set_resume_state
= interp_set_resume_state
;
6681 c
.run_finally
= interp_run_finally
;
6682 c
.run_filter
= interp_run_filter
;
6683 c
.frame_iter_init
= interp_frame_iter_init
;
6684 c
.frame_iter_next
= interp_frame_iter_next
;
6685 c
.find_jit_info
= interp_find_jit_info
;
6686 c
.set_breakpoint
= interp_set_breakpoint
;
6687 c
.clear_breakpoint
= interp_clear_breakpoint
;
6688 c
.frame_get_jit_info
= interp_frame_get_jit_info
;
6689 c
.frame_get_ip
= interp_frame_get_ip
;
6690 c
.frame_get_arg
= interp_frame_get_arg
;
6691 c
.frame_get_local
= interp_frame_get_local
;
6692 c
.frame_get_this
= interp_frame_get_this
;
6693 c
.frame_get_parent
= interp_frame_get_parent
;
6694 c
.frame_arg_to_data
= interp_frame_arg_to_data
;
6695 c
.data_to_frame_arg
= interp_data_to_frame_arg
;
6696 c
.frame_arg_to_storage
= interp_frame_arg_to_storage
;
6697 c
.frame_arg_set_storage
= interp_frame_arg_set_storage
;
6698 c
.start_single_stepping
= interp_start_single_stepping
;
6699 c
.stop_single_stepping
= interp_stop_single_stepping
;
6700 mini_install_interp_callbacks (&c
);
6702 register_interp_stats ();