4 * interp.c: Interpreter for CIL byte codes
7 * Paolo Molaro (lupus@ximian.com)
8 * Miguel de Icaza (miguel@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2001, 2002 Ximian, Inc.
25 #include <mono/utils/gc_wrapper.h>
26 #include <mono/utils/mono-math.h>
27 #include <mono/utils/mono-counters.h>
33 # define alloca __builtin_alloca
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
62 #include "interp-internals.h"
65 #include <mono/mini/mini.h>
66 #include <mono/mini/mini-runtime.h>
67 #include <mono/mini/aot-runtime.h>
68 #include <mono/mini/llvm-runtime.h>
69 #include <mono/mini/llvmonly-runtime.h>
70 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
73 #include <mono/mini/trace.h>
76 #include <mono/mini/mini-arm.h>
78 #include <mono/metadata/icall-decl.h>
81 #pragma warning(disable:4102) // label' : unreferenced label
84 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
86 /* Where we start the frame execution from */
87 guint16
*start_with_ip
;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
94 /* When exiting this clause we also exit the frame */
96 /* Exception that we are filtering */
97 MonoException
*filter_exception
;
98 InterpFrame
*base_frame
;
102 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
104 frame
->parent
= parent_frame
;
105 frame
->stack_args
= method_args
;
106 frame
->retval
= method_retval
;
107 frame
->imethod
= rmethod
;
112 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
115 * List of classes whose methods will be executed by transitioning to JITted code.
118 GSList
*mono_interp_jit_classes
;
119 /* Optimizations enabled with interpreter */
120 int mono_interp_opt
= INTERP_OPT_INLINE
;
121 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
122 static gboolean ss_enabled
;
124 static gboolean interp_init_done
= FALSE
;
126 static void interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
);
127 static InterpMethod
* lookup_method_pointer (gpointer addr
);
129 typedef void (*ICallMethod
) (InterpFrame
*frame
);
131 static MonoNativeTlsKey thread_context_id
;
133 #define DEBUG_INTERP 0
137 int mono_interp_traceopt
= 2;
138 /* If true, then we output the opcodes as we interpret them */
139 static int global_tracing
= 2;
141 static int debug_indent_level
= 0;
143 static int break_on_method
= 0;
144 static int nested_trace
= 0;
145 static GList
*db_methods
= NULL
;
146 static char* dump_args (InterpFrame
*inv
);
153 for (h
= 0; h
< debug_indent_level
; h
++)
158 db_match_method (gpointer data
, gpointer user_data
)
160 MonoMethod
*m
= (MonoMethod
*)user_data
;
161 MonoMethodDesc
*desc
= data
;
163 if (mono_method_desc_full_match (desc
, m
))
168 debug_enter (InterpFrame
*frame
, int *tracing
)
171 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
173 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
177 MonoMethod
*method
= frame
->imethod
->method
;
178 char *mn
, *args
= dump_args (frame
);
179 debug_indent_level
++;
181 mn
= mono_method_full_name (method
, FALSE
);
182 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
184 g_print ("%s)\n", args
);
190 #define DEBUG_LEAVE() \
193 args = dump_retval (frame); \
195 mn = mono_method_full_name (frame->imethod->method, FALSE); \
196 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
198 g_print (" => %s\n", args); \
200 debug_indent_level--; \
201 if (tracing == 3) global_tracing = 0; \
206 int mono_interp_traceopt
= 0;
207 static void debug_enter (InterpFrame
*frame
, int *tracing
)
210 #define DEBUG_LEAVE()
214 #if defined(__GNUC__) && !defined(TARGET_WASM)
215 #define USE_COMPUTED_GOTO 1
217 #if USE_COMPUTED_GOTO
218 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
219 #define MINT_IN_CASE(x) LAB_ ## x:
220 #define MINT_IN_DISPATCH(op) goto *in_labels[op];
222 #define MINT_IN_BREAK if (tracing > 1) { MINT_IN_DISPATCH(*ip); } else { COUNT_OP(*ip); goto *in_labels[*ip]; }
224 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
226 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
228 #define MINT_IN_SWITCH(op) switch (op)
229 #define MINT_IN_CASE(x) case x:
230 #define MINT_IN_DISPATCH(op) goto main_loop;
231 #define MINT_IN_BREAK break
232 #define MINT_IN_DEFAULT default:
236 set_resume_state (ThreadContext
*context
, InterpFrame
*frame
)
238 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */
239 while (frame
->finally_ips
&&
240 frame
->finally_ips
->data
>= context
->handler_ei
->try_start
&&
241 frame
->finally_ips
->data
< context
->handler_ei
->try_end
)
242 frame
->finally_ips
= g_slist_remove (frame
->finally_ips
, frame
->finally_ips
->data
);
244 context
->has_resume_state
= 0;
245 context
->handler_frame
= NULL
;
246 context
->handler_ei
= NULL
;
249 /* Set the current execution state to the resume state in context */
250 #define SET_RESUME_STATE(context) do { \
251 ip = (const guint16*)(context)->handler_ip; \
252 /* spec says stack should be empty at endfinally so it should be at the start too */ \
254 vt_sp = (unsigned char *) sp + imethod->stack_size; \
256 sp->data.p = frame->ex; \
259 set_resume_state ((context), (frame)); \
260 MINT_IN_DISPATCH(*ip); \
264 * If this bit is set, it means the call has thrown the exception, and we
265 * reached this point because the EH code in mono_handle_exception ()
266 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
267 * has set the fields in context to indicate where we have to resume execution.
269 #define CHECK_RESUME_STATE(context) do { \
270 if ((context)->has_resume_state) { \
271 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
272 SET_RESUME_STATE (context); \
279 set_context (ThreadContext
*context
)
281 mono_native_tls_set_value (thread_context_id
, context
);
286 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
287 g_assertf (jit_tls
, "ThreadContext needs initialized JIT TLS");
289 /* jit_tls assumes ownership of 'context' */
290 jit_tls
->interp_context
= context
;
293 static ThreadContext
*
296 ThreadContext
*context
= (ThreadContext
*) mono_native_tls_get_value (thread_context_id
);
297 if (context
== NULL
) {
298 context
= g_new0 (ThreadContext
, 1);
299 set_context (context
);
304 static MONO_NEVER_INLINE
void
305 ves_real_abort (int line
, MonoMethod
*mh
,
306 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
309 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, error
);
310 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
311 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh
->klass
), mh
->name
);
312 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
313 g_printerr ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
314 mono_metadata_free_mh (header
);
317 #define ves_abort() \
319 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
320 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
324 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
326 InterpMethod
*imethod
;
327 MonoJitDomainInfo
*info
;
329 info
= domain_jit_info (domain
);
330 mono_domain_jit_code_hash_lock (domain
);
331 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
332 mono_domain_jit_code_hash_unlock (domain
);
337 interp_get_remoting_invoke (MonoMethod
*method
, gpointer addr
, MonoError
*error
)
339 #ifndef DISABLE_REMOTING
340 InterpMethod
*imethod
;
343 imethod
= lookup_method_pointer (addr
);
346 imethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
347 return_val_if_nok (error
, NULL
);
350 g_assert (mono_use_interpreter
);
352 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke (imethod
->method
, error
);
353 return_val_if_nok (error
, NULL
);
354 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method
, error
);
356 g_assert_not_reached ();
362 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
364 InterpMethod
*imethod
;
365 MonoJitDomainInfo
*info
;
366 MonoMethodSignature
*sig
;
371 info
= domain_jit_info (domain
);
372 mono_domain_jit_code_hash_lock (domain
);
373 imethod
= (InterpMethod
*)mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
374 mono_domain_jit_code_hash_unlock (domain
);
378 sig
= mono_method_signature_internal (method
);
380 imethod
= (InterpMethod
*)mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
381 imethod
->method
= method
;
382 imethod
->domain
= domain
;
383 imethod
->param_count
= sig
->param_count
;
384 imethod
->hasthis
= sig
->hasthis
;
385 imethod
->vararg
= sig
->call_convention
== MONO_CALL_VARARG
;
386 imethod
->rtype
= mini_get_underlying_type (sig
->ret
);
387 imethod
->param_types
= (MonoType
**)mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
388 for (i
= 0; i
< sig
->param_count
; ++i
)
389 imethod
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
391 mono_domain_jit_code_hash_lock (domain
);
392 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
393 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, imethod
);
394 mono_domain_jit_code_hash_unlock (domain
);
396 imethod
->prof_flags
= mono_profiler_get_call_instrumentation_flags (imethod
->method
);
401 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
402 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
403 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
405 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
406 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
407 * (registers are not accurate), thus resuming to the label does not work. */
408 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
409 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
410 #elif defined (_MSC_VER)
411 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
412 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
413 (ext).interp_exit_label_set = FALSE; \
414 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
415 if ((ext).interp_exit_label_set == FALSE) \
416 mono_arch_do_ip_adjustment (&(ext).ctx); \
417 if ((ext).interp_exit_label_set == TRUE) \
419 (ext).interp_exit_label_set = TRUE;
420 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
421 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
422 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
423 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
424 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
425 mono_arch_do_ip_adjustment (&(ext).ctx);
427 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
430 /* INTERP_PUSH_LMF_WITH_CTX:
432 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
433 * This is needed to resume into the interp when the exception is thrown from
434 * native code (see ./mono/tests/install_eh_callback.exe).
436 * This must be a macro in order to retrieve the right register values for
439 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
440 memset (&(ext), 0, sizeof (MonoLMFExt)); \
441 (ext).interp_exit_data = (frame); \
442 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
443 mono_push_lmf (&(ext));
448 * Push an LMF frame on the LMF stack
449 * to mark the transition to native code.
450 * This is needed for the native code to
451 * be able to do stack walks.
454 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
456 memset (ext
, 0, sizeof (MonoLMFExt
));
457 ext
->kind
= MONO_LMFEXT_INTERP_EXIT
;
458 ext
->interp_exit_data
= frame
;
464 interp_pop_lmf (MonoLMFExt
*ext
)
466 mono_pop_lmf (&ext
->lmf
);
469 static MONO_NEVER_INLINE InterpMethod
*
470 get_virtual_method (InterpMethod
*imethod
, MonoVTable
*vtable
)
472 MonoMethod
*m
= imethod
->method
;
473 MonoDomain
*domain
= imethod
->domain
;
474 InterpMethod
*ret
= NULL
;
477 #ifndef DISABLE_REMOTING
478 if (mono_class_is_transparent_proxy (vtable
->klass
)) {
479 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
480 mono_error_assert_ok (error
);
481 ret
= mono_interp_get_imethod (domain
, remoting_invoke_method
, error
);
482 mono_error_assert_ok (error
);
487 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
488 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
489 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), error
);
490 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
497 mono_class_setup_vtable (vtable
->klass
);
499 int slot
= mono_method_get_vtable_slot (m
);
500 if (mono_class_is_interface (m
->klass
)) {
501 g_assert (vtable
->klass
!= m
->klass
);
502 /* TODO: interface offset lookup is slow, go through IMT instead */
503 gboolean non_exact_match
;
504 slot
+= mono_class_interface_offset_with_variance (vtable
->klass
, m
->klass
, &non_exact_match
);
507 MonoMethod
*virtual_method
= m_class_get_vtable (vtable
->klass
) [slot
];
508 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
509 MonoGenericContext context
= { NULL
, NULL
};
511 if (mono_class_is_ginst (virtual_method
->klass
))
512 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
513 else if (mono_class_is_gtd (virtual_method
->klass
))
514 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
515 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
517 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, error
);
518 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
521 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
522 virtual_method
= mono_marshal_get_native_wrapper (virtual_method
, FALSE
, FALSE
);
525 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
526 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
529 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, error
);
530 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
531 return virtual_imethod
;
535 InterpMethod
*imethod
;
536 InterpMethod
*target_imethod
;
539 /* domain lock must be held */
541 append_imethod (MonoDomain
*domain
, GSList
*list
, InterpMethod
*imethod
, InterpMethod
*target_imethod
)
544 InterpVTableEntry
*entry
;
546 entry
= (InterpVTableEntry
*) mono_mempool_alloc (domain
->mp
, sizeof (InterpVTableEntry
));
547 entry
->imethod
= imethod
;
548 entry
->target_imethod
= target_imethod
;
549 ret
= g_slist_append_mempool (domain
->mp
, list
, entry
);
555 get_target_imethod (GSList
*list
, InterpMethod
*imethod
)
557 while (list
!= NULL
) {
558 InterpVTableEntry
*entry
= (InterpVTableEntry
*) list
->data
;
559 if (entry
->imethod
== imethod
)
560 return entry
->target_imethod
;
567 get_method_table (MonoVTable
*vtable
, int offset
)
570 return vtable
->interp_vtable
;
572 return (gpointer
*)vtable
;
576 alloc_method_table (MonoVTable
*vtable
, int offset
)
581 table
= mono_domain_alloc0 (vtable
->domain
, m_class_get_vtable_size (vtable
->klass
) * sizeof (gpointer
));
582 vtable
->interp_vtable
= table
;
584 table
= (gpointer
*)vtable
;
591 get_virtual_method_fast (InterpMethod
*imethod
, MonoVTable
*vtable
, int offset
)
595 #ifndef DISABLE_REMOTING
597 if (mono_class_is_transparent_proxy (vtable
->klass
))
598 return get_virtual_method (imethod
, vtable
);
601 table
= get_method_table (vtable
, offset
);
604 /* Lazily allocate method table */
605 mono_domain_lock (vtable
->domain
);
606 table
= get_method_table (vtable
, offset
);
608 table
= alloc_method_table (vtable
, offset
);
609 mono_domain_unlock (vtable
->domain
);
612 if (!table
[offset
]) {
613 InterpMethod
*target_imethod
= get_virtual_method (imethod
, vtable
);
614 /* Lazily initialize the method table slot */
615 mono_domain_lock (vtable
->domain
);
616 if (!table
[offset
]) {
617 if (imethod
->method
->is_inflated
|| offset
< 0)
618 table
[offset
] = append_imethod (vtable
->domain
, NULL
, imethod
, target_imethod
);
620 table
[offset
] = (gpointer
) ((gsize
)target_imethod
| 0x1);
622 mono_domain_unlock (vtable
->domain
);
625 if ((gsize
)table
[offset
] & 0x1) {
626 /* Non generic virtual call. Only one method in slot */
627 return (InterpMethod
*) ((gsize
)table
[offset
] & ~0x1);
629 /* Virtual generic or interface call. Multiple methods in slot */
630 InterpMethod
*target_imethod
= get_target_imethod ((GSList
*)table
[offset
], imethod
);
632 if (!target_imethod
) {
633 target_imethod
= get_virtual_method (imethod
, vtable
);
634 mono_domain_lock (vtable
->domain
);
635 if (!get_target_imethod ((GSList
*)table
[offset
], imethod
))
636 table
[offset
] = append_imethod (vtable
->domain
, (GSList
*)table
[offset
], imethod
, target_imethod
);
637 mono_domain_unlock (vtable
->domain
);
639 return target_imethod
;
644 stackval_from_data (MonoType
*type_
, stackval
*result
, void *data
, gboolean pinvoke
)
646 MonoType
*type
= mini_native_type_replace_type (type_
);
648 switch (type
->type
) {
649 case MONO_TYPE_OBJECT
:
650 case MONO_TYPE_CLASS
:
651 case MONO_TYPE_STRING
:
652 case MONO_TYPE_ARRAY
:
653 case MONO_TYPE_SZARRAY
:
658 result
->data
.p
= *(gpointer
*)data
;
661 switch (type
->type
) {
665 result
->data
.i
= *(gint8
*)data
;
668 case MONO_TYPE_BOOLEAN
:
669 result
->data
.i
= *(guint8
*)data
;
672 result
->data
.i
= *(gint16
*)data
;
676 result
->data
.i
= *(guint16
*)data
;
679 result
->data
.i
= *(gint32
*)data
;
683 result
->data
.nati
= *(mono_i
*)data
;
686 result
->data
.p
= *(gpointer
*)data
;
689 result
->data
.i
= *(guint32
*)data
;
692 /* memmove handles unaligned case */
693 memmove (&result
->data
.f_r4
, data
, sizeof (float));
697 memmove (&result
->data
.l
, data
, sizeof (gint64
));
700 memmove (&result
->data
.f
, data
, sizeof (double));
702 case MONO_TYPE_STRING
:
703 case MONO_TYPE_SZARRAY
:
704 case MONO_TYPE_CLASS
:
705 case MONO_TYPE_OBJECT
:
706 case MONO_TYPE_ARRAY
:
707 result
->data
.p
= *(gpointer
*)data
;
709 case MONO_TYPE_VALUETYPE
:
710 if (m_class_is_enumtype (type
->data
.klass
)) {
711 stackval_from_data (mono_class_enum_basetype_internal (type
->data
.klass
), result
, data
, pinvoke
);
713 } else if (pinvoke
) {
714 memcpy (result
->data
.vt
, data
, mono_class_native_size (type
->data
.klass
, NULL
));
716 mono_value_copy_internal (result
->data
.vt
, data
, type
->data
.klass
);
719 case MONO_TYPE_GENERICINST
: {
720 if (mono_type_generic_inst_is_valuetype (type
)) {
721 mono_value_copy_internal (result
->data
.vt
, data
, mono_class_from_mono_type_internal (type
));
724 stackval_from_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), result
, data
, pinvoke
);
728 g_error ("got type 0x%02x", type
->type
);
733 stackval_to_data (MonoType
*type_
, stackval
*val
, void *data
, gboolean pinvoke
)
735 MonoType
*type
= mini_native_type_replace_type (type_
);
737 gpointer
*p
= (gpointer
*)data
;
741 /* printf ("TODAT0 %p\n", data); */
742 switch (type
->type
) {
745 guint8
*p
= (guint8
*)data
;
749 case MONO_TYPE_BOOLEAN
: {
750 guint8
*p
= (guint8
*)data
;
751 *p
= (val
->data
.i
!= 0);
756 case MONO_TYPE_CHAR
: {
757 guint16
*p
= (guint16
*)data
;
762 mono_i
*p
= (mono_i
*)data
;
763 /* In theory the value used by stloc should match the local var type
764 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
765 a native int - both by csc and mcs). Not sure what to do about sign extension
766 as it is outside the spec... doing the obvious */
767 *p
= (mono_i
)val
->data
.nati
;
771 mono_u
*p
= (mono_u
*)data
;
773 *p
= (mono_u
)val
->data
.nati
;
778 gint32
*p
= (gint32
*)data
;
784 memmove (data
, &val
->data
.l
, sizeof (gint64
));
788 /* memmove handles unaligned case */
789 memmove (data
, &val
->data
.f_r4
, sizeof (float));
793 memmove (data
, &val
->data
.f
, sizeof (double));
796 case MONO_TYPE_STRING
:
797 case MONO_TYPE_SZARRAY
:
798 case MONO_TYPE_CLASS
:
799 case MONO_TYPE_OBJECT
:
800 case MONO_TYPE_ARRAY
: {
801 gpointer
*p
= (gpointer
*) data
;
802 mono_gc_wbarrier_generic_store_internal (p
, val
->data
.o
);
805 case MONO_TYPE_PTR
: {
806 gpointer
*p
= (gpointer
*) data
;
810 case MONO_TYPE_VALUETYPE
:
811 if (m_class_is_enumtype (type
->data
.klass
)) {
812 stackval_to_data (mono_class_enum_basetype_internal (type
->data
.klass
), val
, data
, pinvoke
);
814 } else if (pinvoke
) {
815 memcpy (data
, val
->data
.vt
, mono_class_native_size (type
->data
.klass
, NULL
));
817 mono_value_copy_internal (data
, val
->data
.vt
, type
->data
.klass
);
820 case MONO_TYPE_GENERICINST
: {
821 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
823 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
)) {
824 mono_value_copy_internal (data
, val
->data
.vt
, mono_class_from_mono_type_internal (type
));
827 stackval_to_data (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
, data
, pinvoke
);
831 g_error ("got type %x", type
->type
);
836 * Same as stackval_to_data but return address of storage instead
837 * of copying the value.
840 stackval_to_data_addr (MonoType
*type_
, stackval
*val
)
842 MonoType
*type
= mini_native_type_replace_type (type_
);
846 switch (type
->type
) {
849 case MONO_TYPE_BOOLEAN
:
858 return &val
->data
.nati
;
863 return &val
->data
.f_r4
;
866 case MONO_TYPE_STRING
:
867 case MONO_TYPE_SZARRAY
:
868 case MONO_TYPE_CLASS
:
869 case MONO_TYPE_OBJECT
:
870 case MONO_TYPE_ARRAY
:
873 case MONO_TYPE_VALUETYPE
:
874 if (m_class_is_enumtype (type
->data
.klass
))
875 return stackval_to_data_addr (mono_class_enum_basetype_internal (type
->data
.klass
), val
);
878 case MONO_TYPE_TYPEDBYREF
:
880 case MONO_TYPE_GENERICINST
: {
881 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
883 if (m_class_is_valuetype (container_class
) && !m_class_is_enumtype (container_class
))
885 return stackval_to_data_addr (m_class_get_byval_arg (type
->data
.generic_class
->container_class
), val
);
888 g_error ("got type %x", type
->type
);
894 * Throw an exception from the interpreter.
896 static MONO_NEVER_INLINE
void
897 interp_throw (ThreadContext
*context
, MonoException
*ex
, InterpFrame
*frame
, gconstpointer ip
, gboolean rethrow
)
902 interp_push_lmf (&ext
, frame
);
903 frame
->ip
= (const guint16
*)ip
;
906 if (mono_object_isinst_checked ((MonoObject
*) ex
, mono_defaults
.exception_class
, error
)) {
907 MonoException
*mono_ex
= (MonoException
*) ex
;
909 mono_ex
->stack_trace
= NULL
;
910 mono_ex
->trace_ips
= NULL
;
913 mono_error_assert_ok (error
);
916 memset (&ctx
, 0, sizeof (MonoContext
));
917 MONO_CONTEXT_SET_SP (&ctx
, frame
);
920 * Call the JIT EH code. The EH code will call back to us using:
921 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
922 * Since ctx.ip is 0, this will start unwinding from the LMF frame
923 * pushed above, which points to our frames.
925 mono_handle_exception (&ctx
, (MonoObject
*)ex
);
926 if (MONO_CONTEXT_GET_IP (&ctx
) != 0) {
927 /* We need to unwind into non-interpreter code */
928 mono_restore_context (&ctx
);
929 g_assert_not_reached ();
932 interp_pop_lmf (&ext
);
934 g_assert (context
->has_resume_state
);
937 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
939 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
940 CHECK_RESUME_STATE(context); \
943 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
945 #define THROW_EX_OVF(ip) THROW_EX (mono_get_exception_overflow (), ip)
947 #define THROW_EX_DIV_ZERO(ip) THROW_EX (mono_get_exception_divide_by_zero (), ip)
949 #define NULL_CHECK(o) do { \
950 if (G_UNLIKELY (!(o))) \
951 THROW_EX (mono_get_exception_null_reference (), ip); \
954 #define EXCEPTION_CHECKPOINT \
956 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
957 MonoException *exc = mono_thread_interruption_checkpoint (); \
959 THROW_EX (exc, ip); \
965 ves_array_create (MonoDomain
*domain
, MonoClass
*klass
, int param_count
, stackval
*values
, MonoError
*error
)
968 intptr_t *lower_bounds
;
971 lengths
= g_newa (uintptr_t, m_class_get_rank (klass
) * 2);
972 for (i
= 0; i
< param_count
; ++i
) {
973 lengths
[i
] = values
->data
.i
;
976 if (m_class_get_rank (klass
) == param_count
) {
977 /* Only lengths provided. */
980 /* lower bounds are first. */
981 lower_bounds
= (intptr_t *) lengths
;
982 lengths
+= m_class_get_rank (klass
);
984 return (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, error
);
988 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
990 g_assert (!frame
->ex
);
991 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
995 for (gint32 i
= 0; i
< m_class_get_rank (ac
); i
++) {
996 guint32 idx
= sp
[i
].data
.i
;
997 guint32 lower
= ao
->bounds
[i
].lower_bound
;
998 guint32 len
= ao
->bounds
[i
].length
;
999 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
1000 frame
->ex
= mono_get_exception_index_out_of_range ();
1003 pos
= (pos
* len
) + idx
- lower
;
1006 pos
= sp
[0].data
.i
;
1007 if (safe
&& pos
>= ao
->max_length
) {
1008 frame
->ex
= mono_get_exception_index_out_of_range ();
1015 static MONO_NEVER_INLINE
void
1016 ves_array_set (InterpFrame
*frame
, stackval
*sp
, MonoMethodSignature
*sig
)
1018 MonoObject
*o
= sp
->data
.o
;
1019 MonoArray
*ao
= (MonoArray
*) o
;
1020 MonoClass
*ac
= o
->vtable
->klass
;
1022 g_assert (m_class_get_rank (ac
) >= 1);
1024 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, TRUE
);
1028 int val_index
= 1 + m_class_get_rank (ac
);
1029 if (sp
[val_index
].data
.p
&& !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o
)))) {
1031 MonoObject
*isinst
= mono_object_isinst_checked (sp
[val_index
].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
1032 mono_error_cleanup (error
);
1034 frame
->ex
= mono_get_exception_array_type_mismatch ();
1039 gint32 esize
= mono_array_element_size (ac
);
1040 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1042 MonoType
*mt
= sig
->params
[m_class_get_rank (ac
)];
1043 stackval_to_data (mt
, &sp
[val_index
], ea
, FALSE
);
1047 ves_array_get (InterpFrame
*frame
, stackval
*sp
, stackval
*retval
, MonoMethodSignature
*sig
, gboolean safe
)
1049 MonoObject
*o
= sp
->data
.o
;
1050 MonoArray
*ao
= (MonoArray
*) o
;
1051 MonoClass
*ac
= o
->vtable
->klass
;
1053 g_assert (m_class_get_rank (ac
) >= 1);
1055 gint32 pos
= ves_array_calculate_index (ao
, sp
+ 1, frame
, safe
);
1059 gint32 esize
= mono_array_element_size (ac
);
1060 gpointer ea
= mono_array_addr_with_size_fast (ao
, esize
, pos
);
1062 MonoType
*mt
= sig
->ret
;
1063 stackval_from_data (mt
, retval
, ea
, FALSE
);
1067 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
1069 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
1071 g_assert (m_class_get_rank (ac
) >= 1);
1073 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
1077 if (needs_typecheck
&& !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject
*) ao
)), required_type
)) {
1078 frame
->ex
= mono_get_exception_array_type_mismatch ();
1081 gint32 esize
= mono_array_element_size (ac
);
1082 return mono_array_addr_with_size_fast (ao
, esize
, pos
);
1085 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1086 static MonoFuncV mono_native_to_interp_trampoline
= NULL
;
1089 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1090 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
1092 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
1095 g_assert (mono_arm_eabi_supported ());
1096 int i8_align
= mono_arm_i8_align ();
1106 for (int i
= 0; i
< sig
->param_count
; i
++) {
1107 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1109 case MONO_TYPE_BOOLEAN
:
1110 case MONO_TYPE_CHAR
:
1120 case MONO_TYPE_SZARRAY
:
1121 case MONO_TYPE_CLASS
:
1122 case MONO_TYPE_OBJECT
:
1123 case MONO_TYPE_STRING
:
1124 case MONO_TYPE_VALUETYPE
:
1125 case MONO_TYPE_GENERICINST
:
1126 #if SIZEOF_VOID_P == 8
1132 #if SIZEOF_VOID_P == 4
1136 /* pairs begin at even registers */
1137 if (i8_align
== 8 && margs
->ilen
& 1)
1144 #if SIZEOF_VOID_P == 8
1149 #if SIZEOF_VOID_P == 4
1155 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
1159 if (margs
->ilen
> 0)
1160 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
1162 if (margs
->flen
> 0)
1163 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
1165 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
1166 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
1168 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
1169 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
1176 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
1180 for (int i
= 0; i
< sig
->param_count
; i
++) {
1181 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
1183 case MONO_TYPE_BOOLEAN
:
1184 case MONO_TYPE_CHAR
:
1194 case MONO_TYPE_SZARRAY
:
1195 case MONO_TYPE_CLASS
:
1196 case MONO_TYPE_OBJECT
:
1197 case MONO_TYPE_STRING
:
1198 case MONO_TYPE_VALUETYPE
:
1199 case MONO_TYPE_GENERICINST
:
1200 #if SIZEOF_VOID_P == 8
1204 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
1206 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
1210 #if SIZEOF_VOID_P == 4
1212 case MONO_TYPE_U8
: {
1213 stackval
*sarg
= &frame
->stack_args
[i
];
1215 /* pairs begin at even registers */
1216 if (i8_align
== 8 && int_i
& 1)
1219 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
1221 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
1223 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
);
1231 if (ptype
== MONO_TYPE_R4
)
1232 * (float *) &(margs
->fargs
[int_f
]) = frame
->stack_args
[i
].data
.f_r4
;
1234 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
1236 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
);
1238 #if SIZEOF_VOID_P == 4
1245 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
1249 switch (sig
->ret
->type
) {
1250 case MONO_TYPE_BOOLEAN
:
1251 case MONO_TYPE_CHAR
:
1261 case MONO_TYPE_SZARRAY
:
1262 case MONO_TYPE_CLASS
:
1263 case MONO_TYPE_OBJECT
:
1264 case MONO_TYPE_STRING
:
1267 case MONO_TYPE_VALUETYPE
:
1268 case MONO_TYPE_GENERICINST
:
1269 margs
->retval
= &(frame
->retval
->data
.p
);
1270 margs
->is_float_ret
= 0;
1274 margs
->retval
= &(frame
->retval
->data
.p
);
1275 margs
->is_float_ret
= 1;
1277 case MONO_TYPE_VOID
:
1278 margs
->retval
= NULL
;
1281 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
1289 interp_frame_arg_to_data (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1291 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1294 stackval_to_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1296 stackval_to_data (sig
->params
[index
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1300 interp_data_to_frame_arg (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer data
)
1302 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1305 stackval_from_data (sig
->ret
, iframe
->retval
, data
, sig
->pinvoke
);
1306 else if (sig
->hasthis
&& index
== 0)
1307 iframe
->stack_args
[index
].data
.p
= *(gpointer
*)data
;
1309 stackval_from_data (sig
->params
[index
- sig
->hasthis
], &iframe
->stack_args
[index
], data
, sig
->pinvoke
);
1313 interp_frame_arg_to_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
)
1315 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1318 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
1320 return stackval_to_data_addr (sig
->params
[index
], &iframe
->stack_args
[index
]);
1324 interp_frame_arg_set_storage (MonoInterpFrameHandle frame
, MonoMethodSignature
*sig
, int index
, gpointer storage
)
1326 InterpFrame
*iframe
= (InterpFrame
*)frame
;
1327 stackval
*val
= (index
== -1) ? iframe
->retval
: &iframe
->stack_args
[index
];
1328 MonoType
*type
= (index
== -1) ? sig
->ret
: sig
->params
[index
];
1330 switch (type
->type
) {
1331 case MONO_TYPE_GENERICINST
:
1332 if (!MONO_TYPE_IS_REFERENCE (type
))
1333 val
->data
.vt
= storage
;
1335 case MONO_TYPE_VALUETYPE
:
1336 val
->data
.vt
= storage
;
1339 g_assert_not_reached ();
1344 get_interp_to_native_trampoline (void)
1346 static MonoPIFunc trampoline
= NULL
;
1349 if (mono_ee_features
.use_aot_trampolines
) {
1350 trampoline
= (MonoPIFunc
) mono_aot_get_trampoline ("interp_to_native_trampoline");
1352 MonoTrampInfo
*info
;
1353 trampoline
= (MonoPIFunc
) mono_arch_get_interp_to_native_trampoline (&info
);
1354 mono_tramp_info_register (info
, NULL
);
1356 mono_memory_barrier ();
1362 interp_to_native_trampoline (gpointer addr
, gpointer ccontext
)
1364 get_interp_to_native_trampoline () (addr
, ccontext
);
1367 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1369 #pragma optimize ("", off)
1371 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE
void
1372 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
, gboolean save_last_error
)
1379 g_assert (!frame
->imethod
);
1381 static MonoPIFunc entry_func
= NULL
;
1383 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1385 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
);
1386 mono_error_assert_ok (error
);
1388 entry_func
= get_interp_to_native_trampoline ();
1390 mono_memory_barrier ();
1393 #ifdef ENABLE_NETCORE
1394 if (save_last_error
) {
1395 mono_marshal_clear_last_error ();
1399 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1400 CallContext ccontext
;
1401 mono_arch_set_native_call_context_args (&ccontext
, frame
, sig
);
1404 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1408 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_pinvoke
);
1409 entry_func ((gpointer
) addr
, args
);
1410 if (save_last_error
)
1411 mono_marshal_set_last_error ();
1412 interp_pop_lmf (&ext
);
1414 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1416 mono_arch_get_native_call_context_ret (&ccontext
, frame
, sig
);
1418 if (ccontext
.stack
!= NULL
)
1419 g_free (ccontext
.stack
);
1421 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1422 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1424 g_free (margs
->iargs
);
1425 g_free (margs
->fargs
);
1428 goto exit_pinvoke
; // prevent unused label warning in some configurations
1433 #pragma optimize ("", on)
1437 * interp_init_delegate:
1439 * Initialize del->interp_method.
1442 interp_init_delegate (MonoDelegate
*del
, MonoError
*error
)
1446 if (del
->interp_method
) {
1447 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1448 del
->method
= ((InterpMethod
*)del
->interp_method
)->method
;
1449 } else if (del
->method
) {
1450 /* Delegate created dynamically */
1451 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
1453 /* Created from JITted code */
1454 g_assert_not_reached ();
1457 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1460 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1461 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1462 mono_class_is_abstract (method
->klass
))
1463 del
->interp_method
= get_virtual_method ((InterpMethod
*)del
->interp_method
, del
->target
->vtable
);
1465 method
= ((InterpMethod
*)del
->interp_method
)->method
;
1466 if (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1467 const char *name
= method
->name
;
1468 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1470 * When invoking the delegate interp_method is executed directly. If it's an
1471 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1473 * FIXME We should do this later, when we also know the delegate on which the
1474 * target method is called.
1476 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (method
, NULL
), error
);
1477 mono_error_assert_ok (error
);
1481 if (!((InterpMethod
*) del
->interp_method
)->transformed
&& method_is_dynamic (method
)) {
1482 /* Return any errors from method compilation */
1483 mono_interp_transform_method ((InterpMethod
*) del
->interp_method
, get_context (), error
);
1484 return_if_nok (error
);
1489 interp_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
1492 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1494 InterpMethod
*imethod
= (InterpMethod
*)addr
;
1496 if (!(imethod
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1497 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (mono_handle_class (this_obj
));
1498 /* virtual invoke delegates must not have null check */
1499 if (mono_method_signature_internal (imethod
->method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
1500 && MONO_HANDLE_IS_NULL (target
)) {
1501 mono_error_set_argument (error
, "this", "Delegate to an instance method cannot have null 'this'");
1506 g_assert (imethod
->method
);
1507 gpointer entry
= mini_get_interp_callbacks ()->create_method_pointer (imethod
->method
, FALSE
, error
);
1508 return_if_nok (error
);
1510 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate
, this_obj
), interp_method
, gpointer
, imethod
);
1512 mono_delegate_ctor (this_obj
, target
, entry
, error
);
1517 * runtime specifies that the implementation of the method is automatically
1518 * provided by the runtime and is primarily used for the methods of delegates.
1520 static MONO_NEVER_INLINE
void
1521 ves_imethod (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodSignature
*sig
, stackval
*sp
, stackval
*retval
)
1523 const char *name
= method
->name
;
1524 mono_class_init_internal (method
->klass
);
1526 if (method
->klass
== mono_defaults
.array_class
) {
1527 if (!strcmp (name
, "UnsafeMov")) {
1528 /* TODO: layout checks */
1529 stackval_from_data (sig
->ret
, retval
, (char*) sp
, FALSE
);
1532 if (!strcmp (name
, "UnsafeLoad")) {
1533 ves_array_get (frame
, sp
, retval
, sig
, FALSE
);
1536 } else if (mini_class_is_system_array (method
->klass
)) {
1537 MonoObject
*obj
= (MonoObject
*) sp
->data
.p
;
1539 frame
->ex
= mono_get_exception_null_reference ();
1542 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1543 ves_array_set (frame
, sp
, sig
);
1546 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1547 ves_array_get (frame
, sp
, retval
, sig
, TRUE
);
1552 g_error ("Don't know how to exec runtime method %s.%s::%s",
1553 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
),
1559 dump_stack (stackval
*stack
, stackval
*sp
)
1561 stackval
*s
= stack
;
1562 GString
*str
= g_string_new ("");
1565 return g_string_free (str
, FALSE
);
1568 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1571 return g_string_free (str
, FALSE
);
1575 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1577 switch (type
->type
) {
1584 case MONO_TYPE_CHAR
:
1585 case MONO_TYPE_BOOLEAN
:
1586 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1588 case MONO_TYPE_STRING
:
1589 case MONO_TYPE_SZARRAY
:
1590 case MONO_TYPE_CLASS
:
1591 case MONO_TYPE_OBJECT
:
1592 case MONO_TYPE_ARRAY
:
1596 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1598 case MONO_TYPE_VALUETYPE
:
1599 if (m_class_is_enumtype (type
->data
.klass
))
1600 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1602 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1605 g_string_append_printf (str
, "[%g] ", s
->data
.f_r4
);
1608 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1613 GString
*res
= g_string_new ("");
1614 mono_type_get_desc (res
, type
, TRUE
);
1615 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1616 g_string_free (res
, TRUE
);
1623 dump_retval (InterpFrame
*inv
)
1625 GString
*str
= g_string_new ("");
1626 MonoType
*ret
= mono_method_signature_internal (inv
->imethod
->method
)->ret
;
1628 if (ret
->type
!= MONO_TYPE_VOID
)
1629 dump_stackval (str
, inv
->retval
, ret
);
1631 return g_string_free (str
, FALSE
);
1635 dump_args (InterpFrame
*inv
)
1637 GString
*str
= g_string_new ("");
1639 MonoMethodSignature
*signature
= mono_method_signature_internal (inv
->imethod
->method
);
1641 if (signature
->param_count
== 0 && !signature
->hasthis
)
1642 return g_string_free (str
, FALSE
);
1644 if (signature
->hasthis
) {
1645 MonoMethod
*method
= inv
->imethod
->method
;
1646 dump_stackval (str
, inv
->stack_args
, m_class_get_byval_arg (method
->klass
));
1649 for (i
= 0; i
< signature
->param_count
; ++i
)
1650 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1652 return g_string_free (str
, FALSE
);
1656 #define CHECK_ADD_OVERFLOW(a,b) \
1657 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1658 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1660 #define CHECK_SUB_OVERFLOW(a,b) \
1661 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1662 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1664 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1665 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1667 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1668 (guint32)(a) < (guint32)(b) ? -1 : 0
1670 #define CHECK_ADD_OVERFLOW64(a,b) \
1671 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1672 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1674 #define CHECK_SUB_OVERFLOW64(a,b) \
1675 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1676 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1678 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1679 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1681 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1682 (guint64)(a) < (guint64)(b) ? -1 : 0
1684 #if SIZEOF_VOID_P == 4
1685 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1686 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1688 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1689 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1692 /* Resolves to TRUE if the operands would overflow */
1693 #define CHECK_MUL_OVERFLOW(a,b) \
1694 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1695 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1696 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1697 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1698 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1699 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1700 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1702 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1703 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1704 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1706 #define CHECK_MUL_OVERFLOW64(a,b) \
1707 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1708 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1709 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1710 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1711 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1712 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1713 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1715 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1716 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1717 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1719 #if SIZEOF_VOID_P == 4
1720 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1721 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1723 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1724 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1728 interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1731 ThreadContext
*context
= get_context ();
1732 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1733 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
1735 MonoMethod
*target_method
= method
;
1743 MonoDomain
*domain
= mono_domain_get ();
1745 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1746 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1747 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (target_method
, FALSE
, TRUE
);
1749 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1751 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1755 args
[0].data
.p
= obj
;
1757 args
[0].data
.p
= NULL
;
1758 args
[1].data
.p
= params
;
1759 args
[2].data
.p
= exc
;
1760 args
[3].data
.p
= target_method
;
1762 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, invoke_wrapper
, error
);
1763 mono_error_assert_ok (error
);
1764 init_frame (&frame
, NULL
, imethod
, args
, &result
);
1766 interp_exec_method (&frame
, context
, error
);
1770 *exc
= (MonoObject
*) frame
.ex
;
1773 mono_error_set_exception_instance (error
, frame
.ex
);
1776 return (MonoObject
*)result
.data
.p
;
1780 InterpMethod
*rmethod
;
1784 gpointer
*many_args
;
1787 /* Main function for entering the interpreter from compiled code */
1789 interp_entry (InterpEntryData
*data
)
1792 InterpMethod
*rmethod
;
1793 ThreadContext
*context
;
1797 MonoMethodSignature
*sig
;
1799 gpointer orig_domain
= NULL
, attach_cookie
;
1802 if ((gsize
)data
->rmethod
& 1) {
1804 data
->this_arg
= mono_object_unbox_internal ((MonoObject
*)data
->this_arg
);
1805 data
->rmethod
= (InterpMethod
*)(gpointer
)((gsize
)data
->rmethod
& ~1);
1807 rmethod
= data
->rmethod
;
1809 if (rmethod
->needs_thread_attach
)
1810 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
1812 context
= get_context ();
1814 method
= rmethod
->method
;
1815 sig
= mono_method_signature_internal (method
);
1817 // FIXME: Optimize this
1819 //printf ("%s\n", mono_method_full_name (method, 1));
1823 args
= g_newa (stackval
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1825 args
[0].data
.p
= data
->this_arg
;
1828 if (data
->many_args
)
1829 params
= data
->many_args
;
1831 params
= data
->args
;
1832 for (i
= 0; i
< sig
->param_count
; ++i
) {
1833 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1834 if (sig
->params
[i
]->byref
) {
1835 args
[a_index
].data
.p
= params
[i
];
1838 type
= rmethod
->param_types
[i
];
1839 switch (type
->type
) {
1840 case MONO_TYPE_VALUETYPE
:
1841 args
[a_index
].data
.p
= params
[i
];
1843 case MONO_TYPE_GENERICINST
:
1844 if (MONO_TYPE_IS_REFERENCE (type
))
1845 args
[a_index
].data
.p
= *(gpointer
*)params
[i
];
1847 args
[a_index
].data
.vt
= params
[i
];
1850 stackval_from_data (type
, &args
[a_index
], params
[i
], FALSE
);
1855 memset (&result
, 0, sizeof (result
));
1856 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1858 type
= rmethod
->rtype
;
1859 switch (type
->type
) {
1860 case MONO_TYPE_GENERICINST
:
1861 if (!MONO_TYPE_IS_REFERENCE (type
))
1862 frame
.retval
->data
.vt
= data
->res
;
1864 case MONO_TYPE_VALUETYPE
:
1865 frame
.retval
->data
.vt
= data
->res
;
1872 interp_exec_method (&frame
, context
, error
);
1874 if (rmethod
->needs_thread_attach
)
1875 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
1877 if (mono_llvm_only
) {
1879 mono_llvm_reraise_exception (frame
.ex
);
1881 g_assert (frame
.ex
== NULL
);
1884 type
= rmethod
->rtype
;
1885 switch (type
->type
) {
1886 case MONO_TYPE_VOID
:
1888 case MONO_TYPE_OBJECT
:
1889 /* No need for a write barrier */
1890 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1892 case MONO_TYPE_GENERICINST
:
1893 if (MONO_TYPE_IS_REFERENCE (type
)) {
1894 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1896 /* Already set before the call */
1899 case MONO_TYPE_VALUETYPE
:
1900 /* Already set before the call */
1903 stackval_to_data (type
, frame
.retval
, data
->res
, FALSE
);
1909 do_icall (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
1911 #ifdef ENABLE_NETCORE
1912 if (save_last_error
)
1913 mono_marshal_clear_last_error ();
1917 case MINT_ICALL_V_V
: {
1918 typedef void (*T
)(void);
1923 case MINT_ICALL_V_P
: {
1924 typedef gpointer (*T
)(void);
1927 sp
[-1].data
.p
= func ();
1930 case MINT_ICALL_P_V
: {
1931 typedef void (*T
)(gpointer
);
1933 func (sp
[-1].data
.p
);
1937 case MINT_ICALL_P_P
: {
1938 typedef gpointer (*T
)(gpointer
);
1940 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1943 case MINT_ICALL_PP_V
: {
1944 typedef void (*T
)(gpointer
,gpointer
);
1947 func (sp
[0].data
.p
, sp
[1].data
.p
);
1950 case MINT_ICALL_PP_P
: {
1951 typedef gpointer (*T
)(gpointer
,gpointer
);
1954 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1957 case MINT_ICALL_PPP_V
: {
1958 typedef void (*T
)(gpointer
,gpointer
,gpointer
);
1961 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1964 case MINT_ICALL_PPP_P
: {
1965 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
);
1968 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
);
1971 case MINT_ICALL_PPPP_V
: {
1972 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1975 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
);
1978 case MINT_ICALL_PPPP_P
: {
1979 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
);
1982 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1985 case MINT_ICALL_PPPPP_V
: {
1986 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1989 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
, sp
[3].data
.p
, sp
[4].data
.p
);
1992 case MINT_ICALL_PPPPP_P
: {
1993 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
1996 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
);
1999 case MINT_ICALL_PPPPPP_V
: {
2000 typedef void (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2003 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
);
2006 case MINT_ICALL_PPPPPP_P
: {
2007 typedef gpointer (*T
)(gpointer
,gpointer
,gpointer
,gpointer
,gpointer
,gpointer
);
2010 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
);
2014 g_assert_not_reached ();
2017 if (save_last_error
)
2018 mono_marshal_set_last_error ();
2020 /* convert the native representation to the stackval representation */
2022 stackval_from_data (sig
->ret
, &sp
[-1], (char*) &sp
[-1].data
.p
, sig
->pinvoke
);
2027 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2029 #pragma optimize ("", off)
2031 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval
*
2032 do_icall_wrapper (InterpFrame
*frame
, MonoMethodSignature
*sig
, int op
, stackval
*sp
, gpointer ptr
, gboolean save_last_error
)
2035 INTERP_PUSH_LMF_WITH_CTX (frame
, ext
, exit_icall
);
2037 sp
= do_icall (frame
, sig
, op
, sp
, ptr
, save_last_error
);
2039 interp_pop_lmf (&ext
);
2041 goto exit_icall
; // prevent unused label warning in some configurations
2046 #pragma optimize ("", on)
2051 gpointer jit_wrapper
;
2053 MonoFtnDesc
*ftndesc
;
2057 jit_call_cb (gpointer arg
)
2059 JitCallCbData
*cb_data
= (JitCallCbData
*)arg
;
2060 gpointer jit_wrapper
= cb_data
->jit_wrapper
;
2061 int pindex
= cb_data
->pindex
;
2062 gpointer
*args
= cb_data
->args
;
2063 MonoFtnDesc ftndesc
= *cb_data
->ftndesc
;
2067 typedef void (*T
)(gpointer
);
2068 T func
= (T
)jit_wrapper
;
2074 typedef void (*T
)(gpointer
, gpointer
);
2075 T func
= (T
)jit_wrapper
;
2077 func (args
[0], &ftndesc
);
2081 typedef void (*T
)(gpointer
, gpointer
, gpointer
);
2082 T func
= (T
)jit_wrapper
;
2084 func (args
[0], args
[1], &ftndesc
);
2088 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
);
2089 T func
= (T
)jit_wrapper
;
2091 func (args
[0], args
[1], args
[2], &ftndesc
);
2095 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2096 T func
= (T
)jit_wrapper
;
2098 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2102 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2103 T func
= (T
)jit_wrapper
;
2105 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2109 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2110 T func
= (T
)jit_wrapper
;
2112 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2116 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2117 T func
= (T
)jit_wrapper
;
2119 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2123 typedef void (*T
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
);
2124 T func
= (T
)jit_wrapper
;
2126 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], args
[7], &ftndesc
);
2130 g_assert_not_reached ();
2135 static MONO_NEVER_INLINE stackval
*
2136 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
, MonoError
*error
)
2138 MonoMethodSignature
*sig
;
2139 MonoFtnDesc ftndesc
;
2140 guint8 res_buf
[256];
2144 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2147 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2148 * by ref and return a return value using an explicit return value argument.
2150 if (!rmethod
->jit_wrapper
) {
2151 MonoMethod
*method
= rmethod
->method
;
2153 sig
= mono_method_signature_internal (method
);
2156 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2157 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2159 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2160 mono_error_assert_ok (error
);
2162 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
2163 return_val_if_nok (error
, NULL
);
2166 rmethod
->jit_addr
= addr
;
2167 rmethod
->jit_sig
= sig
;
2168 mono_memory_barrier ();
2169 rmethod
->jit_wrapper
= jit_wrapper
;
2172 sig
= rmethod
->jit_sig
;
2175 sp
-= sig
->param_count
;
2179 ftndesc
.addr
= rmethod
->jit_addr
;
2182 // FIXME: Optimize this
2186 int stack_index
= 0;
2187 if (rmethod
->hasthis
) {
2188 args
[pindex
++] = sp
[0].data
.p
;
2191 type
= rmethod
->rtype
;
2192 if (type
->type
!= MONO_TYPE_VOID
) {
2193 if (MONO_TYPE_ISSTRUCT (type
))
2194 args
[pindex
++] = vt_sp
;
2196 args
[pindex
++] = res_buf
;
2198 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2199 MonoType
*t
= rmethod
->param_types
[i
];
2200 stackval
*sval
= &sp
[stack_index
+ i
];
2201 if (sig
->params
[i
]->byref
) {
2202 args
[pindex
++] = sval
->data
.p
;
2203 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2204 args
[pindex
++] = sval
->data
.p
;
2205 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2206 args
[pindex
++] = &sval
->data
.p
;
2215 case MONO_TYPE_VALUETYPE
:
2216 args
[pindex
++] = &sval
->data
.i
;
2219 case MONO_TYPE_FNPTR
:
2222 case MONO_TYPE_OBJECT
:
2223 args
[pindex
++] = &sval
->data
.p
;
2227 args
[pindex
++] = &sval
->data
.l
;
2230 args
[pindex
++] = &sval
->data
.f_r4
;
2233 args
[pindex
++] = &sval
->data
.f
;
2236 printf ("%s\n", mono_type_full_name (t
));
2237 g_assert_not_reached ();
2242 interp_push_lmf (&ext
, frame
);
2244 JitCallCbData cb_data
;
2245 memset (&cb_data
, 0, sizeof (cb_data
));
2246 cb_data
.jit_wrapper
= rmethod
->jit_wrapper
;
2247 cb_data
.pindex
= pindex
;
2248 cb_data
.args
= args
;
2249 cb_data
.ftndesc
= &ftndesc
;
2251 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2252 /* Catch the exception thrown by the native code using a try-catch */
2253 gboolean thrown
= FALSE
;
2254 mono_llvm_cpp_catch_exception (jit_call_cb
, &cb_data
, &thrown
);
2255 interp_pop_lmf (&ext
);
2257 MonoObject
*obj
= mono_llvm_load_exception ();
2259 mono_error_set_exception_instance (error
, (MonoException
*)obj
);
2263 jit_call_cb (&cb_data
);
2264 interp_pop_lmf (&ext
);
2267 MonoType
*rtype
= rmethod
->rtype
;
2268 switch (rtype
->type
) {
2269 case MONO_TYPE_VOID
:
2270 case MONO_TYPE_OBJECT
:
2271 case MONO_TYPE_STRING
:
2272 case MONO_TYPE_CLASS
:
2273 case MONO_TYPE_ARRAY
:
2274 case MONO_TYPE_SZARRAY
:
2278 sp
->data
.p
= *(gpointer
*)res_buf
;
2281 sp
->data
.i
= *(gint8
*)res_buf
;
2284 sp
->data
.i
= *(guint8
*)res_buf
;
2287 sp
->data
.i
= *(gint16
*)res_buf
;
2290 sp
->data
.i
= *(guint16
*)res_buf
;
2293 sp
->data
.i
= *(gint32
*)res_buf
;
2296 sp
->data
.i
= *(guint32
*)res_buf
;
2299 sp
->data
.l
= *(gint64
*)res_buf
;
2302 sp
->data
.l
= *(guint64
*)res_buf
;
2305 sp
->data
.f_r4
= *(float*)res_buf
;
2308 sp
->data
.f
= *(double*)res_buf
;
2310 case MONO_TYPE_TYPEDBYREF
:
2311 case MONO_TYPE_VALUETYPE
:
2312 /* The result was written to vt_sp */
2315 case MONO_TYPE_GENERICINST
:
2316 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2317 sp
->data
.p
= *(gpointer
*)res_buf
;
2319 /* The result was written to vt_sp */
2324 g_print ("%s\n", mono_type_full_name (rtype
));
2325 g_assert_not_reached ();
2332 static MONO_NEVER_INLINE
void
2333 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
2336 interp_push_lmf (&ext
, frame
);
2338 interp_pop_lmf (&ext
);
2341 static MONO_NEVER_INLINE
void
2342 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
2345 /* Don't push lmf if we have no interp data */
2346 gboolean push_lmf
= frame
->parent
!= NULL
;
2349 /* Use the parent frame as the current frame is not complete yet */
2351 interp_push_lmf (&ext
, frame
->parent
);
2353 mono_interp_transform_method (frame
->imethod
, context
, error
);
2354 frame
->ex
= mono_error_convert_to_exception (error
);
2357 interp_pop_lmf (&ext
);
2360 static MONO_NEVER_INLINE
void
2361 copy_varargs_vtstack (MonoMethodSignature
*csig
, stackval
*sp
, unsigned char **vt_sp
)
2363 char *vt
= *(char**)vt_sp
;
2364 stackval
*first_arg
= sp
- csig
->param_count
;
2367 * We need to have the varargs linearly on the stack so the ArgIterator
2368 * can iterate over them. We pass the signature first and then copy them
2369 * one by one on the vtstack.
2371 *(gpointer
*)vt
= csig
;
2372 vt
+= sizeof (gpointer
);
2374 for (int i
= csig
->sentinelpos
; i
< csig
->param_count
; i
++) {
2375 int align
, arg_size
;
2376 arg_size
= mono_type_stack_size (csig
->params
[i
], &align
);
2377 vt
= (char*)ALIGN_PTR_TO (vt
, align
);
2379 stackval_to_data (csig
->params
[i
], &first_arg
[i
], vt
, FALSE
);
2383 vt
= (char*)ALIGN_PTR_TO (vt
, MINT_VT_ALIGNMENT
);
2385 *(char**)vt_sp
= vt
;
2389 * These functions are the entry points into the interpreter from compiled code.
2390 * They are called by the interp_in wrappers. They have the following signature:
2391 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2392 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2393 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2394 * more wrappers then these functions.
2395 * this/static * ret/void * 16 arguments -> 64 functions.
2398 #define MAX_INTERP_ENTRY_ARGS 8
2400 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2401 InterpEntryData data; \
2402 (data).rmethod = (_method); \
2403 (data).res = (_res); \
2404 (data).this_arg = (_this_arg); \
2405 (data).many_args = NULL;
2407 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2408 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2409 interp_entry (&data); \
2411 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2412 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2413 (data).args [0] = arg1; \
2414 interp_entry (&data); \
2416 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2417 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2418 (data).args [0] = arg1; \
2419 (data).args [1] = arg2; \
2420 interp_entry (&data); \
2422 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2423 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2424 (data).args [0] = arg1; \
2425 (data).args [1] = arg2; \
2426 (data).args [2] = arg3; \
2427 interp_entry (&data); \
2429 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2430 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2431 (data).args [0] = arg1; \
2432 (data).args [1] = arg2; \
2433 (data).args [2] = arg3; \
2434 (data).args [3] = arg4; \
2435 interp_entry (&data); \
2437 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2438 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2439 (data).args [0] = arg1; \
2440 (data).args [1] = arg2; \
2441 (data).args [2] = arg3; \
2442 (data).args [3] = arg4; \
2443 (data).args [4] = arg5; \
2444 interp_entry (&data); \
2446 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2447 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2448 (data).args [0] = arg1; \
2449 (data).args [1] = arg2; \
2450 (data).args [2] = arg3; \
2451 (data).args [3] = arg4; \
2452 (data).args [4] = arg5; \
2453 (data).args [5] = arg6; \
2454 interp_entry (&data); \
2456 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2457 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2458 (data).args [0] = arg1; \
2459 (data).args [1] = arg2; \
2460 (data).args [2] = arg3; \
2461 (data).args [3] = arg4; \
2462 (data).args [4] = arg5; \
2463 (data).args [5] = arg6; \
2464 (data).args [6] = arg7; \
2465 interp_entry (&data); \
2467 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2468 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2469 (data).args [0] = arg1; \
2470 (data).args [1] = arg2; \
2471 (data).args [2] = arg3; \
2472 (data).args [3] = arg4; \
2473 (data).args [4] = arg5; \
2474 (data).args [5] = arg6; \
2475 (data).args [6] = arg7; \
2476 (data).args [7] = arg8; \
2477 interp_entry (&data); \
2480 #define ARGLIST0 InterpMethod *rmethod
2481 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2482 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2483 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2484 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2485 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2486 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2487 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2488 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2490 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2491 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2492 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2493 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2494 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2495 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2496 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2497 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2498 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2499 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2500 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2501 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2502 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2503 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2504 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2505 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2506 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2507 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2508 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2509 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2510 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2511 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2512 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2513 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2514 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2515 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2516 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2517 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2518 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2519 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2520 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2521 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2522 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2523 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2524 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, res
, rmethod
)
2525 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, res
, rmethod
)
2527 #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
2529 static gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2530 static gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2531 static gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2532 static gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2534 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2536 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2538 INTERP_ENTRY_BASE ((InterpMethod
*)rmethod
, this_arg
, res
);
2539 data
.many_args
= args
;
2540 interp_entry (&data
);
2543 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2545 // inline so we can alloc on stack
2546 #define alloc_storage_for_stackval(s, t, p) do { \
2547 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2548 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2549 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2551 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2553 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2558 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2561 ThreadContext
*context
;
2565 MonoMethodSignature
*sig
;
2566 CallContext
*ccontext
= (CallContext
*) ccontext_untyped
;
2567 InterpMethod
*rmethod
= (InterpMethod
*) rmethod_untyped
;
2568 gpointer orig_domain
= NULL
, attach_cookie
;
2571 if (rmethod
->needs_thread_attach
)
2572 orig_domain
= mono_threads_attach_coop (mono_domain_get (), &attach_cookie
);
2574 context
= get_context ();
2576 method
= rmethod
->method
;
2577 sig
= mono_method_signature_internal (method
);
2581 args
= (stackval
*)alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
2583 init_frame (&frame
, NULL
, rmethod
, args
, &result
);
2585 /* Allocate storage for value types */
2586 for (i
= 0; i
< sig
->param_count
; i
++) {
2587 MonoType
*type
= sig
->params
[i
];
2588 alloc_storage_for_stackval (&frame
.stack_args
[i
+ sig
->hasthis
], type
, sig
->pinvoke
);
2591 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
2592 alloc_storage_for_stackval (frame
.retval
, sig
->ret
, sig
->pinvoke
);
2594 /* Copy the args saved in the trampoline to the frame stack */
2595 mono_arch_get_native_call_context_args (ccontext
, &frame
, sig
);
2598 interp_exec_method (&frame
, context
, error
);
2600 if (rmethod
->needs_thread_attach
)
2601 mono_threads_detach_coop (orig_domain
, &attach_cookie
);
2604 g_assert (frame
.ex
== NULL
);
2606 /* Write back the return value */
2607 mono_arch_set_native_call_context_ret (ccontext
, &frame
, sig
);
2613 interp_entry_from_trampoline (gpointer ccontext_untyped
, gpointer rmethod_untyped
)
2615 g_assert_not_reached ();
2618 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2620 static InterpMethod
*
2621 lookup_method_pointer (gpointer addr
)
2623 MonoDomain
*domain
= mono_domain_get ();
2624 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2625 InterpMethod
*res
= NULL
;
2627 mono_domain_lock (domain
);
2628 if (info
->interp_method_pointer_hash
)
2629 res
= (InterpMethod
*)g_hash_table_lookup (info
->interp_method_pointer_hash
, addr
);
2630 mono_domain_unlock (domain
);
2635 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2637 interp_no_native_to_managed (void)
2639 g_error ("interpreter: native-to-managed transition not available on this platform");
2644 no_llvmonly_interp_method_pointer (void)
2646 g_assert_not_reached ();
2650 * interp_create_method_pointer_llvmonly:
2652 * Return an ftndesc for entering the interpreter and executing METHOD.
2655 interp_create_method_pointer_llvmonly (MonoMethod
*method
, gboolean unbox
, MonoError
*error
)
2657 MonoDomain
*domain
= mono_domain_get ();
2658 gpointer addr
, entry_func
, entry_wrapper
;
2659 MonoMethodSignature
*sig
;
2660 MonoMethod
*wrapper
;
2661 MonoJitDomainInfo
*info
;
2662 InterpMethod
*imethod
;
2664 imethod
= mono_interp_get_imethod (domain
, method
, error
);
2665 return_val_if_nok (error
, NULL
);
2668 if (imethod
->llvmonly_unbox_entry
)
2669 return (MonoFtnDesc
*)imethod
->llvmonly_unbox_entry
;
2671 if (imethod
->jit_entry
)
2672 return (MonoFtnDesc
*)imethod
->jit_entry
;
2675 sig
= mono_method_signature_internal (method
);
2678 * The entry functions need access to the method to call, so we have
2679 * to use a ftndesc. The caller uses a normal signature, while the
2680 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2681 * a gsharedvt_in_sig wrapper.
2683 wrapper
= mini_get_gsharedvt_in_sig_wrapper (sig
);
2685 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2686 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2687 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2688 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2690 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2691 g_assert_not_reached ();
2692 //entry_func = (gpointer)interp_entry_general;
2693 } else if (sig
->hasthis
) {
2694 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2695 entry_func
= entry_funcs_instance
[sig
->param_count
];
2697 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2699 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2700 entry_func
= entry_funcs_static
[sig
->param_count
];
2702 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2704 g_assert (entry_func
);
2706 /* Encode unbox in the lower bit of imethod */
2707 gpointer entry_arg
= imethod
;
2709 entry_arg
= (gpointer
)(((gsize
)entry_arg
) | 1);
2710 MonoFtnDesc
*entry_ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func
, entry_arg
);
2712 addr
= mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper
, entry_ftndesc
);
2714 info
= domain_jit_info (domain
);
2715 mono_domain_lock (domain
);
2716 if (!info
->interp_method_pointer_hash
)
2717 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2718 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2719 mono_domain_unlock (domain
);
2721 mono_memory_barrier ();
2723 imethod
->llvmonly_unbox_entry
= addr
;
2725 imethod
->jit_entry
= addr
;
2727 return (MonoFtnDesc
*)addr
;
2731 * interp_create_method_pointer:
2733 * Return a function pointer which can be used to call METHOD using the
2734 * interpreter. Return NULL for methods which are not supported.
2737 interp_create_method_pointer (MonoMethod
*method
, gboolean compile
, MonoError
*error
)
2739 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2741 return (gpointer
)no_llvmonly_interp_method_pointer
;
2742 return (gpointer
)interp_no_native_to_managed
;
2744 gpointer addr
, entry_func
, entry_wrapper
= NULL
;
2745 MonoDomain
*domain
= mono_domain_get ();
2746 MonoJitDomainInfo
*info
;
2747 InterpMethod
*imethod
= mono_interp_get_imethod (domain
, method
, error
);
2750 return (gpointer
)no_llvmonly_interp_method_pointer
;
2752 if (imethod
->jit_entry
)
2753 return imethod
->jit_entry
;
2755 if (compile
&& !imethod
->transformed
) {
2756 /* Return any errors from method compilation */
2757 mono_interp_transform_method (imethod
, get_context (), error
);
2758 return_val_if_nok (error
, NULL
);
2761 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
2764 /* The caller should call interp_create_method_pointer_llvmonly */
2765 g_assert_not_reached ();
2767 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
2770 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2772 * Interp in wrappers get the argument in the rgctx register. If
2773 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2774 * on that arch the rgctx register is not scratch, so we use a
2775 * separate temp register. We should update the wrappers for this
2776 * if we really care about those architectures (arm).
2778 MonoMethod
*wrapper
= mini_get_interp_in_wrapper (sig
);
2780 entry_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2782 if (entry_wrapper
) {
2783 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2784 entry_func
= (gpointer
)interp_entry_general
;
2785 } else if (sig
->hasthis
) {
2786 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2787 entry_func
= entry_funcs_instance
[sig
->param_count
];
2789 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2791 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2792 entry_func
= entry_funcs_static
[sig
->param_count
];
2794 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2797 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2798 mono_error_assertf_ok (error
, "couldn't compile wrapper \"%s\" for \"%s\"",
2799 mono_method_get_name_full (wrapper
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
),
2800 mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
));
2802 mono_error_cleanup (error
);
2803 error_init_reuse (error
);
2804 if (!mono_native_to_interp_trampoline
) {
2805 if (mono_aot_only
) {
2806 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_aot_get_trampoline ("native_to_interp_trampoline");
2808 MonoTrampInfo
*info
;
2809 mono_native_to_interp_trampoline
= (MonoFuncV
)mono_arch_get_native_to_interp_trampoline (&info
);
2810 mono_tramp_info_register (info
, NULL
);
2813 entry_wrapper
= (gpointer
)mono_native_to_interp_trampoline
;
2814 /* We need the lmf wrapper only when being called from mixed mode */
2816 entry_func
= (gpointer
)interp_entry_from_trampoline
;
2818 static gpointer cached_func
= NULL
;
2820 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
);
2821 mono_memory_barrier ();
2823 entry_func
= cached_func
;
2828 g_assert (entry_func
);
2829 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2830 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2831 ftndesc
->addr
= entry_func
;
2832 ftndesc
->arg
= imethod
;
2833 mono_error_assert_ok (error
);
2836 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2837 * rgctx register using a trampoline.
2840 addr
= mono_create_ftnptr_arg_trampoline (ftndesc
, entry_wrapper
);
2842 info
= domain_jit_info (domain
);
2843 mono_domain_lock (domain
);
2844 if (!info
->interp_method_pointer_hash
)
2845 info
->interp_method_pointer_hash
= g_hash_table_new (NULL
, NULL
);
2846 g_hash_table_insert (info
->interp_method_pointer_hash
, addr
, imethod
);
2847 mono_domain_unlock (domain
);
2849 mono_memory_barrier ();
2850 imethod
->jit_entry
= addr
;
2857 static int opcode_counts
[512];
2859 #define COUNT_OP(op) opcode_counts[op]++
2861 #define COUNT_OP(op)
2865 #define DUMP_INSTR() \
2866 if (tracing > 1) { \
2868 if (sp > frame->stack) { \
2869 ins = dump_stack (frame->stack, sp); \
2871 ins = g_strdup (""); \
2875 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2876 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2877 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2883 #define DUMP_INSTR()
2886 #define INIT_VTABLE(vtable) do { \
2887 if (G_UNLIKELY (!(vtable)->initialized)) { \
2888 mono_runtime_class_init_full ((vtable), error); \
2889 if (!mono_error_ok (error)) \
2890 THROW_EX (mono_error_convert_to_exception (error), ip); \
2897 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2898 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2899 * should be followed:
2900 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2901 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2902 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
2903 * to be allocated to the C stack and not to registers.
2904 * - minimalize the number of MonoObject* locals/arguments.
2908 #define frame_objref(frame) (frame)->o
2910 #define frame_objref(frame) o
2914 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2915 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2916 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
2917 * to return error information.
2920 interp_exec_method_full (InterpFrame
*frame
, ThreadContext
*context
, FrameClauseArgs
*clause_args
, MonoError
*error
)
2922 InterpFrame child_frame
;
2923 const unsigned short *ip
= NULL
;
2925 InterpMethod
*imethod
= NULL
;
2927 gint tracing
= global_tracing
;
2928 unsigned char *vtalloc
;
2931 unsigned char *vt_sp
;
2932 unsigned char *locals
= NULL
;
2933 // See the comment about GC safety above
2934 MonoObject
*o
= NULL
;
2936 #if USE_COMPUTED_GOTO
2937 static void *in_labels
[] = {
2938 #define OPDEF(a,b,c,d) \
2940 #include "mintops.def"
2944 MonoMethodPInvoke
* piinfo
= NULL
;
2947 frame
->finally_ips
= NULL
;
2948 frame
->endfinally_ip
= NULL
;
2951 debug_enter (frame
, &tracing
);
2954 imethod
= frame
->imethod
;
2955 if (!imethod
->transformed
) {
2957 char *mn
= mono_method_full_name (imethod
->method
, TRUE
);
2958 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2963 do_transform_method (frame
, context
);
2965 THROW_EX (frame
->ex
, NULL
);
2966 EXCEPTION_CHECKPOINT
;
2970 frame
->args
= g_newa (char, imethod
->alloca_size
);
2973 ip
= clause_args
->start_with_ip
;
2974 if (clause_args
->base_frame
) {
2975 frame
->args
= g_newa (char, imethod
->alloca_size
);
2976 memcpy (frame
->args
, clause_args
->base_frame
->args
, imethod
->alloca_size
);
2979 sp
= frame
->stack
= (stackval
*) (char *) frame
->args
;
2980 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
2984 locals
= (unsigned char *) vt_sp
+ imethod
->vt_stack_size
;
2985 frame
->locals
= locals
;
2986 child_frame
.parent
= frame
;
2988 if (clause_args
&& clause_args
->filter_exception
) {
2989 sp
->data
.p
= clause_args
->filter_exception
;
2993 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2996 * using while (ip < end) may result in a 15% performance drop,
2997 * but it may be useful for debug
3000 #ifndef USE_COMPUTED_GOTO
3003 /* g_assert (sp >= frame->stack); */
3004 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
3006 MINT_IN_SWITCH (*ip
) {
3007 MINT_IN_CASE(MINT_INITLOCALS
)
3008 memset (locals
, 0, imethod
->locals_size
);
3011 MINT_IN_CASE(MINT_NOP
)
3014 MINT_IN_CASE(MINT_NIY
)
3015 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3017 MINT_IN_CASE(MINT_BREAK
)
3019 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break
, frame
);
3021 MINT_IN_CASE(MINT_BREAKPOINT
)
3025 MINT_IN_CASE(MINT_LDNULL
)
3030 MINT_IN_CASE(MINT_ARGLIST
)
3031 g_assert (frame
->varargs
);
3033 *(gpointer
*)sp
->data
.p
= frame
->varargs
;
3034 vt_sp
+= ALIGN_TO (sizeof (gpointer
), MINT_VT_ALIGNMENT
);
3038 MINT_IN_CASE(MINT_VTRESULT
) {
3039 int ret_size
= * (guint16
*)(ip
+ 1);
3040 unsigned char *ret_vt_sp
= vt_sp
;
3041 vt_sp
-= READ32(ip
+ 2);
3043 memmove (vt_sp
, ret_vt_sp
, ret_size
);
3044 sp
[-1].data
.p
= vt_sp
;
3045 vt_sp
+= ALIGN_TO (ret_size
, MINT_VT_ALIGNMENT
);
3050 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3051 MINT_IN_CASE(MINT_LDC_I4_M1
)
3054 MINT_IN_CASE(MINT_LDC_I4_0
)
3057 MINT_IN_CASE(MINT_LDC_I4_1
)
3060 MINT_IN_CASE(MINT_LDC_I4_2
)
3063 MINT_IN_CASE(MINT_LDC_I4_3
)
3066 MINT_IN_CASE(MINT_LDC_I4_4
)
3069 MINT_IN_CASE(MINT_LDC_I4_5
)
3072 MINT_IN_CASE(MINT_LDC_I4_6
)
3075 MINT_IN_CASE(MINT_LDC_I4_7
)
3078 MINT_IN_CASE(MINT_LDC_I4_8
)
3081 MINT_IN_CASE(MINT_LDC_I4_S
)
3082 sp
->data
.i
= *(const short *)(ip
+ 1);
3086 MINT_IN_CASE(MINT_LDC_I4
)
3088 sp
->data
.i
= READ32 (ip
);
3092 MINT_IN_CASE(MINT_LDC_I8
)
3094 sp
->data
.l
= READ64 (ip
);
3098 MINT_IN_CASE(MINT_LDC_I8_S
)
3099 sp
->data
.l
= *(const short *)(ip
+ 1);
3103 MINT_IN_CASE(MINT_LDC_R4
) {
3107 sp
->data
.f_r4
= * (float *)&val
;
3112 MINT_IN_CASE(MINT_LDC_R8
)
3113 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
3117 MINT_IN_CASE(MINT_DUP
)
3122 MINT_IN_CASE(MINT_DUP_VT
)
3123 i32
= READ32 (ip
+ 1);
3125 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
3126 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
3130 MINT_IN_CASE(MINT_POP
) {
3131 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
3133 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
3138 MINT_IN_CASE(MINT_JMP
) {
3139 InterpMethod
*new_method
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3140 gboolean realloc_frame
= new_method
->alloca_size
> imethod
->alloca_size
;
3142 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
3143 MONO_PROFILER_RAISE (method_tail_call
, (imethod
->method
, new_method
->method
));
3145 if (!new_method
->transformed
) {
3146 MONO_API_ERROR_INIT (error
);
3149 mono_interp_transform_method (new_method
, context
, error
);
3150 frame
->ex
= mono_error_convert_to_exception (error
);
3155 imethod
= frame
->imethod
= new_method
;
3157 * We allocate the stack frame from scratch and store the arguments in the
3158 * locals again since it's possible for the caller stack frame to be smaller
3159 * than the callee stack frame (at the interp level)
3161 if (realloc_frame
) {
3162 frame
->args
= g_newa (char, imethod
->alloca_size
);
3163 memset (frame
->args
, 0, imethod
->alloca_size
);
3164 sp
= frame
->stack
= (stackval
*) frame
->args
;
3166 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
3170 locals
= vt_sp
+ imethod
->vt_stack_size
;
3171 frame
->locals
= locals
;
3175 MINT_IN_CASE(MINT_CALLI
) {
3176 MonoMethodSignature
*csignature
;
3177 stackval
*endsp
= sp
;
3181 csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3185 child_frame
.imethod
= (InterpMethod
*)sp
->data
.p
;
3188 child_frame
.retval
= sp
;
3189 /* decrement by the actual number of args */
3190 sp
-= csignature
->param_count
;
3191 if (csignature
->hasthis
)
3193 child_frame
.stack_args
= sp
;
3195 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3196 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), error
);
3197 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3200 if (csignature
->hasthis
) {
3201 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3203 if (m_class_is_valuetype (this_arg
->vtable
->klass
)) {
3204 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3205 sp
[0].data
.p
= unboxed
;
3209 interp_exec_method (&child_frame
, context
, error
);
3211 CHECK_RESUME_STATE (context
);
3213 /* need to handle typedbyref ... */
3214 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3220 MINT_IN_CASE(MINT_CALLI_NAT_FAST
) {
3221 gpointer target_ip
= sp
[-1].data
.p
;
3222 MonoMethodSignature
*csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3223 int opcode
= *(guint16
*)(ip
+ 2);
3224 gboolean save_last_error
= *(guint16
*)(ip
+ 3);
3229 sp
= do_icall_wrapper (frame
, csignature
, opcode
, sp
, target_ip
, save_last_error
);
3230 EXCEPTION_CHECKPOINT
;
3231 CHECK_RESUME_STATE (context
);
3235 MINT_IN_CASE(MINT_CALLI_NAT
) {
3236 MonoMethodSignature
*csignature
;
3237 stackval
*endsp
= sp
;
3238 unsigned char *code
= NULL
;
3239 gboolean save_last_error
= FALSE
;
3243 csignature
= (MonoMethodSignature
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3244 save_last_error
= *(guint16
*)(ip
+ 2);
3248 code
= (guchar
*)sp
->data
.p
;
3249 child_frame
.imethod
= NULL
;
3252 child_frame
.retval
= sp
;
3253 /* decrement by the actual number of args */
3254 sp
-= csignature
->param_count
;
3255 if (csignature
->hasthis
)
3257 child_frame
.stack_args
= sp
;
3258 if (imethod
->method
->dynamic
&& csignature
->pinvoke
) {
3259 MonoMarshalSpec
**mspecs
;
3262 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3263 mspecs
= g_new0 (MonoMarshalSpec
*, csignature
->param_count
+ 1);
3265 piinfo
= piinfo
? piinfo
: g_newa (MonoMethodPInvoke
, 1);
3266 memset (piinfo
, 0, sizeof (*piinfo
));
3268 m
= mono_marshal_get_native_func_wrapper (m_class_get_image (imethod
->method
->klass
), csignature
, piinfo
, mspecs
, code
);
3270 for (int i
= csignature
->param_count
; i
>= 0; i
--)
3272 mono_metadata_free_marshal_spec (mspecs
[i
]);
3275 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, m
, error
);
3276 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
3278 interp_exec_method (&child_frame
, context
, error
);
3280 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
, save_last_error
);
3283 CHECK_RESUME_STATE (context
);
3285 /* need to handle typedbyref ... */
3286 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
3292 MINT_IN_CASE(MINT_CALLVIRT_FAST
)
3293 MINT_IN_CASE(MINT_VCALLVIRT_FAST
) {
3294 MonoObject
*this_arg
;
3295 MonoClass
*this_class
;
3296 gboolean is_void
= *ip
== MINT_VCALLVIRT_FAST
;
3297 InterpMethod
*target_imethod
;
3298 stackval
*endsp
= sp
;
3301 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3305 target_imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3306 slot
= *(gint16
*)(ip
+ 2);
3309 child_frame
.retval
= sp
;
3311 /* decrement by the actual number of args */
3312 sp
-= target_imethod
->param_count
+ target_imethod
->hasthis
;
3313 child_frame
.stack_args
= sp
;
3315 this_arg
= (MonoObject
*)sp
->data
.p
;
3316 this_class
= this_arg
->vtable
->klass
;
3318 child_frame
.imethod
= get_virtual_method_fast (target_imethod
, this_arg
->vtable
, slot
);
3319 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3321 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3322 sp
[0].data
.p
= unboxed
;
3325 interp_exec_method (&child_frame
, context
, error
);
3327 CHECK_RESUME_STATE (context
);
3330 /* need to handle typedbyref ... */
3336 MINT_IN_CASE(MINT_CALL_VARARG
) {
3337 stackval
*endsp
= sp
;
3338 int num_varargs
= 0;
3339 MonoMethodSignature
*csig
;
3343 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3344 /* The real signature for vararg calls */
3345 csig
= (MonoMethodSignature
*) imethod
->data_items
[* (guint16
*) (ip
+ 2)];
3346 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3347 num_varargs
= csig
->param_count
- csig
->sentinelpos
;
3348 child_frame
.varargs
= (char*) vt_sp
;
3349 copy_varargs_vtstack (csig
, sp
, &vt_sp
);
3353 child_frame
.retval
= sp
;
3355 /* decrement by the actual number of args */
3356 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
+ num_varargs
;
3357 child_frame
.stack_args
= sp
;
3359 interp_exec_method (&child_frame
, context
, error
);
3361 CHECK_RESUME_STATE (context
);
3363 if (csig
->ret
->type
!= MONO_TYPE_VOID
) {
3369 MINT_IN_CASE(MINT_CALL
)
3370 MINT_IN_CASE(MINT_VCALL
)
3371 MINT_IN_CASE(MINT_CALLVIRT
)
3372 MINT_IN_CASE(MINT_VCALLVIRT
) {
3373 gboolean is_void
= *ip
== MINT_VCALL
|| *ip
== MINT_VCALLVIRT
;
3374 gboolean is_virtual
= *ip
== MINT_CALLVIRT
|| *ip
== MINT_VCALLVIRT
;
3375 stackval
*endsp
= sp
;
3379 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3382 child_frame
.retval
= sp
;
3384 /* decrement by the actual number of args */
3385 sp
-= child_frame
.imethod
->param_count
+ child_frame
.imethod
->hasthis
;
3386 child_frame
.stack_args
= sp
;
3389 MonoObject
*this_arg
= (MonoObject
*)sp
->data
.p
;
3390 MonoClass
*this_class
= this_arg
->vtable
->klass
;
3392 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
->vtable
);
3393 if (m_class_is_valuetype (this_class
) && m_class_is_valuetype (child_frame
.imethod
->method
->klass
)) {
3395 gpointer unboxed
= mono_object_unbox_internal (this_arg
);
3396 sp
[0].data
.p
= unboxed
;
3400 interp_exec_method (&child_frame
, context
, error
);
3402 CHECK_RESUME_STATE (context
);
3405 /* need to handle typedbyref ... */
3411 MINT_IN_CASE(MINT_JIT_CALL
) {
3412 InterpMethod
*rmethod
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3413 MONO_API_ERROR_INIT (error
);
3415 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
, error
);
3416 if (!is_ok (error
)) {
3417 MonoException
*ex
= mono_error_convert_to_exception (error
);
3422 CHECK_RESUME_STATE (context
);
3424 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
3429 MINT_IN_CASE(MINT_CALLRUN
) {
3430 MonoMethod
*target_method
= (MonoMethod
*) imethod
->data_items
[* (guint16
*)(ip
+ 1)];
3431 MonoMethodSignature
*sig
= (MonoMethodSignature
*) imethod
->data_items
[* (guint16
*)(ip
+ 2)];
3437 sp
-= sig
->param_count
;
3441 ves_imethod (frame
, target_method
, sig
, sp
, retval
);
3443 THROW_EX (frame
->ex
, ip
);
3445 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3452 MINT_IN_CASE(MINT_RET
)
3454 *frame
->retval
= *sp
;
3455 if (sp
> frame
->stack
)
3456 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
3458 MINT_IN_CASE(MINT_RET_VOID
)
3459 if (sp
> frame
->stack
)
3460 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (imethod
->method
, TRUE
));
3462 MINT_IN_CASE(MINT_RET_VT
)
3463 i32
= READ32(ip
+ 1);
3465 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
3466 if (sp
> frame
->stack
)
3467 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
3469 MINT_IN_CASE(MINT_BR_S
)
3470 ip
+= (short) *(ip
+ 1);
3472 MINT_IN_CASE(MINT_BR
)
3473 ip
+= (gint32
) READ32(ip
+ 1);
3475 #define ZEROP_S(datamem, op) \
3477 if (sp->data.datamem op 0) \
3478 ip += * (gint16 *)(ip + 1); \
3482 #define ZEROP(datamem, op) \
3484 if (sp->data.datamem op 0) \
3485 ip += (gint32)READ32(ip + 1); \
3489 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
3492 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
3495 MINT_IN_CASE(MINT_BRFALSE_R4_S
)
3498 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
3501 MINT_IN_CASE(MINT_BRFALSE_I4
)
3504 MINT_IN_CASE(MINT_BRFALSE_I8
)
3507 MINT_IN_CASE(MINT_BRFALSE_R4
)
3510 MINT_IN_CASE(MINT_BRFALSE_R8
)
3513 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
3516 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
3519 MINT_IN_CASE(MINT_BRTRUE_R4_S
)
3522 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
3525 MINT_IN_CASE(MINT_BRTRUE_I4
)
3528 MINT_IN_CASE(MINT_BRTRUE_I8
)
3531 MINT_IN_CASE(MINT_BRTRUE_R4
)
3534 MINT_IN_CASE(MINT_BRTRUE_R8
)
3537 #define CONDBR_S(cond) \
3540 ip += * (gint16 *)(ip + 1); \
3543 #define BRELOP_S(datamem, op) \
3544 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3546 #define CONDBR(cond) \
3549 ip += (gint32)READ32(ip + 1); \
3553 #define BRELOP(datamem, op) \
3554 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3556 MINT_IN_CASE(MINT_BEQ_I4_S
)
3559 MINT_IN_CASE(MINT_BEQ_I8_S
)
3562 MINT_IN_CASE(MINT_BEQ_R4_S
)
3563 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3565 MINT_IN_CASE(MINT_BEQ_R8_S
)
3566 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3568 MINT_IN_CASE(MINT_BEQ_I4
)
3571 MINT_IN_CASE(MINT_BEQ_I8
)
3574 MINT_IN_CASE(MINT_BEQ_R4
)
3575 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
== sp
[1].data
.f_r4
)
3577 MINT_IN_CASE(MINT_BEQ_R8
)
3578 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
3580 MINT_IN_CASE(MINT_BGE_I4_S
)
3583 MINT_IN_CASE(MINT_BGE_I8_S
)
3586 MINT_IN_CASE(MINT_BGE_R4_S
)
3587 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3589 MINT_IN_CASE(MINT_BGE_R8_S
)
3590 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3592 MINT_IN_CASE(MINT_BGE_I4
)
3595 MINT_IN_CASE(MINT_BGE_I8
)
3598 MINT_IN_CASE(MINT_BGE_R4
)
3599 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3601 MINT_IN_CASE(MINT_BGE_R8
)
3602 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
3604 MINT_IN_CASE(MINT_BGT_I4_S
)
3607 MINT_IN_CASE(MINT_BGT_I8_S
)
3610 MINT_IN_CASE(MINT_BGT_R4_S
)
3611 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3613 MINT_IN_CASE(MINT_BGT_R8_S
)
3614 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3616 MINT_IN_CASE(MINT_BGT_I4
)
3619 MINT_IN_CASE(MINT_BGT_I8
)
3622 MINT_IN_CASE(MINT_BGT_R4
)
3623 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3625 MINT_IN_CASE(MINT_BGT_R8
)
3626 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
3628 MINT_IN_CASE(MINT_BLT_I4_S
)
3631 MINT_IN_CASE(MINT_BLT_I8_S
)
3634 MINT_IN_CASE(MINT_BLT_R4_S
)
3635 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3637 MINT_IN_CASE(MINT_BLT_R8_S
)
3638 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3640 MINT_IN_CASE(MINT_BLT_I4
)
3643 MINT_IN_CASE(MINT_BLT_I8
)
3646 MINT_IN_CASE(MINT_BLT_R4
)
3647 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3649 MINT_IN_CASE(MINT_BLT_R8
)
3650 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
3652 MINT_IN_CASE(MINT_BLE_I4_S
)
3655 MINT_IN_CASE(MINT_BLE_I8_S
)
3658 MINT_IN_CASE(MINT_BLE_R4_S
)
3659 CONDBR_S(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3661 MINT_IN_CASE(MINT_BLE_R8_S
)
3662 CONDBR_S(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3664 MINT_IN_CASE(MINT_BLE_I4
)
3667 MINT_IN_CASE(MINT_BLE_I8
)
3670 MINT_IN_CASE(MINT_BLE_R4
)
3671 CONDBR(!isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) && sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3673 MINT_IN_CASE(MINT_BLE_R8
)
3674 CONDBR(!mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
3676 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
3679 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
3682 MINT_IN_CASE(MINT_BNE_UN_R4_S
)
3683 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3685 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
3686 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3688 MINT_IN_CASE(MINT_BNE_UN_I4
)
3691 MINT_IN_CASE(MINT_BNE_UN_I8
)
3694 MINT_IN_CASE(MINT_BNE_UN_R4
)
3695 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
!= sp
[1].data
.f_r4
)
3697 MINT_IN_CASE(MINT_BNE_UN_R8
)
3698 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
3701 #define BRELOP_S_CAST(datamem, op, type) \
3703 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3704 ip += * (gint16 *)(ip + 1); \
3708 #define BRELOP_CAST(datamem, op, type) \
3710 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3711 ip += (gint32)READ32(ip + 1); \
3715 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
3716 BRELOP_S_CAST(i
, >=, guint32
);
3718 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3719 BRELOP_S_CAST(l
, >=, guint64
);
3721 MINT_IN_CASE(MINT_BGE_UN_R4_S
)
3722 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3724 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3725 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3727 MINT_IN_CASE(MINT_BGE_UN_I4
)
3728 BRELOP_CAST(i
, >=, guint32
);
3730 MINT_IN_CASE(MINT_BGE_UN_I8
)
3731 BRELOP_CAST(l
, >=, guint64
);
3733 MINT_IN_CASE(MINT_BGE_UN_R4
)
3734 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
>= sp
[1].data
.f_r4
)
3736 MINT_IN_CASE(MINT_BGE_UN_R8
)
3737 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3739 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3740 BRELOP_S_CAST(i
, >, guint32
);
3742 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3743 BRELOP_S_CAST(l
, >, guint64
);
3745 MINT_IN_CASE(MINT_BGT_UN_R4_S
)
3746 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3748 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3749 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3751 MINT_IN_CASE(MINT_BGT_UN_I4
)
3752 BRELOP_CAST(i
, >, guint32
);
3754 MINT_IN_CASE(MINT_BGT_UN_I8
)
3755 BRELOP_CAST(l
, >, guint64
);
3757 MINT_IN_CASE(MINT_BGT_UN_R4
)
3758 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
> sp
[1].data
.f_r4
)
3760 MINT_IN_CASE(MINT_BGT_UN_R8
)
3761 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3763 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3764 BRELOP_S_CAST(i
, <=, guint32
);
3766 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3767 BRELOP_S_CAST(l
, <=, guint64
);
3769 MINT_IN_CASE(MINT_BLE_UN_R4_S
)
3770 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3772 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3773 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3775 MINT_IN_CASE(MINT_BLE_UN_I4
)
3776 BRELOP_CAST(i
, <=, guint32
);
3778 MINT_IN_CASE(MINT_BLE_UN_I8
)
3779 BRELOP_CAST(l
, <=, guint64
);
3781 MINT_IN_CASE(MINT_BLE_UN_R4
)
3782 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
<= sp
[1].data
.f_r4
)
3784 MINT_IN_CASE(MINT_BLE_UN_R8
)
3785 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3787 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3788 BRELOP_S_CAST(i
, <, guint32
);
3790 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3791 BRELOP_S_CAST(l
, <, guint64
);
3793 MINT_IN_CASE(MINT_BLT_UN_R4_S
)
3794 CONDBR_S(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3796 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3797 CONDBR_S(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3799 MINT_IN_CASE(MINT_BLT_UN_I4
)
3800 BRELOP_CAST(i
, <, guint32
);
3802 MINT_IN_CASE(MINT_BLT_UN_I8
)
3803 BRELOP_CAST(l
, <, guint64
);
3805 MINT_IN_CASE(MINT_BLT_UN_R4
)
3806 CONDBR(isunordered (sp
[0].data
.f_r4
, sp
[1].data
.f_r4
) || sp
[0].data
.f_r4
< sp
[1].data
.f_r4
)
3808 MINT_IN_CASE(MINT_BLT_UN_R8
)
3809 CONDBR(mono_isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3811 MINT_IN_CASE(MINT_SWITCH
) {
3813 const unsigned short *st
;
3819 if ((guint32
)sp
->data
.i
< n
) {
3821 ip
+= 2 * (guint32
)sp
->data
.i
;
3822 offset
= READ32 (ip
);
3829 MINT_IN_CASE(MINT_LDIND_I1_CHECK
)
3830 NULL_CHECK (sp
[-1].data
.p
);
3832 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3834 MINT_IN_CASE(MINT_LDIND_U1_CHECK
)
3835 NULL_CHECK (sp
[-1].data
.p
);
3837 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3839 MINT_IN_CASE(MINT_LDIND_I2_CHECK
)
3840 NULL_CHECK (sp
[-1].data
.p
);
3842 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3844 MINT_IN_CASE(MINT_LDIND_U2_CHECK
)
3845 NULL_CHECK (sp
[-1].data
.p
);
3847 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3849 MINT_IN_CASE(MINT_LDIND_I4_CHECK
) /* Fall through */
3850 MINT_IN_CASE(MINT_LDIND_U4_CHECK
)
3851 NULL_CHECK (sp
[-1].data
.p
);
3853 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3855 MINT_IN_CASE(MINT_LDIND_I8_CHECK
)
3856 NULL_CHECK (sp
[-1].data
.p
);
3858 #ifdef NO_UNALIGNED_ACCESS
3859 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
3860 memcpy (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
3863 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
3865 MINT_IN_CASE(MINT_LDIND_I
) {
3866 guint16 offset
= * (guint16
*)(ip
+ 1);
3867 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3871 MINT_IN_CASE(MINT_LDIND_I8
) {
3872 guint16 offset
= * (guint16
*)(ip
+ 1);
3873 #ifdef NO_UNALIGNED_ACCESS
3874 if ((gsize
)sp
[-1 - offset
].data
.p
% SIZEOF_VOID_P
)
3875 memcpy (&sp
[-1 - offset
].data
.l
, sp
[-1 - offset
].data
.p
, sizeof (gint64
));
3878 sp
[-1 - offset
].data
.l
= *(gint64
*)sp
[-1 - offset
].data
.p
;
3882 MINT_IN_CASE(MINT_LDIND_R4_CHECK
)
3883 NULL_CHECK (sp
[-1].data
.p
);
3885 sp
[-1].data
.f_r4
= *(gfloat
*)sp
[-1].data
.p
;
3887 MINT_IN_CASE(MINT_LDIND_R8_CHECK
)
3888 NULL_CHECK (sp
[-1].data
.p
);
3890 #ifdef NO_UNALIGNED_ACCESS
3891 if ((gsize
)sp
[-1].data
.p
% SIZEOF_VOID_P
)
3892 memcpy (&sp
[-1].data
.f
, sp
[-1].data
.p
, sizeof (gdouble
));
3895 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3897 MINT_IN_CASE(MINT_LDIND_REF
)
3899 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3901 MINT_IN_CASE(MINT_LDIND_REF_CHECK
) {
3902 NULL_CHECK (sp
[-1].data
.p
);
3904 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3907 MINT_IN_CASE(MINT_STIND_REF
)
3910 mono_gc_wbarrier_generic_store_internal (sp
->data
.p
, sp
[1].data
.o
);
3912 MINT_IN_CASE(MINT_STIND_I1
)
3915 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3917 MINT_IN_CASE(MINT_STIND_I2
)
3920 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3922 MINT_IN_CASE(MINT_STIND_I4
)
3925 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3927 MINT_IN_CASE(MINT_STIND_I
)
3930 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3932 MINT_IN_CASE(MINT_STIND_I8
)
3935 #ifdef NO_UNALIGNED_ACCESS
3936 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
3937 memcpy (sp
->data
.p
, &sp
[1].data
.l
, sizeof (gint64
));
3940 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3942 MINT_IN_CASE(MINT_STIND_R4
)
3945 * (float *) sp
->data
.p
= sp
[1].data
.f_r4
;
3947 MINT_IN_CASE(MINT_STIND_R8
)
3950 #ifdef NO_UNALIGNED_ACCESS
3951 if ((gsize
)sp
->data
.p
% SIZEOF_VOID_P
)
3952 memcpy (sp
->data
.p
, &sp
[1].data
.f
, sizeof (double));
3955 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3957 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3960 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3962 #define BINOP(datamem, op) \
3964 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3966 MINT_IN_CASE(MINT_ADD_I4
)
3969 MINT_IN_CASE(MINT_ADD_I8
)
3972 MINT_IN_CASE(MINT_ADD_R4
)
3975 MINT_IN_CASE(MINT_ADD_R8
)
3978 MINT_IN_CASE(MINT_ADD1_I4
)
3982 MINT_IN_CASE(MINT_ADD1_I8
)
3986 MINT_IN_CASE(MINT_SUB_I4
)
3989 MINT_IN_CASE(MINT_SUB_I8
)
3992 MINT_IN_CASE(MINT_SUB_R4
)
3995 MINT_IN_CASE(MINT_SUB_R8
)
3998 MINT_IN_CASE(MINT_SUB1_I4
)
4002 MINT_IN_CASE(MINT_SUB1_I8
)
4006 MINT_IN_CASE(MINT_MUL_I4
)
4009 MINT_IN_CASE(MINT_MUL_I8
)
4012 MINT_IN_CASE(MINT_MUL_R4
)
4015 MINT_IN_CASE(MINT_MUL_R8
)
4018 MINT_IN_CASE(MINT_DIV_I4
)
4019 if (sp
[-1].data
.i
== 0)
4020 THROW_EX_DIV_ZERO (ip
);
4021 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4025 MINT_IN_CASE(MINT_DIV_I8
)
4026 if (sp
[-1].data
.l
== 0)
4027 THROW_EX_DIV_ZERO (ip
);
4028 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4032 MINT_IN_CASE(MINT_DIV_R4
)
4035 MINT_IN_CASE(MINT_DIV_R8
)
4039 #define BINOP_CAST(datamem, op, type) \
4041 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4043 MINT_IN_CASE(MINT_DIV_UN_I4
)
4044 if (sp
[-1].data
.i
== 0)
4045 THROW_EX_DIV_ZERO (ip
);
4046 BINOP_CAST(i
, /, guint32
);
4048 MINT_IN_CASE(MINT_DIV_UN_I8
)
4049 if (sp
[-1].data
.l
== 0)
4050 THROW_EX_DIV_ZERO (ip
);
4051 BINOP_CAST(l
, /, guint64
);
4053 MINT_IN_CASE(MINT_REM_I4
)
4054 if (sp
[-1].data
.i
== 0)
4055 THROW_EX_DIV_ZERO (ip
);
4056 if (sp
[-1].data
.i
== (-1) && sp
[-2].data
.i
== G_MININT32
)
4060 MINT_IN_CASE(MINT_REM_I8
)
4061 if (sp
[-1].data
.l
== 0)
4062 THROW_EX_DIV_ZERO (ip
);
4063 if (sp
[-1].data
.l
== (-1) && sp
[-2].data
.l
== G_MININT64
)
4067 MINT_IN_CASE(MINT_REM_R4
)
4068 /* FIXME: what do we actually do here? */
4070 sp
[-1].data
.f_r4
= fmodf (sp
[-1].data
.f_r4
, sp
[0].data
.f_r4
);
4073 MINT_IN_CASE(MINT_REM_R8
)
4074 /* FIXME: what do we actually do here? */
4076 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
4079 MINT_IN_CASE(MINT_REM_UN_I4
)
4080 if (sp
[-1].data
.i
== 0)
4081 THROW_EX_DIV_ZERO (ip
);
4082 BINOP_CAST(i
, %, guint32
);
4084 MINT_IN_CASE(MINT_REM_UN_I8
)
4085 if (sp
[-1].data
.l
== 0)
4086 THROW_EX_DIV_ZERO (ip
);
4087 BINOP_CAST(l
, %, guint64
);
4089 MINT_IN_CASE(MINT_AND_I4
)
4092 MINT_IN_CASE(MINT_AND_I8
)
4095 MINT_IN_CASE(MINT_OR_I4
)
4098 MINT_IN_CASE(MINT_OR_I8
)
4101 MINT_IN_CASE(MINT_XOR_I4
)
4104 MINT_IN_CASE(MINT_XOR_I8
)
4108 #define SHIFTOP(datamem, op) \
4110 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4113 MINT_IN_CASE(MINT_SHL_I4
)
4116 MINT_IN_CASE(MINT_SHL_I8
)
4119 MINT_IN_CASE(MINT_SHR_I4
)
4122 MINT_IN_CASE(MINT_SHR_I8
)
4125 MINT_IN_CASE(MINT_SHR_UN_I4
)
4127 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
4130 MINT_IN_CASE(MINT_SHR_UN_I8
)
4132 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
4135 MINT_IN_CASE(MINT_NEG_I4
)
4136 sp
[-1].data
.i
= - sp
[-1].data
.i
;
4139 MINT_IN_CASE(MINT_NEG_I8
)
4140 sp
[-1].data
.l
= - sp
[-1].data
.l
;
4143 MINT_IN_CASE(MINT_NEG_R4
)
4144 sp
[-1].data
.f_r4
= - sp
[-1].data
.f_r4
;
4147 MINT_IN_CASE(MINT_NEG_R8
)
4148 sp
[-1].data
.f
= - sp
[-1].data
.f
;
4151 MINT_IN_CASE(MINT_NOT_I4
)
4152 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
4155 MINT_IN_CASE(MINT_NOT_I8
)
4156 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
4159 MINT_IN_CASE(MINT_CONV_I1_I4
)
4160 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
4163 MINT_IN_CASE(MINT_CONV_I1_I8
)
4164 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
4167 MINT_IN_CASE(MINT_CONV_I1_R4
)
4168 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f_r4
;
4171 MINT_IN_CASE(MINT_CONV_I1_R8
)
4172 /* without gint32 cast, C compiler is allowed to use undefined
4173 * behaviour if data.f is bigger than >255. See conv.fpint section
4175 * > The conversion truncates; that is, the fractional part
4176 * > is discarded. The behavior is undefined if the truncated
4177 * > value cannot be represented in the destination type.
4179 sp
[-1].data
.i
= (gint8
) (gint32
) sp
[-1].data
.f
;
4182 MINT_IN_CASE(MINT_CONV_U1_I4
)
4183 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
4186 MINT_IN_CASE(MINT_CONV_U1_I8
)
4187 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
4190 MINT_IN_CASE(MINT_CONV_U1_R4
)
4191 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f_r4
;
4194 MINT_IN_CASE(MINT_CONV_U1_R8
)
4195 sp
[-1].data
.i
= (guint8
) (guint32
) sp
[-1].data
.f
;
4198 MINT_IN_CASE(MINT_CONV_I2_I4
)
4199 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
4202 MINT_IN_CASE(MINT_CONV_I2_I8
)
4203 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
4206 MINT_IN_CASE(MINT_CONV_I2_R4
)
4207 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f_r4
;
4210 MINT_IN_CASE(MINT_CONV_I2_R8
)
4211 sp
[-1].data
.i
= (gint16
) (gint32
) sp
[-1].data
.f
;
4214 MINT_IN_CASE(MINT_CONV_U2_I4
)
4215 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
4218 MINT_IN_CASE(MINT_CONV_U2_I8
)
4219 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
4222 MINT_IN_CASE(MINT_CONV_U2_R4
)
4223 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f_r4
;
4226 MINT_IN_CASE(MINT_CONV_U2_R8
)
4227 sp
[-1].data
.i
= (guint16
) (guint32
) sp
[-1].data
.f
;
4230 MINT_IN_CASE(MINT_CONV_I4_R4
)
4231 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
4234 MINT_IN_CASE(MINT_CONV_I4_R8
)
4235 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
4238 MINT_IN_CASE(MINT_CONV_U4_I8
)
4239 MINT_IN_CASE(MINT_CONV_I4_I8
)
4240 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
4243 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
4244 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
4247 MINT_IN_CASE(MINT_CONV_U4_R4
)
4248 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4249 sp
[-1].data
.i
= mono_rconv_u4 (sp
[-1].data
.f_r4
);
4251 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
4255 MINT_IN_CASE(MINT_CONV_U4_R8
)
4256 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4257 sp
[-1].data
.i
= mono_fconv_u4_2 (sp
[-1].data
.f
);
4259 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4263 MINT_IN_CASE(MINT_CONV_I8_I4
)
4264 sp
[-1].data
.l
= sp
[-1].data
.i
;
4267 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
4268 sp
[-2].data
.l
= sp
[-2].data
.i
;
4271 MINT_IN_CASE(MINT_CONV_I8_U4
)
4272 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
4275 MINT_IN_CASE(MINT_CONV_I8_R4
)
4276 sp
[-1].data
.l
= (gint64
) sp
[-1].data
.f_r4
;
4279 MINT_IN_CASE(MINT_CONV_I8_R8
)
4280 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
4283 MINT_IN_CASE(MINT_CONV_R4_I4
)
4284 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.i
;
4287 MINT_IN_CASE(MINT_CONV_R4_I8
)
4288 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.l
;
4291 MINT_IN_CASE(MINT_CONV_R4_R8
)
4292 sp
[-1].data
.f_r4
= (float)sp
[-1].data
.f
;
4295 MINT_IN_CASE(MINT_CONV_R8_I4
)
4296 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
4299 MINT_IN_CASE(MINT_CONV_R8_I8
)
4300 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
4303 MINT_IN_CASE(MINT_CONV_R8_R4
)
4304 sp
[-1].data
.f
= (double) sp
[-1].data
.f_r4
;
4307 MINT_IN_CASE(MINT_CONV_R8_R4_SP
)
4308 sp
[-2].data
.f
= (double) sp
[-2].data
.f_r4
;
4311 MINT_IN_CASE(MINT_CONV_U8_I4
)
4312 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
4315 MINT_IN_CASE(MINT_CONV_U8_R4
)
4316 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4317 sp
[-1].data
.l
= mono_rconv_u8 (sp
[-1].data
.f_r4
);
4319 sp
[-1].data
.l
= (guint64
) sp
[-1].data
.f_r4
;
4323 MINT_IN_CASE(MINT_CONV_U8_R8
)
4324 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4325 sp
[-1].data
.l
= mono_fconv_u8_2 (sp
[-1].data
.f
);
4327 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
4331 MINT_IN_CASE(MINT_CPOBJ
) {
4332 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4333 g_assert (m_class_is_valuetype (c
));
4334 /* if this assertion fails, we need to add a write barrier */
4335 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c
)));
4336 stackval_from_data (m_class_get_byval_arg (c
), (stackval
*)sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
4341 MINT_IN_CASE(MINT_CPOBJ_VT
) {
4342 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4343 mono_value_copy_internal (sp
[-2].data
.vt
, sp
[-1].data
.vt
, c
);
4348 MINT_IN_CASE(MINT_LDOBJ_VT
) {
4349 int size
= READ32(ip
+ 1);
4351 memcpy (vt_sp
, sp
[-1].data
.p
, size
);
4352 sp
[-1].data
.p
= vt_sp
;
4353 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4356 MINT_IN_CASE(MINT_LDSTR
)
4357 sp
->data
.p
= imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4361 MINT_IN_CASE(MINT_LDSTR_TOKEN
) {
4362 MonoString
*s
= NULL
;
4363 guint32 strtoken
= (guint32
)(gsize
)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4365 MonoMethod
*method
= imethod
->method
;
4366 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
4367 s
= (MonoString
*)mono_method_get_wrapper_data (method
, strtoken
);
4368 } else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4369 s
= mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method
, strtoken
));
4371 g_assert_not_reached ();
4378 MINT_IN_CASE(MINT_NEWOBJ_ARRAY
) {
4379 MonoClass
*newobj_class
;
4380 guint32 token
= * (guint16
*)(ip
+ 1);
4381 guint16 param_count
= * (guint16
*)(ip
+ 2);
4383 newobj_class
= (MonoClass
*) imethod
->data_items
[token
];
4386 sp
->data
.o
= ves_array_create (imethod
->domain
, newobj_class
, param_count
, sp
, error
);
4387 if (!mono_error_ok (error
))
4388 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4394 MINT_IN_CASE(MINT_NEWOBJ_FAST
) {
4395 guint16 param_count
;
4396 guint16 imethod_index
= *(guint16
*) (ip
+ 1);
4398 const gboolean is_inlined
= imethod_index
== 0xffff;
4400 param_count
= *(guint16
*)(ip
+ 2);
4404 memmove (sp
+ 1 + is_inlined
, sp
, param_count
* sizeof (stackval
));
4407 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 3)];
4408 INIT_VTABLE (vtable
);
4410 frame_objref (frame
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
4411 if (G_UNLIKELY (!frame_objref (frame
))) {
4412 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
4413 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4416 sp
[0].data
.o
= frame_objref (frame
);
4418 sp
[1].data
.o
= frame_objref (frame
);
4419 sp
+= param_count
+ 2;
4421 InterpMethod
*ctor_method
= (InterpMethod
*) imethod
->data_items
[imethod_index
];
4424 child_frame
.imethod
= ctor_method
;
4425 child_frame
.stack_args
= sp
;
4427 interp_exec_method (&child_frame
, context
, error
);
4428 CHECK_RESUME_STATE (context
);
4429 sp
[0].data
.o
= frame_objref (frame
);
4436 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST
)
4437 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST
) {
4438 guint16 param_count
;
4439 stackval valuetype_this
;
4443 child_frame
.imethod
= (InterpMethod
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4444 param_count
= *(guint16
*)(ip
+ 2);
4448 memmove (sp
+ 1, sp
, param_count
* sizeof (stackval
));
4450 child_frame
.stack_args
= sp
;
4452 gboolean vtst
= *ip
== MINT_NEWOBJ_VTST_FAST
;
4454 memset (vt_sp
, 0, *(guint16
*)(ip
+ 3));
4456 valuetype_this
.data
.p
= vt_sp
;
4459 memset (&valuetype_this
, 0, sizeof (stackval
));
4460 sp
->data
.p
= &valuetype_this
;
4464 interp_exec_method (&child_frame
, context
, error
);
4466 CHECK_RESUME_STATE (context
);
4468 *sp
= valuetype_this
;
4472 MINT_IN_CASE(MINT_NEWOBJ
) {
4473 MonoClass
*newobj_class
;
4474 MonoMethodSignature
*csig
;
4475 stackval valuetype_this
;
4481 token
= * (guint16
*)(ip
+ 1);
4484 child_frame
.ip
= NULL
;
4485 child_frame
.ex
= NULL
;
4487 child_frame
.imethod
= (InterpMethod
*)imethod
->data_items
[token
];
4488 csig
= mono_method_signature_internal (child_frame
.imethod
->method
);
4489 newobj_class
= child_frame
.imethod
->method
->klass
;
4490 /*if (profiling_classes) {
4491 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4493 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4496 g_assert (csig
->hasthis
);
4497 if (csig
->param_count
) {
4498 sp
-= csig
->param_count
;
4499 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
4501 child_frame
.stack_args
= sp
;
4504 * First arg is the object.
4506 if (m_class_is_valuetype (newobj_class
)) {
4507 MonoType
*t
= m_class_get_byval_arg (newobj_class
);
4508 memset (&valuetype_this
, 0, sizeof (stackval
));
4509 if (!m_class_is_enumtype (newobj_class
) && (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
4511 valuetype_this
.data
.p
= vt_sp
;
4513 sp
->data
.p
= &valuetype_this
;
4516 if (newobj_class
!= mono_defaults
.string_class
) {
4517 MonoVTable
*vtable
= mono_class_vtable_checked (imethod
->domain
, newobj_class
, error
);
4518 if (!mono_error_ok (error
) || !mono_runtime_class_init_full (vtable
, error
))
4519 THROW_EX (mono_error_convert_to_exception (error
), ip
);
4520 frame_objref (frame
) = mono_object_new_checked (imethod
->domain
, newobj_class
, error
);
4521 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4522 EXCEPTION_CHECKPOINT
;
4523 sp
->data
.o
= frame_objref (frame
);
4524 #ifndef DISABLE_REMOTING
4525 if (mono_object_is_transparent_proxy (frame_objref (frame
))) {
4526 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check (child_frame
.imethod
->method
, error
);
4527 mono_error_assert_ok (error
);
4528 child_frame
.imethod
= mono_interp_get_imethod (imethod
->domain
, remoting_invoke_method
, error
);
4529 mono_error_assert_ok (error
);
4534 child_frame
.retval
= &retval
;
4538 interp_exec_method (&child_frame
, context
, error
);
4540 CHECK_RESUME_STATE (context
);
4543 * a constructor returns void, but we need to return the object we created
4545 if (m_class_is_valuetype (newobj_class
) && !m_class_is_enumtype (newobj_class
)) {
4546 *sp
= valuetype_this
;
4547 } else if (newobj_class
== mono_defaults
.string_class
) {
4550 sp
->data
.o
= frame_objref (frame
);
4555 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
4561 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR
) {
4562 MonoMethodSignature
*csig
;
4566 token
= * (guint16
*)(ip
+ 1);
4569 InterpMethod
*cmethod
= (InterpMethod
*)imethod
->data_items
[token
];
4570 csig
= mono_method_signature_internal (cmethod
->method
);
4572 g_assert (csig
->hasthis
);
4573 sp
-= csig
->param_count
;
4575 gpointer arg0
= sp
[0].data
.p
;
4577 gpointer
*byreference_this
= (gpointer
*)vt_sp
;
4578 *byreference_this
= arg0
;
4580 /* Followed by a VTRESULT opcode which will push the result on the stack */
4584 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE
) {
4585 gpointer
*byreference_this
= (gpointer
*)sp
[-1].data
.p
;
4586 sp
[-1].data
.p
= *byreference_this
;
4590 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
) {
4592 sp
[0].data
.p
= (guint8
*)sp
[0].data
.p
+ sp
[1].data
.nati
;
4597 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET
) {
4599 sp
[0].data
.nati
= (guint8
*)sp
[1].data
.p
- (guint8
*)sp
[0].data
.p
;
4604 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
) {
4606 MonoObject
*obj
= sp
[0].data
.o
;
4607 sp
[0].data
.i
= (obj
->vtable
->flags
& MONO_VT_FLAG_ARRAY_OR_STRING
) != 0;
4612 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE
)
4613 MINT_IN_CASE(MINT_ISINST_INTERFACE
) {
4614 gboolean isinst_instr
= *ip
== MINT_ISINST_INTERFACE
;
4615 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4616 if ((o
= sp
[-1].data
.o
)) {
4618 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o
->vtable
, m_class_get_interface_id (c
))) {
4620 } else if (m_class_is_array_special_interface (c
) || mono_object_is_transparent_proxy (o
)) {
4622 isinst
= mono_object_isinst_checked (o
, c
, error
) != NULL
;
4623 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4630 sp
[-1].data
.p
= NULL
;
4632 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4638 MINT_IN_CASE(MINT_CASTCLASS_COMMON
)
4639 MINT_IN_CASE(MINT_ISINST_COMMON
) {
4640 gboolean isinst_instr
= *ip
== MINT_ISINST_COMMON
;
4641 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4642 if ((o
= sp
[-1].data
.o
)) {
4643 gboolean isinst
= mono_class_has_parent_fast (o
->vtable
->klass
, c
);
4647 sp
[-1].data
.p
= NULL
;
4649 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4655 MINT_IN_CASE(MINT_CASTCLASS
)
4656 MINT_IN_CASE(MINT_ISINST
) {
4657 gboolean isinst_instr
= *ip
== MINT_ISINST
;
4658 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4659 if ((o
= sp
[-1].data
.o
)) {
4660 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, error
);
4661 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4664 sp
[-1].data
.p
= NULL
;
4666 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4672 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
4673 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
4676 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
4677 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
4680 MINT_IN_CASE(MINT_UNBOX
)
4681 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4686 if (!(m_class_get_rank (o
->vtable
->klass
) == 0 && m_class_get_element_class (o
->vtable
->klass
) == m_class_get_element_class (c
)))
4687 THROW_EX (mono_get_exception_invalid_cast (), ip
);
4689 sp
[-1].data
.p
= mono_object_unbox_internal (o
);
4692 MINT_IN_CASE(MINT_THROW
)
4695 sp
->data
.p
= mono_get_exception_null_reference ();
4697 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
4699 MINT_IN_CASE(MINT_CHECKPOINT
)
4700 /* Do synchronous checking of abort requests */
4701 EXCEPTION_CHECKPOINT
;
4704 MINT_IN_CASE(MINT_SAFEPOINT
)
4705 /* Do synchronous checking of abort requests */
4706 EXCEPTION_CHECKPOINT
;
4707 /* Poll safepoint */
4708 mono_threads_safepoint ();
4711 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
4713 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4716 MINT_IN_CASE(MINT_LDFLDA
)
4719 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
4722 MINT_IN_CASE(MINT_CKNULL_N
) {
4723 /* Same as CKNULL, but further down the stack */
4724 int n
= *(guint16
*)(ip
+ 1);
4731 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4732 o = sp [-1].data.o; \
4735 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4737 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4740 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4742 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
4743 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
4744 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
4745 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
4746 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
4747 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
4748 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f_r4
, float); MINT_IN_BREAK
;
4749 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
4750 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4751 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
4752 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED
) LDFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4753 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED
) LDFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4755 MINT_IN_CASE(MINT_LDFLD_VT
) {
4759 int size
= READ32(ip
+ 2);
4760 sp
[-1].data
.p
= vt_sp
;
4761 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), size
);
4762 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4767 MINT_IN_CASE(MINT_LDRMFLD
) {
4768 MonoClassField
*field
;
4773 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4775 #ifndef DISABLE_REMOTING
4776 if (mono_object_is_transparent_proxy (o
)) {
4778 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4780 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4781 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4784 addr
= (char*)o
+ field
->offset
;
4786 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
4790 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
4791 MonoClassField
*field
;
4797 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4798 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4799 i32
= mono_class_value_size (klass
, NULL
);
4802 #ifndef DISABLE_REMOTING
4803 if (mono_object_is_transparent_proxy (o
)) {
4805 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4806 addr
= (char*)mono_load_remote_field_checked (o
, klass
, field
, &tmp
, error
);
4807 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4810 addr
= (char*)o
+ field
->offset
;
4812 sp
[-1].data
.p
= vt_sp
;
4813 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4814 memcpy(sp
[-1].data
.p
, addr
, i32
);
4818 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4819 o = sp [-2].data.o; \
4823 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
4825 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4828 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4830 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
4831 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
4832 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
4833 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
4834 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
4835 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
4836 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f_r4
, float); MINT_IN_BREAK
;
4837 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
4838 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
4839 MINT_IN_CASE(MINT_STFLD_O
)
4843 mono_gc_wbarrier_set_field_internal (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.o
);
4846 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED
) STFLD_UNALIGNED(l
, gint64
, TRUE
); MINT_IN_BREAK
;
4847 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED
) STFLD_UNALIGNED(f
, double, TRUE
); MINT_IN_BREAK
;
4849 MINT_IN_CASE(MINT_STFLD_VT
) {
4854 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 2)];
4855 i32
= mono_class_value_size (klass
, NULL
);
4857 guint16 offset
= * (guint16
*)(ip
+ 1);
4858 mono_value_copy_internal ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
4860 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4864 MINT_IN_CASE(MINT_STRMFLD
) {
4865 MonoClassField
*field
;
4870 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4873 #ifndef DISABLE_REMOTING
4874 if (mono_object_is_transparent_proxy (o
)) {
4875 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4876 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, error
);
4877 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4880 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
4885 MINT_IN_CASE(MINT_STRMFLD_VT
) {
4886 MonoClassField
*field
;
4890 field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4891 MonoClass
*klass
= mono_class_from_mono_type_internal (field
->type
);
4892 i32
= mono_class_value_size (klass
, NULL
);
4895 #ifndef DISABLE_REMOTING
4896 if (mono_object_is_transparent_proxy (o
)) {
4897 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
4898 mono_store_remote_field_checked (o
, klass
, field
, sp
[-1].data
.p
, error
);
4899 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
4902 mono_value_copy_internal ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
4905 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4908 MINT_IN_CASE(MINT_LDSFLDA
) {
4909 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4910 INIT_VTABLE (vtable
);
4911 sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
4917 MINT_IN_CASE(MINT_LDSSFLDA
) {
4918 guint32 offset
= READ32(ip
+ 1);
4919 sp
->data
.p
= mono_get_special_static_data (offset
);
4925 /* We init class here to preserve cctor order */
4926 #define LDSFLD(datamem, fieldtype) { \
4927 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4928 INIT_VTABLE (vtable); \
4929 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
4934 MINT_IN_CASE(MINT_LDSFLD_I1
) LDSFLD(i
, gint8
); MINT_IN_BREAK
;
4935 MINT_IN_CASE(MINT_LDSFLD_U1
) LDSFLD(i
, guint8
); MINT_IN_BREAK
;
4936 MINT_IN_CASE(MINT_LDSFLD_I2
) LDSFLD(i
, gint16
); MINT_IN_BREAK
;
4937 MINT_IN_CASE(MINT_LDSFLD_U2
) LDSFLD(i
, guint16
); MINT_IN_BREAK
;
4938 MINT_IN_CASE(MINT_LDSFLD_I4
) LDSFLD(i
, gint32
); MINT_IN_BREAK
;
4939 MINT_IN_CASE(MINT_LDSFLD_I8
) LDSFLD(l
, gint64
); MINT_IN_BREAK
;
4940 MINT_IN_CASE(MINT_LDSFLD_R4
) LDSFLD(f_r4
, float); MINT_IN_BREAK
;
4941 MINT_IN_CASE(MINT_LDSFLD_R8
) LDSFLD(f
, double); MINT_IN_BREAK
;
4942 MINT_IN_CASE(MINT_LDSFLD_O
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
4943 MINT_IN_CASE(MINT_LDSFLD_P
) LDSFLD(p
, gpointer
); MINT_IN_BREAK
;
4945 MINT_IN_CASE(MINT_LDSFLD_VT
) {
4946 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
4947 gpointer addr
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
4948 i32
= READ32(ip
+ 3);
4949 INIT_VTABLE (vtable
);
4952 memcpy (vt_sp
, addr
, i32
);
4953 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
4959 #define LDTSFLD(datamem, fieldtype) { \
4960 guint32 offset = READ32(ip + 1); \
4961 MonoInternalThread *thread = mono_thread_internal_current (); \
4962 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4963 sp[0].data.datamem = *(fieldtype*)addr; \
4967 MINT_IN_CASE(MINT_LDTSFLD_I1
) LDTSFLD(i
, gint8
); MINT_IN_BREAK
;
4968 MINT_IN_CASE(MINT_LDTSFLD_U1
) LDTSFLD(i
, guint8
); MINT_IN_BREAK
;
4969 MINT_IN_CASE(MINT_LDTSFLD_I2
) LDTSFLD(i
, gint16
); MINT_IN_BREAK
;
4970 MINT_IN_CASE(MINT_LDTSFLD_U2
) LDTSFLD(i
, guint16
); MINT_IN_BREAK
;
4971 MINT_IN_CASE(MINT_LDTSFLD_I4
) LDTSFLD(i
, gint32
); MINT_IN_BREAK
;
4972 MINT_IN_CASE(MINT_LDTSFLD_I8
) LDTSFLD(l
, gint64
); MINT_IN_BREAK
;
4973 MINT_IN_CASE(MINT_LDTSFLD_R4
) LDTSFLD(f_r4
, float); MINT_IN_BREAK
;
4974 MINT_IN_CASE(MINT_LDTSFLD_R8
) LDTSFLD(f
, double); MINT_IN_BREAK
;
4975 MINT_IN_CASE(MINT_LDTSFLD_O
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
4976 MINT_IN_CASE(MINT_LDTSFLD_P
) LDTSFLD(p
, gpointer
); MINT_IN_BREAK
;
4978 MINT_IN_CASE(MINT_LDSSFLD
) {
4979 MonoClassField
*field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
4980 guint32 offset
= READ32(ip
+ 2);
4981 gpointer addr
= mono_get_special_static_data (offset
);
4982 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
4987 MINT_IN_CASE(MINT_LDSSFLD_VT
) {
4988 guint32 offset
= READ32(ip
+ 1);
4989 gpointer addr
= mono_get_special_static_data (offset
);
4991 int size
= READ32 (ip
+ 3);
4992 memcpy (vt_sp
, addr
, size
);
4994 vt_sp
+= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4999 #define STSFLD(datamem, fieldtype) { \
5000 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
5001 INIT_VTABLE (vtable); \
5003 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
5007 MINT_IN_CASE(MINT_STSFLD_I1
) STSFLD(i
, gint8
); MINT_IN_BREAK
;
5008 MINT_IN_CASE(MINT_STSFLD_U1
) STSFLD(i
, guint8
); MINT_IN_BREAK
;
5009 MINT_IN_CASE(MINT_STSFLD_I2
) STSFLD(i
, gint16
); MINT_IN_BREAK
;
5010 MINT_IN_CASE(MINT_STSFLD_U2
) STSFLD(i
, guint16
); MINT_IN_BREAK
;
5011 MINT_IN_CASE(MINT_STSFLD_I4
) STSFLD(i
, gint32
); MINT_IN_BREAK
;
5012 MINT_IN_CASE(MINT_STSFLD_I8
) STSFLD(l
, gint64
); MINT_IN_BREAK
;
5013 MINT_IN_CASE(MINT_STSFLD_R4
) STSFLD(f_r4
, float); MINT_IN_BREAK
;
5014 MINT_IN_CASE(MINT_STSFLD_R8
) STSFLD(f
, double); MINT_IN_BREAK
;
5015 MINT_IN_CASE(MINT_STSFLD_P
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5016 MINT_IN_CASE(MINT_STSFLD_O
) STSFLD(p
, gpointer
); MINT_IN_BREAK
;
5018 MINT_IN_CASE(MINT_STSFLD_VT
) {
5019 MonoVTable
*vtable
= (MonoVTable
*) imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5020 gpointer addr
= imethod
->data_items
[*(guint16
*)(ip
+ 2)];
5021 i32
= READ32(ip
+ 3);
5022 INIT_VTABLE (vtable
);
5024 memcpy (addr
, sp
[-1].data
.vt
, i32
);
5025 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5031 #define STTSFLD(datamem, fieldtype) { \
5032 guint32 offset = READ32(ip + 1); \
5033 MonoInternalThread *thread = mono_thread_internal_current (); \
5034 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5036 *(fieldtype*)addr = sp[0].data.datamem; \
5040 MINT_IN_CASE(MINT_STTSFLD_I1
) STTSFLD(i
, gint8
); MINT_IN_BREAK
;
5041 MINT_IN_CASE(MINT_STTSFLD_U1
) STTSFLD(i
, guint8
); MINT_IN_BREAK
;
5042 MINT_IN_CASE(MINT_STTSFLD_I2
) STTSFLD(i
, gint16
); MINT_IN_BREAK
;
5043 MINT_IN_CASE(MINT_STTSFLD_U2
) STTSFLD(i
, guint16
); MINT_IN_BREAK
;
5044 MINT_IN_CASE(MINT_STTSFLD_I4
) STTSFLD(i
, gint32
); MINT_IN_BREAK
;
5045 MINT_IN_CASE(MINT_STTSFLD_I8
) STTSFLD(l
, gint64
); MINT_IN_BREAK
;
5046 MINT_IN_CASE(MINT_STTSFLD_R4
) STTSFLD(f_r4
, float); MINT_IN_BREAK
;
5047 MINT_IN_CASE(MINT_STTSFLD_R8
) STTSFLD(f
, double); MINT_IN_BREAK
;
5048 MINT_IN_CASE(MINT_STTSFLD_P
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5049 MINT_IN_CASE(MINT_STTSFLD_O
) STTSFLD(p
, gpointer
); MINT_IN_BREAK
;
5051 MINT_IN_CASE(MINT_STSSFLD
) {
5052 MonoClassField
*field
= (MonoClassField
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5053 guint32 offset
= READ32(ip
+ 2);
5054 gpointer addr
= mono_get_special_static_data (offset
);
5056 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
5060 MINT_IN_CASE(MINT_STSSFLD_VT
) {
5061 guint32 offset
= READ32(ip
+ 1);
5062 gpointer addr
= mono_get_special_static_data (offset
);
5064 int size
= READ32 (ip
+ 3);
5065 memcpy (addr
, sp
->data
.vt
, size
);
5066 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5071 MINT_IN_CASE(MINT_STOBJ_VT
) {
5073 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5075 size
= mono_class_value_size (c
, NULL
);
5076 mono_value_copy_internal (sp
[-2].data
.p
, sp
[-1].data
.p
, c
);
5077 vt_sp
-= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5081 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
5082 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT32
)
5084 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
5087 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
5088 if (sp
[-1].data
.i
< 0)
5090 sp
[-1].data
.l
= sp
[-1].data
.i
;
5093 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
5094 if (sp
[-1].data
.l
< 0)
5098 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
5099 if ((guint64
) sp
[-1].data
.l
> G_MAXINT64
)
5103 MINT_IN_CASE(MINT_CONV_OVF_U8_R4
)
5104 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT64
|| isnan (sp
[-1].data
.f_r4
))
5106 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f_r4
;
5109 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
5110 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT64
|| isnan (sp
[-1].data
.f
))
5112 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
5115 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
5116 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT64
)
5118 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5121 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4
)
5122 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXINT64
)
5124 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5127 MINT_IN_CASE(MINT_CONV_OVF_I8_R4
)
5128 if (sp
[-1].data
.f_r4
< G_MININT64
|| sp
[-1].data
.f_r4
> G_MAXINT64
|| isnan (sp
[-1].data
.f_r4
))
5130 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f_r4
;
5133 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
5134 if (sp
[-1].data
.f
< G_MININT64
|| sp
[-1].data
.f
> G_MAXINT64
|| isnan (sp
[-1].data
.f
))
5136 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
5139 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
5140 if ((guint64
)sp
[-1].data
.l
> G_MAXINT32
)
5142 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
5145 MINT_IN_CASE(MINT_BOX
) {
5146 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5147 guint16 offset
= * (guint16
*)(ip
+ 2);
5149 frame_objref (frame
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5150 stackval_to_data (m_class_get_byval_arg (vtable
->klass
), &sp
[-1 - offset
], mono_object_get_data (frame_objref (frame
)), FALSE
);
5152 sp
[-1 - offset
].data
.p
= frame_objref (frame
);
5157 MINT_IN_CASE(MINT_BOX_VT
) {
5158 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5160 guint16 offset
= * (guint16
*)(ip
+ 2);
5161 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
5162 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
5164 int size
= mono_class_value_size (c
, NULL
);
5165 frame_objref (frame
) = mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
5166 mono_value_copy_internal (mono_object_get_data (frame_objref (frame
)), sp
[-1 - offset
].data
.p
, c
);
5168 sp
[-1 - offset
].data
.p
= frame_objref (frame
);
5169 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5176 MINT_IN_CASE(MINT_BOX_NULLABLE
) {
5177 c
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
5178 guint16 offset
= * (guint16
*)(ip
+ 2);
5179 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
5180 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
5182 int size
= mono_class_value_size (c
, NULL
);
5184 sp
[-1 - offset
].data
.o
= mono_nullable_box (sp
[-1 - offset
].data
.p
, c
, error
);
5185 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5187 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5194 MINT_IN_CASE(MINT_NEWARR
) {
5195 MonoVTable
*vtable
= (MonoVTable
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5196 sp
[-1].data
.o
= (MonoObject
*) mono_array_new_specific_checked (vtable
, sp
[-1].data
.i
, error
);
5197 if (!mono_error_ok (error
)) {
5198 THROW_EX (mono_error_convert_to_exception (error
), ip
);
5200 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5202 /*if (profiling_classes) {
5203 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5205 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5210 MINT_IN_CASE(MINT_LDLEN
)
5213 sp
[-1].data
.nati
= mono_array_length_internal ((MonoArray
*)o
);
5216 MINT_IN_CASE(MINT_LDLEN_SPAN
) {
5219 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 1);
5220 sp
[-1].data
.nati
= *(gint32
*) ((guint8
*) o
+ offset_length
);
5224 MINT_IN_CASE(MINT_GETCHR
) {
5226 s
= (MonoString
*)sp
[-2].data
.p
;
5228 i32
= sp
[-1].data
.i
;
5229 if (i32
< 0 || i32
>= mono_string_length_internal (s
))
5230 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5232 sp
[-1].data
.i
= mono_string_chars_internal (s
)[i32
];
5236 MINT_IN_CASE(MINT_GETITEM_SPAN
) {
5237 guint8
*span
= (guint8
*) sp
[-2].data
.p
;
5238 int index
= sp
[-1].data
.i
;
5239 gsize element_size
= (gsize
) *(gint16
*) (ip
+ 1);
5240 gsize offset_length
= (gsize
) *(gint16
*) (ip
+ 2);
5241 gsize offset_pointer
= (gsize
) *(gint16
*) (ip
+ 3);
5246 gint32 length
= *(gint32
*) (span
+ offset_length
);
5247 if (index
< 0 || index
>= length
)
5248 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5250 gpointer pointer
= *(gpointer
*)(span
+ offset_pointer
);
5251 sp
[-1].data
.p
= (guint8
*) pointer
+ index
* element_size
;
5256 MINT_IN_CASE(MINT_STRLEN
)
5260 sp
[-1].data
.i
= mono_string_length_internal ((MonoString
*) o
);
5262 MINT_IN_CASE(MINT_ARRAY_RANK
)
5265 sp
[-1].data
.i
= m_class_get_rank (mono_object_class (sp
[-1].data
.p
));
5268 MINT_IN_CASE(MINT_LDELEMA_FAST
) {
5269 /* No bounds, one direction */
5270 gint32 size
= READ32 (ip
+ 1);
5271 gint32 index
= sp
[-1].data
.i
;
5273 MonoArray
*ao
= (MonoArray
*)sp
[-2].data
.o
;
5275 if (index
>= ao
->max_length
)
5276 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5277 sp
[-2].data
.p
= mono_array_addr_with_size_fast (ao
, size
, index
);
5283 MINT_IN_CASE(MINT_LDELEMA
)
5284 MINT_IN_CASE(MINT_LDELEMA_TC
) {
5285 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
5287 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[*(guint16
*) (ip
+ 1)];
5288 guint16 numargs
= *(guint16
*) (ip
+ 2);
5294 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
5296 THROW_EX (frame
->ex
, ip
);
5301 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
5302 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
5303 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
5304 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
5305 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
5306 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
5307 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
5308 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
5309 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
5310 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
5311 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
5312 MINT_IN_CASE(MINT_LDELEM_VT
) {
5318 o
= (MonoArray
*)sp
[0].data
.p
;
5321 aindex
= sp
[1].data
.i
;
5322 if (aindex
>= mono_array_length_internal (o
))
5323 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5326 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5329 case MINT_LDELEM_I1
:
5330 sp
[0].data
.i
= mono_array_get_fast (o
, gint8
, aindex
);
5332 case MINT_LDELEM_U1
:
5333 sp
[0].data
.i
= mono_array_get_fast (o
, guint8
, aindex
);
5335 case MINT_LDELEM_I2
:
5336 sp
[0].data
.i
= mono_array_get_fast (o
, gint16
, aindex
);
5338 case MINT_LDELEM_U2
:
5339 sp
[0].data
.i
= mono_array_get_fast (o
, guint16
, aindex
);
5342 sp
[0].data
.nati
= mono_array_get_fast (o
, mono_i
, aindex
);
5344 case MINT_LDELEM_I4
:
5345 sp
[0].data
.i
= mono_array_get_fast (o
, gint32
, aindex
);
5347 case MINT_LDELEM_U4
:
5348 sp
[0].data
.i
= mono_array_get_fast (o
, guint32
, aindex
);
5350 case MINT_LDELEM_I8
:
5351 sp
[0].data
.l
= mono_array_get_fast (o
, guint64
, aindex
);
5353 case MINT_LDELEM_R4
:
5354 sp
[0].data
.f_r4
= mono_array_get_fast (o
, float, aindex
);
5356 case MINT_LDELEM_R8
:
5357 sp
[0].data
.f
= mono_array_get_fast (o
, double, aindex
);
5359 case MINT_LDELEM_REF
:
5360 sp
[0].data
.p
= mono_array_get_fast (o
, gpointer
, aindex
);
5362 case MINT_LDELEM_VT
: {
5363 i32
= READ32 (ip
+ 1);
5364 char *src_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5365 sp
[0].data
.vt
= vt_sp
;
5366 // Copying to vtstack. No wbarrier needed
5367 memcpy (sp
[0].data
.vt
, src_addr
, i32
);
5368 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5380 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
5381 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
5382 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
5383 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
5384 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
5385 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
5386 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
5387 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
5388 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
5389 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
5390 MINT_IN_CASE(MINT_STELEM_VT
) {
5398 aindex
= sp
[1].data
.i
;
5399 if (aindex
>= mono_array_length_internal ((MonoArray
*)o
))
5400 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
5404 mono_array_set_fast ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
5406 case MINT_STELEM_I1
:
5407 mono_array_set_fast ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
5409 case MINT_STELEM_U1
:
5410 mono_array_set_fast ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
5412 case MINT_STELEM_I2
:
5413 mono_array_set_fast ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
5415 case MINT_STELEM_U2
:
5416 mono_array_set_fast ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
5418 case MINT_STELEM_I4
:
5419 mono_array_set_fast ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
5421 case MINT_STELEM_I8
:
5422 mono_array_set_fast ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
5424 case MINT_STELEM_R4
:
5425 mono_array_set_fast ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f_r4
);
5427 case MINT_STELEM_R8
:
5428 mono_array_set_fast ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
5430 case MINT_STELEM_REF
: {
5431 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.o
, m_class_get_element_class (mono_object_class (o
)), error
);
5432 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5433 if (sp
[2].data
.p
&& !isinst_obj
)
5434 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
5435 mono_array_setref_fast ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
5438 case MINT_STELEM_VT
: {
5439 MonoClass
*klass_vt
= (MonoClass
*)imethod
->data_items
[*(guint16
*) (ip
+ 1)];
5440 i32
= READ32 (ip
+ 2);
5441 char *dst_addr
= mono_array_addr_with_size_fast ((MonoArray
*) o
, i32
, aindex
);
5443 mono_value_copy_internal (dst_addr
, sp
[2].data
.vt
, klass_vt
);
5444 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
5455 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
5456 if (sp
[-1].data
.i
< 0)
5460 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
5461 if (sp
[-1].data
.l
< G_MININT32
|| sp
[-1].data
.l
> G_MAXINT32
)
5463 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5466 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
5467 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT32
)
5469 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
5472 MINT_IN_CASE(MINT_CONV_OVF_I4_R4
)
5473 if (sp
[-1].data
.f_r4
< G_MININT32
|| sp
[-1].data
.f_r4
> G_MAXINT32
)
5475 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f_r4
;
5478 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
5479 if (sp
[-1].data
.f
< G_MININT32
|| sp
[-1].data
.f
> G_MAXINT32
)
5481 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
5484 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
5485 if (sp
[-1].data
.i
< 0)
5489 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
5490 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT32
)
5492 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
5495 MINT_IN_CASE(MINT_CONV_OVF_U4_R4
)
5496 if (sp
[-1].data
.f_r4
< 0 || sp
[-1].data
.f_r4
> G_MAXUINT32
)
5498 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f_r4
;
5501 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
5502 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT32
)
5504 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
5507 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
5508 if (sp
[-1].data
.i
< G_MININT16
|| sp
[-1].data
.i
> G_MAXINT16
)
5512 MINT_IN_CASE(MINT_CONV_OVF_I2_U4
)
5513 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT16
)
5517 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
5518 if (sp
[-1].data
.l
< G_MININT16
|| sp
[-1].data
.l
> G_MAXINT16
)
5520 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5523 MINT_IN_CASE(MINT_CONV_OVF_I2_U8
)
5524 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT16
)
5526 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
5529 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
5530 if (sp
[-1].data
.f
< G_MININT16
|| sp
[-1].data
.f
> G_MAXINT16
)
5532 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5535 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8
)
5536 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT16
)
5538 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
5541 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
5542 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT16
)
5546 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
5547 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT16
)
5549 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
5552 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
5553 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT16
)
5555 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
5558 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
5559 if (sp
[-1].data
.i
< G_MININT8
|| sp
[-1].data
.i
> G_MAXINT8
)
5563 MINT_IN_CASE(MINT_CONV_OVF_I1_U4
)
5564 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXINT8
)
5568 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
5569 if (sp
[-1].data
.l
< G_MININT8
|| sp
[-1].data
.l
> G_MAXINT8
)
5571 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5574 MINT_IN_CASE(MINT_CONV_OVF_I1_U8
)
5575 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXINT8
)
5577 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
5580 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
5581 if (sp
[-1].data
.f
< G_MININT8
|| sp
[-1].data
.f
> G_MAXINT8
)
5583 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5586 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8
)
5587 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXINT8
)
5589 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
5592 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
5593 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> G_MAXUINT8
)
5597 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
5598 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> G_MAXUINT8
)
5600 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
5603 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
5604 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> G_MAXUINT8
)
5606 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
5609 MINT_IN_CASE(MINT_CKFINITE
)
5610 if (!mono_isfinite (sp
[-1].data
.f
))
5611 THROW_EX (mono_get_exception_arithmetic (), ip
);
5614 MINT_IN_CASE(MINT_MKREFANY
) {
5615 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5617 /* The value address is on the stack */
5618 gpointer addr
= sp
[-1].data
.p
;
5619 /* Push the typedref value on the stack */
5620 sp
[-1].data
.p
= vt_sp
;
5621 vt_sp
+= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5623 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5625 tref
->type
= m_class_get_byval_arg (c
);
5631 MINT_IN_CASE(MINT_REFANYTYPE
) {
5632 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5633 MonoType
*type
= tref
->type
;
5635 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5636 sp
[-1].data
.p
= vt_sp
;
5638 *(gpointer
*)sp
[-1].data
.p
= type
;
5642 MINT_IN_CASE(MINT_REFANYVAL
) {
5643 MonoTypedRef
*tref
= (MonoTypedRef
*)sp
[-1].data
.p
;
5644 gpointer addr
= tref
->value
;
5646 c
= (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5647 if (c
!= tref
->klass
)
5648 THROW_EX (mono_get_exception_invalid_cast (), ip
);
5650 vt_sp
-= ALIGN_TO (sizeof (MonoTypedRef
), MINT_VT_ALIGNMENT
);
5652 sp
[-1].data
.p
= addr
;
5656 MINT_IN_CASE(MINT_LDTOKEN
)
5659 * (gpointer
*)sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5663 MINT_IN_CASE(MINT_ADD_OVF_I4
)
5664 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5668 MINT_IN_CASE(MINT_ADD_OVF_I8
)
5669 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5673 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
5674 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5676 BINOP_CAST(i
, +, guint32
);
5678 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
5679 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5681 BINOP_CAST(l
, +, guint64
);
5683 MINT_IN_CASE(MINT_MUL_OVF_I4
)
5684 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5688 MINT_IN_CASE(MINT_MUL_OVF_I8
)
5689 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5693 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
5694 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5696 BINOP_CAST(i
, *, guint32
);
5698 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
5699 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5701 BINOP_CAST(l
, *, guint64
);
5703 MINT_IN_CASE(MINT_SUB_OVF_I4
)
5704 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
5708 MINT_IN_CASE(MINT_SUB_OVF_I8
)
5709 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
5713 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
5714 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
5716 BINOP_CAST(i
, -, guint32
);
5718 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
5719 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
5721 BINOP_CAST(l
, -, guint64
);
5723 MINT_IN_CASE(MINT_START_ABORT_PROT
)
5724 mono_threads_begin_abort_protected_block ();
5727 MINT_IN_CASE(MINT_ENDFINALLY
) {
5729 int clause_index
= *ip
;
5730 gboolean pending_abort
= mono_threads_end_abort_protected_block ();
5732 if (clause_args
&& clause_index
== clause_args
->exit_clause
)
5734 while (sp
> frame
->stack
) {
5737 if (frame
->finally_ips
) {
5738 ip
= (const guint16
*)frame
->finally_ips
->data
;
5739 frame
->finally_ips
= g_slist_remove (frame
->finally_ips
, ip
);
5740 /* Throw abort after the last finally block to avoid confusing EH */
5741 if (pending_abort
&& !frame
->finally_ips
)
5742 EXCEPTION_CHECKPOINT
;
5743 MINT_IN_DISPATCH(*ip
);
5749 MINT_IN_CASE(MINT_LEAVE
)
5750 MINT_IN_CASE(MINT_LEAVE_S
)
5751 MINT_IN_CASE(MINT_LEAVE_CHECK
)
5752 MINT_IN_CASE(MINT_LEAVE_S_CHECK
) {
5753 while (sp
> frame
->stack
) {
5758 if (*ip
== MINT_LEAVE_S_CHECK
|| *ip
== MINT_LEAVE_CHECK
) {
5759 if (imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
5762 child_frame
.parent
= frame
;
5763 child_frame
.imethod
= NULL
;
5765 * We need for mono_thread_get_undeniable_exception to be able to unwind
5766 * to check the abort threshold. For this to work we use child_frame as a
5767 * dummy frame that is stored in the lmf and serves as the transition frame
5769 do_icall_wrapper (&child_frame
, NULL
, MINT_ICALL_V_P
, &tmp_sp
, (gpointer
)mono_thread_get_undeniable_exception
, FALSE
);
5771 MonoException
*abort_exc
= (MonoException
*)tmp_sp
.data
.p
;
5773 THROW_EX (abort_exc
, frame
->ip
);
5777 if (*ip
== MINT_LEAVE_S
|| *ip
== MINT_LEAVE_S_CHECK
) {
5778 ip
+= (short) *(ip
+ 1);
5780 ip
+= (gint32
) READ32 (ip
+ 1);
5782 frame
->endfinally_ip
= ip
;
5785 MonoExceptionClause
*clause
;
5786 GSList
*old_list
= frame
->finally_ips
;
5787 MonoMethod
*method
= imethod
->method
;
5791 g_print ("* Handle finally IL_%04x\n", frame
->endfinally_ip
== NULL
? 0 : frame
->endfinally_ip
- imethod
->code
);
5793 if (imethod
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5794 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5797 ip_offset
= frame
->ip
- imethod
->code
;
5799 if (frame
->endfinally_ip
!= NULL
)
5800 frame
->finally_ips
= g_slist_prepend(frame
->finally_ips
, (void *)frame
->endfinally_ip
);
5802 for (int i
= imethod
->num_clauses
- 1; i
>= 0; i
--) {
5803 clause
= &imethod
->clauses
[i
];
5804 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (frame
->endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, frame
->endfinally_ip
- imethod
->code
)))) {
5805 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5806 ip
= imethod
->code
+ clause
->handler_offset
;
5807 frame
->finally_ips
= g_slist_prepend (frame
->finally_ips
, (gpointer
) ip
);
5810 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
5816 frame
->endfinally_ip
= NULL
;
5818 if (old_list
!= frame
->finally_ips
&& frame
->finally_ips
) {
5819 ip
= (const guint16
*)frame
->finally_ips
->data
;
5820 frame
->finally_ips
= g_slist_remove (frame
->finally_ips
, ip
);
5821 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5822 vt_sp
= (unsigned char *) sp
+ imethod
->stack_size
;
5823 MINT_IN_DISPATCH (*ip
);
5829 MINT_IN_CASE(MINT_ICALL_V_V
)
5830 MINT_IN_CASE(MINT_ICALL_V_P
)
5831 MINT_IN_CASE(MINT_ICALL_P_V
)
5832 MINT_IN_CASE(MINT_ICALL_P_P
)
5833 MINT_IN_CASE(MINT_ICALL_PP_V
)
5834 MINT_IN_CASE(MINT_ICALL_PP_P
)
5835 MINT_IN_CASE(MINT_ICALL_PPP_V
)
5836 MINT_IN_CASE(MINT_ICALL_PPP_P
)
5837 MINT_IN_CASE(MINT_ICALL_PPPP_V
)
5838 MINT_IN_CASE(MINT_ICALL_PPPP_P
)
5839 MINT_IN_CASE(MINT_ICALL_PPPPP_V
)
5840 MINT_IN_CASE(MINT_ICALL_PPPPP_P
)
5841 MINT_IN_CASE(MINT_ICALL_PPPPPP_V
)
5842 MINT_IN_CASE(MINT_ICALL_PPPPPP_P
)
5844 sp
= do_icall_wrapper (frame
, NULL
, *ip
, sp
, imethod
->data_items
[*(guint16
*)(ip
+ 1)], FALSE
);
5845 EXCEPTION_CHECKPOINT
;
5846 CHECK_RESUME_STATE (context
);
5849 MINT_IN_CASE(MINT_MONO_LDPTR
)
5850 sp
->data
.p
= imethod
->data_items
[*(guint16
*)(ip
+ 1)];
5854 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
5855 sp
->data
.p
= mono_object_new_checked (imethod
->domain
, (MonoClass
*)imethod
->data_items
[*(guint16
*)(ip
+ 1)], error
);
5856 mono_error_cleanup (error
); /* FIXME: don't swallow the error */
5860 MINT_IN_CASE(MINT_MONO_FREE
)
5863 g_error ("that doesn't seem right");
5864 g_free (sp
->data
.p
);
5866 MINT_IN_CASE(MINT_MONO_RETOBJ
)
5869 stackval_from_data (mono_method_signature_internal (imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
5870 mono_method_signature_internal (imethod
->method
)->pinvoke
);
5871 if (sp
> frame
->stack
)
5872 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
5874 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO
)
5875 sp
->data
.p
= mono_tls_get_sgen_thread_info ();
5879 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
5881 mono_memory_barrier ();
5884 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
5885 sp
->data
.p
= mono_domain_get ();
5889 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
5890 if (G_UNLIKELY (ss_enabled
)) {
5891 typedef void (*T
) (void);
5895 void *tramp
= mini_get_single_step_trampoline ();
5896 mono_memory_barrier ();
5897 ss_tramp
= (T
)tramp
;
5901 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5902 * the address of that instruction is stored as the seq point address.
5907 * Use the same trampoline as the JIT. This ensures that
5908 * the debugger has the context for the last interpreter
5911 do_debugger_tramp (ss_tramp
, frame
);
5913 CHECK_RESUME_STATE (context
);
5917 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
5918 /* Just a placeholder for a breakpoint */
5921 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
5922 typedef void (*T
) (void);
5925 void *tramp
= mini_get_breakpoint_trampoline ();
5926 mono_memory_barrier ();
5927 bp_tramp
= (T
)tramp
;
5932 /* Use the same trampoline as the JIT */
5933 do_debugger_tramp (bp_tramp
, frame
);
5935 CHECK_RESUME_STATE (context
);
5941 #define RELOP(datamem, op) \
5943 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5946 #define RELOP_FP(datamem, op, noorder) \
5948 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5949 sp [-1].data.i = noorder; \
5951 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5954 MINT_IN_CASE(MINT_CEQ_I4
)
5957 MINT_IN_CASE(MINT_CEQ0_I4
)
5958 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
5961 MINT_IN_CASE(MINT_CEQ_I8
)
5964 MINT_IN_CASE(MINT_CEQ_R4
)
5965 RELOP_FP(f_r4
, ==, 0);
5967 MINT_IN_CASE(MINT_CEQ_R8
)
5970 MINT_IN_CASE(MINT_CNE_I4
)
5973 MINT_IN_CASE(MINT_CNE_I8
)
5976 MINT_IN_CASE(MINT_CNE_R4
)
5977 RELOP_FP(f_r4
, !=, 1);
5979 MINT_IN_CASE(MINT_CNE_R8
)
5982 MINT_IN_CASE(MINT_CGT_I4
)
5985 MINT_IN_CASE(MINT_CGT_I8
)
5988 MINT_IN_CASE(MINT_CGT_R4
)
5989 RELOP_FP(f_r4
, >, 0);
5991 MINT_IN_CASE(MINT_CGT_R8
)
5994 MINT_IN_CASE(MINT_CGE_I4
)
5997 MINT_IN_CASE(MINT_CGE_I8
)
6000 MINT_IN_CASE(MINT_CGE_R4
)
6001 RELOP_FP(f_r4
, >=, 0);
6003 MINT_IN_CASE(MINT_CGE_R8
)
6007 #define RELOP_CAST(datamem, op, type) \
6009 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6012 MINT_IN_CASE(MINT_CGE_UN_I4
)
6013 RELOP_CAST(l
, >=, guint32
);
6015 MINT_IN_CASE(MINT_CGE_UN_I8
)
6016 RELOP_CAST(l
, >=, guint64
);
6019 MINT_IN_CASE(MINT_CGT_UN_I4
)
6020 RELOP_CAST(i
, >, guint32
);
6022 MINT_IN_CASE(MINT_CGT_UN_I8
)
6023 RELOP_CAST(l
, >, guint64
);
6025 MINT_IN_CASE(MINT_CGT_UN_R4
)
6026 RELOP_FP(f_r4
, >, 1);
6028 MINT_IN_CASE(MINT_CGT_UN_R8
)
6031 MINT_IN_CASE(MINT_CLT_I4
)
6034 MINT_IN_CASE(MINT_CLT_I8
)
6037 MINT_IN_CASE(MINT_CLT_R4
)
6038 RELOP_FP(f_r4
, <, 0);
6040 MINT_IN_CASE(MINT_CLT_R8
)
6043 MINT_IN_CASE(MINT_CLT_UN_I4
)
6044 RELOP_CAST(i
, <, guint32
);
6046 MINT_IN_CASE(MINT_CLT_UN_I8
)
6047 RELOP_CAST(l
, <, guint64
);
6049 MINT_IN_CASE(MINT_CLT_UN_R4
)
6050 RELOP_FP(f_r4
, <, 1);
6052 MINT_IN_CASE(MINT_CLT_UN_R8
)
6055 MINT_IN_CASE(MINT_CLE_I4
)
6058 MINT_IN_CASE(MINT_CLE_I8
)
6061 MINT_IN_CASE(MINT_CLE_UN_I4
)
6062 RELOP_CAST(l
, <=, guint32
);
6064 MINT_IN_CASE(MINT_CLE_UN_I8
)
6065 RELOP_CAST(l
, <=, guint64
);
6067 MINT_IN_CASE(MINT_CLE_R4
)
6068 RELOP_FP(f_r4
, <=, 0);
6070 MINT_IN_CASE(MINT_CLE_R8
)
6078 MINT_IN_CASE(MINT_LDFTN
) {
6079 sp
->data
.p
= imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6084 MINT_IN_CASE(MINT_LDVIRTFTN
) {
6085 InterpMethod
*m
= (InterpMethod
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6087 NULL_CHECK (sp
->data
.p
);
6089 sp
->data
.p
= get_virtual_method (m
, sp
->data
.o
->vtable
);
6094 MINT_IN_CASE(MINT_LDFTN_DYNAMIC
) {
6095 MONO_API_ERROR_INIT (error
);
6096 InterpMethod
*m
= mono_interp_get_imethod (mono_domain_get (), (MonoMethod
*) sp
[-1].data
.p
, error
);
6097 mono_error_assert_ok (error
);
6103 #define LDARG(datamem, argtype) \
6104 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6108 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
6109 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
6110 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
6111 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
6112 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
6113 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
6114 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f_r4
, float); MINT_IN_BREAK
;
6115 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
6116 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6117 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
6119 MINT_IN_CASE(MINT_LDARG_VT
)
6121 i32
= READ32(ip
+ 2);
6122 memcpy(sp
->data
.p
, frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
, i32
);
6123 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6128 #define STARG(datamem, argtype) \
6130 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6133 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
6134 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
6135 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
6136 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
6137 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
6138 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
6139 MINT_IN_CASE(MINT_STARG_R4
) STARG(f_r4
, float); MINT_IN_BREAK
;
6140 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
6141 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6142 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
6144 MINT_IN_CASE(MINT_STARG_VT
)
6145 i32
= READ32(ip
+ 2);
6147 memcpy(frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
, sp
->data
.p
, i32
);
6148 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6152 MINT_IN_CASE(MINT_PROF_ENTER
) {
6155 if (MONO_PROFILER_ENABLED (method_enter
)) {
6156 MonoProfilerCallContext
*prof_ctx
= NULL
;
6158 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
6159 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6160 prof_ctx
->interp_frame
= frame
;
6161 prof_ctx
->method
= imethod
->method
;
6164 MONO_PROFILER_RAISE (method_enter
, (imethod
->method
, prof_ctx
));
6172 MINT_IN_CASE(MINT_TRACE_ENTER
) {
6175 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6176 prof_ctx
->interp_frame
= frame
;
6177 prof_ctx
->method
= imethod
->method
;
6179 mono_trace_enter_method (imethod
->method
, prof_ctx
);
6183 MINT_IN_CASE(MINT_TRACE_EXIT
) {
6185 i32
= READ32(ip
+ 1);
6190 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
6192 *frame
->retval
= *sp
;
6194 MonoProfilerCallContext
*prof_ctx
= g_alloca (sizeof (MonoProfilerCallContext
));
6195 prof_ctx
->interp_frame
= frame
;
6196 prof_ctx
->method
= imethod
->method
;
6198 mono_trace_leave_method (imethod
->method
, prof_ctx
);
6203 MINT_IN_CASE(MINT_LDARGA
)
6204 sp
->data
.p
= &frame
->stack_args
[* (guint16
*)(ip
+ 1)];
6209 MINT_IN_CASE(MINT_LDARGA_VT
)
6210 sp
->data
.p
= frame
->stack_args
[* (guint16
*)(ip
+ 1)].data
.p
;
6215 #define LDLOC(datamem, argtype) \
6216 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6220 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
6221 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
6222 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
6223 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
6224 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
6225 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
6226 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f_r4
, float); MINT_IN_BREAK
;
6227 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
6228 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6229 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
6231 MINT_IN_CASE(MINT_LDLOC_VT
)
6233 i32
= READ32(ip
+ 2);
6234 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
6235 vt_sp
+= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6240 MINT_IN_CASE(MINT_LDLOCA_S
)
6241 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
6246 #define STLOC(datamem, argtype) \
6248 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6251 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
6252 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
6253 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
6254 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
6255 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
6256 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
6257 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f_r4
, float); MINT_IN_BREAK
;
6258 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
6259 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6260 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
6262 #define STLOC_NP(datamem, argtype) \
6263 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6266 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
6267 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
6269 MINT_IN_CASE(MINT_STLOC_VT
)
6270 i32
= READ32(ip
+ 2);
6272 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
6273 vt_sp
-= ALIGN_TO (i32
, MINT_VT_ALIGNMENT
);
6277 MINT_IN_CASE(MINT_LOCALLOC
) {
6278 if (sp
!= frame
->stack
+ 1) /*FIX?*/
6279 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
6281 int len
= sp
[-1].data
.i
;
6282 sp
[-1].data
.p
= alloca (len
);
6284 if (imethod
->init_locals
)
6285 memset (sp
[-1].data
.p
, 0, len
);
6289 MINT_IN_CASE(MINT_ENDFILTER
)
6290 /* top of stack is result of filter */
6291 frame
->retval
= &sp
[-1];
6293 MINT_IN_CASE(MINT_INITOBJ
)
6295 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
6298 MINT_IN_CASE(MINT_CPBLK
)
6300 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
6301 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
6303 /* FIXME: value and size may be int64... */
6304 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
6307 MINT_IN_CASE(MINT_CONSTRAINED_
) {
6309 /* FIXME: implement */
6311 token
= READ32 (ip
);
6316 MINT_IN_CASE(MINT_INITBLK
)
6318 NULL_CHECK (sp
[0].data
.p
);
6320 /* FIXME: value and size may be int64... */
6321 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
6324 MINT_IN_CASE(MINT_NO_
)
6325 /* FIXME: implement */
6329 MINT_IN_CASE(MINT_RETHROW
) {
6330 int exvar_offset
= *(guint16
*)(ip
+ 1);
6331 THROW_EX_GENERAL (*(MonoException
**)(frame
->locals
+ exvar_offset
), ip
, TRUE
);
6334 MINT_IN_CASE(MINT_MONO_RETHROW
) {
6336 * need to clarify what this should actually do:
6338 * Takes an exception from the stack and rethrows it.
6339 * This is useful for wrappers that don't want to have to
6340 * use CEE_THROW and lose the exception stacktrace.
6345 sp
->data
.p
= mono_get_exception_null_reference ();
6347 THROW_EX_GENERAL ((MonoException
*)sp
->data
.p
, ip
, TRUE
);
6350 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR
) {
6354 del
= (MonoDelegate
*)sp
->data
.p
;
6355 if (!del
->interp_method
) {
6356 /* Not created from interpreted code */
6357 MONO_API_ERROR_INIT (error
);
6358 g_assert (del
->method
);
6359 del
->interp_method
= mono_interp_get_imethod (del
->object
.vtable
->domain
, del
->method
, error
);
6360 mono_error_assert_ok (error
);
6362 g_assert (del
->interp_method
);
6363 sp
->data
.p
= del
->interp_method
;
6368 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL
) {
6370 int n
= *(guint16
*)(ip
+ 1);
6371 del
= (MonoDelegate
*)sp
[-n
].data
.p
;
6372 if (!del
->interp_invoke_impl
) {
6374 * First time we are called. Set up the invoke wrapper. We might be able to do this
6375 * in ctor but we would need to handle AllocDelegateLike_internal separately
6377 MONO_API_ERROR_INIT (error
);
6378 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (del
->object
.vtable
->klass
);
6379 del
->interp_invoke_impl
= mono_interp_get_imethod (del
->object
.vtable
->domain
, mono_marshal_get_delegate_invoke (invoke
, del
), error
);
6380 mono_error_assert_ok (error
);
6383 sp
[-1].data
.p
= del
->interp_invoke_impl
;
6388 #define MATH_UNOP(mathfunc) \
6389 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6392 MINT_IN_CASE(MINT_ABS
) MATH_UNOP(fabs
); MINT_IN_BREAK
;
6393 MINT_IN_CASE(MINT_ASIN
) MATH_UNOP(asin
); MINT_IN_BREAK
;
6394 MINT_IN_CASE(MINT_ASINH
) MATH_UNOP(asinh
); MINT_IN_BREAK
;
6395 MINT_IN_CASE(MINT_ACOS
) MATH_UNOP(acos
); MINT_IN_BREAK
;
6396 MINT_IN_CASE(MINT_ACOSH
) MATH_UNOP(acosh
); MINT_IN_BREAK
;
6397 MINT_IN_CASE(MINT_ATAN
) MATH_UNOP(atan
); MINT_IN_BREAK
;
6398 MINT_IN_CASE(MINT_ATANH
) MATH_UNOP(atanh
); MINT_IN_BREAK
;
6399 MINT_IN_CASE(MINT_COS
) MATH_UNOP(cos
); MINT_IN_BREAK
;
6400 MINT_IN_CASE(MINT_CBRT
) MATH_UNOP(cbrt
); MINT_IN_BREAK
;
6401 MINT_IN_CASE(MINT_COSH
) MATH_UNOP(cosh
); MINT_IN_BREAK
;
6402 MINT_IN_CASE(MINT_SIN
) MATH_UNOP(sin
); MINT_IN_BREAK
;
6403 MINT_IN_CASE(MINT_SQRT
) MATH_UNOP(sqrt
); MINT_IN_BREAK
;
6404 MINT_IN_CASE(MINT_SINH
) MATH_UNOP(sinh
); MINT_IN_BREAK
;
6405 MINT_IN_CASE(MINT_TAN
) MATH_UNOP(tan
); MINT_IN_BREAK
;
6406 MINT_IN_CASE(MINT_TANH
) MATH_UNOP(tanh
); MINT_IN_BREAK
;
6408 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG
) {
6409 MonoClass
*klass
= (MonoClass
*)imethod
->data_items
[* (guint16
*)(ip
+ 1)];
6410 guint64 a_val
= 0, b_val
= 0;
6412 stackval_to_data (m_class_get_byval_arg (klass
), &sp
[-2], &a_val
, FALSE
);
6413 stackval_to_data (m_class_get_byval_arg (klass
), &sp
[-1], &b_val
, FALSE
);
6415 sp
[-1].data
.i
= (a_val
& b_val
) == b_val
;
6419 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE
) {
6420 sp
[-1].data
.i
= mono_object_hash_internal (sp
[-1].data
.o
);
6424 MINT_IN_CASE(MINT_INTRINS_GET_TYPE
) {
6425 NULL_CHECK (sp
[-1].data
.p
);
6426 sp
[-1].data
.o
= (MonoObject
*) sp
[-1].data
.o
->vtable
->type
;
6432 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-imethod
->code
);
6436 g_assert_not_reached ();
6439 error_init_reuse (error
);
6441 if (clause_args
&& clause_args
->base_frame
)
6442 memcpy (clause_args
->base_frame
->args
, frame
->args
, imethod
->alloca_size
);
6444 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
6445 imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
6446 MonoProfilerCallContext
*prof_ctx
= NULL
;
6448 if (imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
6449 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
6450 prof_ctx
->interp_frame
= frame
;
6451 prof_ctx
->method
= imethod
->method
;
6453 MonoType
*rtype
= mono_method_signature_internal (imethod
->method
)->ret
;
6455 switch (rtype
->type
) {
6456 case MONO_TYPE_VOID
:
6458 case MONO_TYPE_VALUETYPE
:
6459 prof_ctx
->return_value
= frame
->retval
->data
.p
;
6462 prof_ctx
->return_value
= frame
->retval
;
6467 MONO_PROFILER_RAISE (method_leave
, (imethod
->method
, prof_ctx
));
6470 } else if (frame
->ex
&& imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
6471 MONO_PROFILER_RAISE (method_exception_leave
, (imethod
->method
, &frame
->ex
->object
));
6477 interp_parse_options (const char *options
)
6484 args
= g_strsplit (options
, ",", -1);
6485 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
6488 if (strncmp (arg
, "jit=", 4) == 0)
6489 mono_interp_jit_classes
= g_slist_prepend (mono_interp_jit_classes
, arg
+ 4);
6490 if (strncmp (arg
, "interp-only=", 4) == 0)
6491 mono_interp_only_classes
= g_slist_prepend (mono_interp_only_classes
, arg
+ strlen ("interp-only="));
6492 if (strncmp (arg
, "-inline", 7) == 0)
6493 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6498 * interp_set_resume_state:
6500 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6503 interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoJitExceptionInfo
*ei
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
6505 ThreadContext
*context
;
6508 context
= (ThreadContext
*)jit_tls
->interp_context
;
6511 context
->has_resume_state
= TRUE
;
6512 context
->handler_frame
= (InterpFrame
*)interp_frame
;
6513 context
->handler_ei
= ei
;
6514 /* This is on the stack, so it doesn't need a wbarrier */
6515 context
->handler_frame
->ex
= ex
;
6518 *(MonoException
**)(context
->handler_frame
->locals
+ ei
->exvar_offset
) = ex
;
6519 context
->handler_ip
= (guint16
*) handler_ip
;
6523 * interp_run_finally:
6525 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6526 * frame->interp_frame.
6527 * Return TRUE if the finally clause threw an exception.
6530 interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6532 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6533 ThreadContext
*context
= get_context ();
6534 const unsigned short *old_ip
= iframe
->ip
;
6535 FrameClauseArgs clause_args
;
6537 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6538 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6539 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6540 clause_args
.exit_clause
= clause_index
;
6543 interp_exec_method_full (iframe
, context
, &clause_args
, error
);
6544 if (context
->has_resume_state
) {
6547 iframe
->ip
= old_ip
;
6553 * interp_run_filter:
6555 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6556 * frame->interp_frame.
6559 interp_run_filter (StackFrameInfo
*frame
, MonoException
*ex
, int clause_index
, gpointer handler_ip
, gpointer handler_ip_end
)
6561 InterpFrame
*iframe
= (InterpFrame
*)frame
->interp_frame
;
6562 ThreadContext
*context
= get_context ();
6563 InterpFrame child_frame
;
6565 FrameClauseArgs clause_args
;
6568 * Have to run the clause in a new frame which is a copy of IFRAME, since
6569 * during debugging, there are two copies of the frame on the stack.
6571 memset (&child_frame
, 0, sizeof (InterpFrame
));
6572 child_frame
.imethod
= iframe
->imethod
;
6573 child_frame
.retval
= &retval
;
6574 child_frame
.parent
= iframe
;
6575 child_frame
.stack_args
= iframe
->stack_args
;
6577 memset (&clause_args
, 0, sizeof (FrameClauseArgs
));
6578 clause_args
.start_with_ip
= (guint16
*) handler_ip
;
6579 clause_args
.end_at_ip
= (guint16
*) handler_ip_end
;
6580 clause_args
.filter_exception
= ex
;
6581 clause_args
.base_frame
= iframe
;
6584 interp_exec_method_full (&child_frame
, context
, &clause_args
, error
);
6585 /* ENDFILTER stores the result into child_frame->retval */
6586 return child_frame
.retval
->data
.i
? TRUE
: FALSE
;
6590 InterpFrame
*current
;
6594 * interp_frame_iter_init:
6596 * Initialize an iterator for iterating through interpreted frames.
6599 interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
6601 StackIter
*stack_iter
= (StackIter
*)iter
;
6603 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
6607 * interp_frame_iter_next:
6609 * Fill out FRAME with date for the next interpreter frame.
6612 interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
6614 StackIter
*stack_iter
= (StackIter
*)iter
;
6615 InterpFrame
*iframe
= stack_iter
->current
;
6617 memset (frame
, 0, sizeof (StackFrameInfo
));
6618 /* pinvoke frames doesn't have imethod set */
6619 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
&& iframe
->imethod
->jinfo
))
6620 iframe
= iframe
->parent
;
6624 MonoMethod
*method
= iframe
->imethod
->method
;
6625 frame
->domain
= iframe
->imethod
->domain
;
6626 frame
->interp_frame
= iframe
;
6627 frame
->method
= method
;
6628 frame
->actual_method
= method
;
6629 if (method
&& ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)))) {
6630 frame
->native_offset
= -1;
6631 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
6633 frame
->type
= FRAME_TYPE_INTERP
;
6634 /* This is the offset in the interpreter IR */
6635 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
6636 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6637 frame
->managed
= TRUE
;
6639 frame
->ji
= iframe
->imethod
->jinfo
;
6640 frame
->frame_addr
= iframe
;
6642 stack_iter
->current
= iframe
->parent
;
6648 interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
6650 InterpMethod
* imethod
;
6652 imethod
= lookup_imethod (domain
, method
);
6654 return imethod
->jinfo
;
6660 interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6662 guint16
*code
= (guint16
*)ip
;
6663 g_assert (*code
== MINT_SDB_SEQ_POINT
);
6664 *code
= MINT_SDB_BREAKPOINT
;
6668 interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
6670 guint16
*code
= (guint16
*)ip
;
6671 g_assert (*code
== MINT_SDB_BREAKPOINT
);
6672 *code
= MINT_SDB_SEQ_POINT
;
6676 interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
6678 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6680 g_assert (iframe
->imethod
);
6681 return iframe
->imethod
->jinfo
;
6685 interp_frame_get_ip (MonoInterpFrameHandle frame
)
6687 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6689 g_assert (iframe
->imethod
);
6690 return (gpointer
)iframe
->ip
;
6694 interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
6696 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6697 MonoMethodSignature
*sig
;
6699 g_assert (iframe
->imethod
);
6701 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6702 return stackval_to_data_addr (sig
->params
[pos
], &iframe
->stack_args
[pos
+ !!iframe
->imethod
->hasthis
]);
6706 interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
6708 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6710 g_assert (iframe
->imethod
);
6712 return iframe
->locals
+ iframe
->imethod
->local_offsets
[pos
];
6716 interp_frame_get_this (MonoInterpFrameHandle frame
)
6718 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6720 g_assert (iframe
->imethod
);
6721 g_assert (iframe
->imethod
->hasthis
);
6722 return &iframe
->stack_args
[0].data
.p
;
6725 static MonoInterpFrameHandle
6726 interp_frame_get_parent (MonoInterpFrameHandle frame
)
6728 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6730 return iframe
->parent
;
6734 interp_frame_get_res (MonoInterpFrameHandle frame
)
6736 InterpFrame
*iframe
= (InterpFrame
*)frame
;
6737 MonoMethodSignature
*sig
;
6739 g_assert (iframe
->imethod
);
6740 sig
= mono_method_signature_internal (iframe
->imethod
->method
);
6741 if (sig
->ret
->type
== MONO_TYPE_VOID
)
6744 return stackval_to_data_addr (sig
->ret
, iframe
->retval
);
6748 interp_start_single_stepping (void)
6754 interp_stop_single_stepping (void)
6760 register_interp_stats (void)
6762 mono_counters_init ();
6763 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP
| MONO_COUNTER_LONG
| MONO_COUNTER_TIME
, &mono_interp_stats
.transform_time
);
6764 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inlined_methods
);
6765 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP
| MONO_COUNTER_INT
, &mono_interp_stats
.inline_failures
);
6768 #undef MONO_EE_CALLBACK
6769 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6771 static const MonoEECallbacks mono_interp_callbacks
= {
6776 mono_ee_interp_init (const char *opts
)
6778 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION
);
6779 g_assert (!interp_init_done
);
6780 interp_init_done
= TRUE
;
6782 mono_native_tls_alloc (&thread_context_id
, NULL
);
6785 interp_parse_options (opts
);
6786 if (mini_get_debug_options ()->mdb_optimizations
)
6787 mono_interp_opt
&= ~INTERP_OPT_INLINE
;
6788 mono_interp_transform_init ();
6790 mini_install_interp_callbacks (&mono_interp_callbacks
);
6792 register_interp_stats ();