3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001, 2002 Ximian, Inc.
27 #include <mono/utils/gc_wrapper.h>
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/reflection-internals.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/utils/atomic.h>
62 #include "interp-internals.h"
66 #include <mono/mini/mini.h>
67 #include <mono/mini/jit-icalls.h>
68 #include <mono/mini/debugger-agent.h>
71 #include <mono/mini/mini-arm.h>
74 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
77 #define finite _finite
81 #define finite isfinite
86 init_frame (InterpFrame
*frame
, InterpFrame
*parent_frame
, InterpMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
88 frame
->parent
= parent_frame
;
89 frame
->stack_args
= method_args
;
90 frame
->retval
= method_retval
;
91 frame
->imethod
= rmethod
;
94 frame
->invoke_trap
= 0;
97 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
98 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
99 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
103 * List of classes whose methods will be executed by transitioning to JITted code.
107 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
108 static gboolean ss_enabled
;
110 static char* dump_frame (InterpFrame
*inv
);
111 static MonoArray
*get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
);
112 static void ves_exec_method_with_context (InterpFrame
*frame
, ThreadContext
*context
, unsigned short *start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
);
114 typedef void (*ICallMethod
) (InterpFrame
*frame
);
116 static guint32 die_on_exception
= 0;
117 static MonoNativeTlsKey thread_context_id
;
119 static char* dump_args (InterpFrame
*inv
);
121 #define DEBUG_INTERP 0
124 int mono_interp_traceopt
= 2;
125 /* If true, then we output the opcodes as we interpret them */
126 static int global_tracing
= 2;
128 static int debug_indent_level
= 0;
130 static int break_on_method
= 0;
131 static int nested_trace
= 0;
132 static GList
*db_methods
= NULL
;
139 for (h
= 0; h
< debug_indent_level
; h
++)
144 db_match_method (gpointer data
, gpointer user_data
)
146 MonoMethod
*m
= (MonoMethod
*)user_data
;
147 MonoMethodDesc
*desc
= data
;
149 if (mono_method_desc_full_match (desc
, m
))
154 debug_enter (InterpFrame
*frame
, int *tracing
)
157 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->imethod
->method
);
159 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
163 MonoMethod
*method
= frame
->imethod
->method
;
164 char *mn
, *args
= dump_args (frame
);
165 debug_indent_level
++;
167 mn
= mono_method_full_name (method
, FALSE
);
168 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
170 g_print ("%s)\n", args
);
176 #define DEBUG_LEAVE() \
179 args = dump_retval (frame); \
181 mn = mono_method_full_name (frame->imethod->method, FALSE); \
182 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
184 g_print (" => %s\n", args); \
186 debug_indent_level--; \
187 if (tracing == 3) global_tracing = 0; \
192 int mono_interp_traceopt
= 0;
193 static void debug_enter (InterpFrame
*frame
, int *tracing
)
196 #define DEBUG_LEAVE()
200 /* Set the current execution state to the resume state in context */
201 #define SET_RESUME_STATE(context) do { \
202 ip = (context)->handler_ip; \
204 sp->data.p = frame->ex; \
208 (context)->has_resume_state = 0; \
209 (context)->handler_frame = NULL; \
214 set_context (ThreadContext
*context
)
216 MonoJitTlsData
*jit_tls
;
218 mono_native_tls_set_value (thread_context_id
, context
);
219 jit_tls
= mono_tls_get_jit_tls ();
221 jit_tls
->interp_context
= context
;
225 ves_real_abort (int line
, MonoMethod
*mh
,
226 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
229 MonoMethodHeader
*header
= mono_method_get_header_checked (mh
, &error
);
230 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
231 g_printerr ("Execution aborted in method: %s::%s\n", mh
->klass
->name
, mh
->name
);
232 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line
, ip
-(const unsigned short *) header
->code
);
233 g_print ("0x%04x %02x\n", ip
-(const unsigned short *) header
->code
, *ip
);
234 mono_metadata_free_mh (header
);
236 printf ("\t[%ld] 0x%08x %0.5f\n", sp
-stack
, sp
[-1].data
.i
, sp
[-1].data
.f
);
239 #define ves_abort() \
241 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
242 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
246 lookup_imethod (MonoDomain
*domain
, MonoMethod
*method
)
249 MonoJitDomainInfo
*info
;
251 info
= domain_jit_info (domain
);
252 mono_domain_jit_code_hash_lock (domain
);
253 rtm
= mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
254 mono_domain_jit_code_hash_unlock (domain
);
258 #ifndef DISABLE_REMOTING
260 mono_interp_get_remoting_invoke (gpointer imethod
, MonoError
*error
)
262 InterpMethod
*imethod_cast
= (InterpMethod
*) imethod
;
264 g_assert (mono_use_interpreter
);
266 return mono_interp_get_imethod (mono_domain_get (), mono_marshal_get_remoting_invoke (imethod_cast
->method
), error
);
271 mono_interp_get_imethod (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
274 MonoJitDomainInfo
*info
;
275 MonoMethodSignature
*sig
;
280 info
= domain_jit_info (domain
);
281 mono_domain_jit_code_hash_lock (domain
);
282 rtm
= mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
283 mono_domain_jit_code_hash_unlock (domain
);
287 sig
= mono_method_signature (method
);
289 rtm
= mono_domain_alloc0 (domain
, sizeof (InterpMethod
));
290 rtm
->method
= method
;
291 rtm
->domain
= domain
;
292 rtm
->param_count
= sig
->param_count
;
293 rtm
->hasthis
= sig
->hasthis
;
294 rtm
->rtype
= mini_get_underlying_type (sig
->ret
);
295 rtm
->param_types
= mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
296 for (i
= 0; i
< sig
->param_count
; ++i
)
297 rtm
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
299 mono_domain_jit_code_hash_lock (domain
);
300 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
301 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, rtm
);
302 mono_domain_jit_code_hash_unlock (domain
);
304 rtm
->prof_flags
= mono_profiler_get_call_instrumentation_flags (rtm
->method
);
310 mono_interp_create_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
312 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
313 method
= mono_marshal_get_synchronized_wrapper (method
);
314 return mono_interp_get_imethod (domain
, method
, error
);
320 * Push an LMF frame on the LMF stack
321 * to mark the transition to native code.
322 * This is needed for the native code to
323 * be able to do stack walks.
326 interp_push_lmf (MonoLMFExt
*ext
, InterpFrame
*frame
)
328 memset (ext
, 0, sizeof (MonoLMFExt
));
329 ext
->interp_exit
= TRUE
;
330 ext
->interp_exit_data
= frame
;
336 interp_pop_lmf (MonoLMFExt
*ext
)
338 mono_pop_lmf (&ext
->lmf
);
341 static inline InterpMethod
*
342 get_virtual_method (InterpMethod
*imethod
, MonoObject
*obj
)
344 MonoMethod
*m
= imethod
->method
;
345 MonoDomain
*domain
= imethod
->domain
;
346 InterpMethod
*ret
= NULL
;
349 #ifndef DISABLE_REMOTING
350 if (mono_object_is_transparent_proxy (obj
)) {
351 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_remoting_invoke (m
), &error
);
352 mono_error_assert_ok (&error
);
357 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
358 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
359 ret
= mono_interp_get_imethod (domain
, mono_marshal_get_synchronized_wrapper (m
), &error
);
360 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
367 mono_class_setup_vtable (obj
->vtable
->klass
);
369 int slot
= mono_method_get_vtable_slot (m
);
370 if (mono_class_is_interface (m
->klass
)) {
371 g_assert (obj
->vtable
->klass
!= m
->klass
);
372 /* TODO: interface offset lookup is slow, go through IMT instead */
373 gboolean non_exact_match
;
374 slot
+= mono_class_interface_offset_with_variance (obj
->vtable
->klass
, m
->klass
, &non_exact_match
);
377 MonoMethod
*virtual_method
= obj
->vtable
->klass
->vtable
[slot
];
378 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
379 MonoGenericContext context
= { NULL
, NULL
};
381 if (mono_class_is_ginst (virtual_method
->klass
))
382 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
383 else if (mono_class_is_gtd (virtual_method
->klass
))
384 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
385 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
387 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, &error
);
388 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
391 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
392 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
395 InterpMethod
*virtual_imethod
= mono_interp_get_imethod (domain
, virtual_method
, &error
);
396 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
397 return virtual_imethod
;
401 stackval_from_data (MonoType
*type_
, stackval
*result
, char *data
, gboolean pinvoke
)
403 MonoType
*type
= mini_native_type_replace_type (type_
);
405 switch (type
->type
) {
406 case MONO_TYPE_OBJECT
:
407 case MONO_TYPE_CLASS
:
408 case MONO_TYPE_STRING
:
409 case MONO_TYPE_ARRAY
:
410 case MONO_TYPE_SZARRAY
:
415 result
->data
.p
= *(gpointer
*)data
;
418 switch (type
->type
) {
422 result
->data
.i
= *(gint8
*)data
;
425 case MONO_TYPE_BOOLEAN
:
426 result
->data
.i
= *(guint8
*)data
;
429 result
->data
.i
= *(gint16
*)data
;
433 result
->data
.i
= *(guint16
*)data
;
436 result
->data
.i
= *(gint32
*)data
;
440 result
->data
.nati
= *(mono_i
*)data
;
443 result
->data
.p
= *(gpointer
*)data
;
446 result
->data
.i
= *(guint32
*)data
;
450 /* memmove handles unaligned case */
451 memmove (&tmp
, data
, sizeof (float));
452 result
->data
.f
= tmp
;
457 memmove (&result
->data
.l
, data
, sizeof (gint64
));
460 memmove (&result
->data
.f
, data
, sizeof (double));
462 case MONO_TYPE_STRING
:
463 case MONO_TYPE_SZARRAY
:
464 case MONO_TYPE_CLASS
:
465 case MONO_TYPE_OBJECT
:
466 case MONO_TYPE_ARRAY
:
467 result
->data
.p
= *(gpointer
*)data
;
469 case MONO_TYPE_VALUETYPE
:
470 if (type
->data
.klass
->enumtype
) {
471 stackval_from_data (mono_class_enum_basetype (type
->data
.klass
), result
, data
, pinvoke
);
474 mono_value_copy (result
->data
.vt
, data
, type
->data
.klass
);
476 case MONO_TYPE_GENERICINST
: {
477 if (mono_type_generic_inst_is_valuetype (type
)) {
478 mono_value_copy (result
->data
.vt
, data
, mono_class_from_mono_type (type
));
481 stackval_from_data (&type
->data
.generic_class
->container_class
->byval_arg
, result
, data
, pinvoke
);
485 g_warning ("got type 0x%02x", type
->type
);
486 g_assert_not_reached ();
491 stackval_to_data (MonoType
*type_
, stackval
*val
, char *data
, gboolean pinvoke
)
493 MonoType
*type
= mini_native_type_replace_type (type_
);
495 gpointer
*p
= (gpointer
*)data
;
499 /* printf ("TODAT0 %p\n", data); */
500 switch (type
->type
) {
503 guint8
*p
= (guint8
*)data
;
507 case MONO_TYPE_BOOLEAN
: {
508 guint8
*p
= (guint8
*)data
;
509 *p
= (val
->data
.i
!= 0);
514 case MONO_TYPE_CHAR
: {
515 guint16
*p
= (guint16
*)data
;
520 mono_i
*p
= (mono_i
*)data
;
521 /* In theory the value used by stloc should match the local var type
522 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
523 a native int - both by csc and mcs). Not sure what to do about sign extension
524 as it is outside the spec... doing the obvious */
525 *p
= (mono_i
)val
->data
.nati
;
529 mono_u
*p
= (mono_u
*)data
;
531 *p
= (mono_u
)val
->data
.nati
;
536 gint32
*p
= (gint32
*)data
;
542 gint64
*p
= (gint64
*)data
;
547 float *p
= (float*)data
;
552 double *p
= (double*)data
;
556 case MONO_TYPE_STRING
:
557 case MONO_TYPE_SZARRAY
:
558 case MONO_TYPE_CLASS
:
559 case MONO_TYPE_OBJECT
:
560 case MONO_TYPE_ARRAY
: {
561 gpointer
*p
= (gpointer
*) data
;
562 mono_gc_wbarrier_generic_store (p
, val
->data
.p
);
565 case MONO_TYPE_PTR
: {
566 gpointer
*p
= (gpointer
*) data
;
570 case MONO_TYPE_VALUETYPE
:
571 if (type
->data
.klass
->enumtype
) {
572 stackval_to_data (mono_class_enum_basetype (type
->data
.klass
), val
, data
, pinvoke
);
575 mono_value_copy (data
, val
->data
.vt
, type
->data
.klass
);
577 case MONO_TYPE_GENERICINST
: {
578 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
580 if (container_class
->valuetype
&& !container_class
->enumtype
) {
581 mono_value_copy (data
, val
->data
.vt
, mono_class_from_mono_type (type
));
584 stackval_to_data (&type
->data
.generic_class
->container_class
->byval_arg
, val
, data
, pinvoke
);
588 g_warning ("got type %x", type
->type
);
589 g_assert_not_reached ();
594 fill_in_trace (MonoException
*exception
, InterpFrame
*frame
)
597 char *stack_trace
= dump_frame (frame
);
598 MonoDomain
*domain
= frame
->imethod
->domain
;
599 (exception
)->stack_trace
= mono_string_new_checked (domain
, stack_trace
, &error
);
600 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
601 (exception
)->trace_ips
= get_trace_ips (domain
, frame
);
602 g_free (stack_trace
);
605 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
607 #define THROW_EX_GENERAL(exception,ex_ip,rethrow) \
609 frame->ip = (ex_ip); \
610 frame->ex = (MonoException*)(exception); \
612 FILL_IN_TRACE(frame->ex, frame); \
614 MONO_PROFILER_RAISE (exception_throw, ((MonoObject *) exception)); \
615 goto handle_exception; \
618 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
621 ves_array_create (InterpFrame
*frame
, MonoDomain
*domain
, MonoClass
*klass
, MonoMethodSignature
*sig
, stackval
*values
)
624 intptr_t *lower_bounds
;
629 lengths
= alloca (sizeof (uintptr_t) * klass
->rank
* 2);
630 for (i
= 0; i
< sig
->param_count
; ++i
) {
631 lengths
[i
] = values
->data
.i
;
634 if (klass
->rank
== sig
->param_count
) {
635 /* Only lengths provided. */
638 /* lower bounds are first. */
639 lower_bounds
= (intptr_t *) lengths
;
640 lengths
+= klass
->rank
;
642 obj
= (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, &error
);
643 if (!mono_error_ok (&error
)) {
644 frame
->ex
= mono_error_convert_to_exception (&error
);
645 FILL_IN_TRACE (frame
->ex
, frame
);
647 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
652 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, InterpFrame
*frame
, gboolean safe
)
654 g_assert (!frame
->ex
);
655 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
659 for (gint32 i
= 0; i
< ac
->rank
; i
++) {
660 guint32 idx
= sp
[i
].data
.i
;
661 guint32 lower
= ao
->bounds
[i
].lower_bound
;
662 guint32 len
= ao
->bounds
[i
].length
;
663 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
664 frame
->ex
= mono_get_exception_index_out_of_range ();
665 FILL_IN_TRACE (frame
->ex
, frame
);
668 pos
= (pos
* len
) + idx
- lower
;
672 if (safe
&& pos
>= ao
->max_length
) {
673 frame
->ex
= mono_get_exception_index_out_of_range ();
674 FILL_IN_TRACE (frame
->ex
, frame
);
682 ves_array_set (InterpFrame
*frame
)
684 stackval
*sp
= frame
->stack_args
+ 1;
686 MonoObject
*o
= frame
->stack_args
->data
.p
;
687 MonoArray
*ao
= (MonoArray
*) o
;
688 MonoClass
*ac
= o
->vtable
->klass
;
690 g_assert (ac
->rank
>= 1);
692 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
696 if (sp
[ac
->rank
].data
.p
&& !mono_object_class (o
)->element_class
->valuetype
) {
698 MonoObject
*isinst
= mono_object_isinst_checked (sp
[ac
->rank
].data
.p
, mono_object_class (o
)->element_class
, &error
);
699 mono_error_cleanup (&error
);
701 frame
->ex
= mono_get_exception_array_type_mismatch ();
702 FILL_IN_TRACE (frame
->ex
, frame
);
707 gint32 esize
= mono_array_element_size (ac
);
708 gpointer ea
= mono_array_addr_with_size (ao
, esize
, pos
);
710 MonoType
*mt
= mono_method_signature (frame
->imethod
->method
)->params
[ac
->rank
];
711 stackval_to_data (mt
, &sp
[ac
->rank
], ea
, FALSE
);
715 ves_array_get (InterpFrame
*frame
, gboolean safe
)
717 stackval
*sp
= frame
->stack_args
+ 1;
719 MonoObject
*o
= frame
->stack_args
->data
.p
;
720 MonoArray
*ao
= (MonoArray
*) o
;
721 MonoClass
*ac
= o
->vtable
->klass
;
723 g_assert (ac
->rank
>= 1);
725 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, safe
);
729 gint32 esize
= mono_array_element_size (ac
);
730 gpointer ea
= mono_array_addr_with_size (ao
, esize
, pos
);
732 MonoType
*mt
= mono_method_signature (frame
->imethod
->method
)->ret
;
733 stackval_from_data (mt
, frame
->retval
, ea
, FALSE
);
737 ves_array_element_address (InterpFrame
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
739 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
741 g_assert (ac
->rank
>= 1);
743 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
747 if (needs_typecheck
&& !mono_class_is_assignable_from (mono_object_class ((MonoObject
*) ao
)->element_class
, required_type
->element_class
)) {
748 frame
->ex
= mono_get_exception_array_type_mismatch ();
749 FILL_IN_TRACE (frame
->ex
, frame
);
752 gint32 esize
= mono_array_element_size (ac
);
753 return mono_array_addr_with_size (ao
, esize
, pos
);
757 interp_walk_stack_with_ctx (MonoInternalStackWalk func
, MonoContext
*ctx
, MonoUnwindOptions options
, void *user_data
)
759 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
764 InterpFrame
*frame
= context
->current_frame
;
767 MonoStackFrameInfo fi
;
768 memset (&fi
, 0, sizeof (MonoStackFrameInfo
));
770 /* TODO: hack to make some asserts happy. */
771 fi
.ji
= (MonoJitInfo
*) frame
->imethod
;
774 fi
.method
= fi
.actual_method
= frame
->imethod
->method
;
776 if (!fi
.method
|| (fi
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (fi
.method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
777 fi
.native_offset
= -1;
778 fi
.type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
780 fi
.type
= FRAME_TYPE_MANAGED
;
781 fi
.native_offset
= frame
->ip
- frame
->imethod
->code
;
782 if (!fi
.method
->wrapper_type
)
786 if (func (&fi
, ctx
, user_data
))
788 frame
= frame
->parent
;
792 static MonoPIFunc mono_interp_enter_icall_trampoline
= NULL
;
794 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, InterpFrame
*frame
)
796 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
799 g_assert (mono_arm_eabi_supported ());
800 int i8_align
= mono_arm_i8_align ();
810 for (int i
= 0; i
< sig
->param_count
; i
++) {
811 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
813 case MONO_TYPE_BOOLEAN
:
824 case MONO_TYPE_SZARRAY
:
825 case MONO_TYPE_CLASS
:
826 case MONO_TYPE_OBJECT
:
827 case MONO_TYPE_STRING
:
828 case MONO_TYPE_VALUETYPE
:
829 case MONO_TYPE_GENERICINST
:
830 #if SIZEOF_VOID_P == 8
835 #if SIZEOF_VOID_P == 4
838 /* pairs begin at even registers */
839 if (i8_align
== 8 && margs
->ilen
& 1)
846 #if SIZEOF_VOID_P == 8
851 #if SIZEOF_VOID_P == 4
857 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
862 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
865 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
867 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
868 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
870 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
871 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
878 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
882 for (int i
= 0; i
< sig
->param_count
; i
++) {
883 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
885 case MONO_TYPE_BOOLEAN
:
896 case MONO_TYPE_SZARRAY
:
897 case MONO_TYPE_CLASS
:
898 case MONO_TYPE_OBJECT
:
899 case MONO_TYPE_STRING
:
900 case MONO_TYPE_VALUETYPE
:
901 case MONO_TYPE_GENERICINST
:
902 #if SIZEOF_VOID_P == 8
905 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
907 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
911 #if SIZEOF_VOID_P == 4
913 stackval
*sarg
= &frame
->stack_args
[i
];
915 /* pairs begin at even registers */
916 if (i8_align
== 8 && int_i
& 1)
919 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.lo
;
921 margs
->iargs
[int_i
] = (gpointer
) sarg
->data
.pair
.hi
;
923 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
);
931 if (ptype
== MONO_TYPE_R4
)
932 * (float *) &(margs
->fargs
[int_f
]) = (float) frame
->stack_args
[i
].data
.f
;
934 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
936 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
);
938 #if SIZEOF_VOID_P == 4
945 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
949 switch (sig
->ret
->type
) {
950 case MONO_TYPE_BOOLEAN
:
961 case MONO_TYPE_SZARRAY
:
962 case MONO_TYPE_CLASS
:
963 case MONO_TYPE_OBJECT
:
964 case MONO_TYPE_STRING
:
966 case MONO_TYPE_VALUETYPE
:
967 case MONO_TYPE_GENERICINST
:
968 margs
->retval
= &(frame
->retval
->data
.p
);
969 margs
->is_float_ret
= 0;
973 margs
->retval
= &(frame
->retval
->data
.p
);
974 margs
->is_float_ret
= 1;
977 margs
->retval
= NULL
;
980 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
987 ves_pinvoke_method (InterpFrame
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
)
993 g_assert (!frame
->imethod
);
994 if (!mono_interp_enter_icall_trampoline
) {
996 mono_interp_enter_icall_trampoline
= mono_aot_get_trampoline ("enter_icall_trampoline");
999 mono_interp_enter_icall_trampoline
= mono_arch_get_enter_icall_trampoline (&info
);
1001 // mono_tramp_info_register (info, NULL);
1005 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
1007 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline
, addr
);
1008 g_print ("margs(out): ilen=%d, flen=%d\n", margs
->ilen
, margs
->flen
);
1011 context
->current_frame
= frame
;
1013 interp_push_lmf (&ext
, frame
);
1014 mono_interp_enter_icall_trampoline (addr
, margs
);
1015 interp_pop_lmf (&ext
);
1017 if (*mono_thread_interruption_request_flag ()) {
1018 MonoException
*exc
= mono_thread_interruption_checkpoint ();
1021 context
->search_for_handler
= 1;
1025 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
1026 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
1028 g_free (margs
->iargs
);
1029 g_free (margs
->fargs
);
1034 mono_interp_init_delegate (MonoDelegate
*del
)
1038 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
1039 del
->method
= ((InterpMethod
*) del
->method_ptr
)->method
;
1044 * runtime specifies that the implementation of the method is automatically
1045 * provided by the runtime and is primarily used for the methods of delegates.
1048 ves_imethod (InterpFrame
*frame
, ThreadContext
*context
)
1050 MonoMethod
*method
= frame
->imethod
->method
;
1051 const char *name
= method
->name
;
1052 MonoObject
*obj
= (MonoObject
*) frame
->stack_args
->data
.p
;
1053 MonoObject
*isinst_obj
;
1056 mono_class_init (method
->klass
);
1058 if (method
->klass
== mono_defaults
.array_class
) {
1059 if (!strcmp (method
->name
, "UnsafeMov")) {
1060 /* TODO: layout checks */
1061 MonoType
*mt
= mono_method_signature (method
)->ret
;
1062 stackval_from_data (mt
, frame
->retval
, (char *) frame
->stack_args
, FALSE
);
1065 if (!strcmp (method
->name
, "UnsafeLoad")) {
1066 ves_array_get (frame
, FALSE
);
1071 isinst_obj
= mono_object_isinst_checked (obj
, mono_defaults
.array_class
, &error
);
1072 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
1073 if (obj
&& isinst_obj
) {
1074 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
1075 ves_array_set (frame
);
1078 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
1079 ves_array_get (frame
, TRUE
);
1084 g_error ("Don't know how to exec runtime method %s.%s::%s",
1085 method
->klass
->name_space
, method
->klass
->name
,
1091 dump_stack (stackval
*stack
, stackval
*sp
)
1093 stackval
*s
= stack
;
1094 GString
*str
= g_string_new ("");
1097 return g_string_free (str
, FALSE
);
1100 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1103 return g_string_free (str
, FALSE
);
1108 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1110 switch (type
->type
) {
1117 case MONO_TYPE_CHAR
:
1118 case MONO_TYPE_BOOLEAN
:
1119 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1121 case MONO_TYPE_STRING
:
1122 case MONO_TYPE_SZARRAY
:
1123 case MONO_TYPE_CLASS
:
1124 case MONO_TYPE_OBJECT
:
1125 case MONO_TYPE_ARRAY
:
1129 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1131 case MONO_TYPE_VALUETYPE
:
1132 if (type
->data
.klass
->enumtype
)
1133 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1135 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1139 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1144 GString
*res
= g_string_new ("");
1145 mono_type_get_desc (res
, type
, TRUE
);
1146 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1147 g_string_free (res
, TRUE
);
1155 dump_retval (InterpFrame
*inv
)
1157 GString
*str
= g_string_new ("");
1158 MonoType
*ret
= mono_method_signature (inv
->imethod
->method
)->ret
;
1160 if (ret
->type
!= MONO_TYPE_VOID
)
1161 dump_stackval (str
, inv
->retval
, ret
);
1163 return g_string_free (str
, FALSE
);
1168 dump_args (InterpFrame
*inv
)
1170 GString
*str
= g_string_new ("");
1172 MonoMethodSignature
*signature
= mono_method_signature (inv
->imethod
->method
);
1174 if (signature
->param_count
== 0 && !signature
->hasthis
)
1175 return g_string_free (str
, FALSE
);
1177 if (signature
->hasthis
) {
1178 MonoMethod
*method
= inv
->imethod
->method
;
1179 dump_stackval (str
, inv
->stack_args
, &method
->klass
->byval_arg
);
1182 for (i
= 0; i
< signature
->param_count
; ++i
)
1183 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1185 return g_string_free (str
, FALSE
);
1189 dump_frame (InterpFrame
*inv
)
1191 GString
*str
= g_string_new ("");
1196 for (i
= 0; inv
; inv
= inv
->parent
) {
1197 if (inv
->imethod
!= NULL
) {
1198 MonoMethod
*method
= inv
->imethod
->method
;
1202 const char * opname
= "";
1204 gchar
*source
= NULL
;
1208 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1209 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) == 0) {
1210 MonoMethodHeader
*hd
= mono_method_get_header_checked (method
, &error
);
1211 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
1215 opname
= mono_interp_opname
[*inv
->ip
];
1216 codep
= inv
->ip
- inv
->imethod
->code
;
1217 source
= g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method
->name
, codep
);
1222 MonoDebugSourceLocation
*minfo
= mono_debug_lookup_method (method
);
1223 source
= mono_debug_method_lookup_location (minfo
, codep
);
1225 mono_metadata_free_mh (hd
);
1228 args
= dump_args (inv
);
1229 name
= mono_method_full_name (method
, TRUE
);
1231 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i
, codep
, opname
, name
, args
, source
);
1233 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s)\n", i
, codep
, opname
, name
, args
);
1240 return g_string_free (str
, FALSE
);
1244 get_trace_ips (MonoDomain
*domain
, InterpFrame
*top
)
1251 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1252 if (inv
->imethod
!= NULL
)
1255 res
= mono_array_new_checked (domain
, mono_defaults
.int_class
, 2 * i
, &error
);
1256 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
1258 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1259 if (inv
->imethod
!= NULL
) {
1260 mono_array_set (res
, gpointer
, i
, inv
->imethod
);
1262 mono_array_set (res
, gpointer
, i
, (gpointer
)inv
->ip
);
1270 #define MYGUINT64_MAX 18446744073709551615ULL
1271 #define MYGINT64_MAX 9223372036854775807LL
1272 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1274 #define MYGUINT32_MAX 4294967295U
1275 #define MYGINT32_MAX 2147483647
1276 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1278 #define CHECK_ADD_OVERFLOW(a,b) \
1279 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1280 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1282 #define CHECK_SUB_OVERFLOW(a,b) \
1283 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1284 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1286 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1287 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1289 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1290 (guint32)(a) < (guint32)(b) ? -1 : 0
1292 #define CHECK_ADD_OVERFLOW64(a,b) \
1293 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1294 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1296 #define CHECK_SUB_OVERFLOW64(a,b) \
1297 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1298 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1300 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1301 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1303 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1304 (guint64)(a) < (guint64)(b) ? -1 : 0
1306 #if SIZEOF_VOID_P == 4
1307 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1308 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1310 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1311 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1314 /* Resolves to TRUE if the operands would overflow */
1315 #define CHECK_MUL_OVERFLOW(a,b) \
1316 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1317 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1318 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1319 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1320 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1321 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1322 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1324 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1325 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1326 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1328 #define CHECK_MUL_OVERFLOW64(a,b) \
1329 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1330 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1331 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1332 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1333 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1334 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1335 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1337 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1338 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1339 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1341 #if SIZEOF_VOID_P == 4
1342 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1343 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1345 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1346 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1350 mono_interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1352 InterpFrame frame
, *old_frame
;
1353 ThreadContext
* volatile context
= mono_native_tls_get_value (thread_context_id
);
1354 MonoMethodSignature
*sig
= mono_method_signature (method
);
1355 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
1358 ThreadContext context_struct
;
1366 if (context
== NULL
) {
1367 context
= &context_struct
;
1368 memset (context
, 0, sizeof (ThreadContext
));
1369 set_context (context
);
1371 old_frame
= context
->current_frame
;
1374 MonoDomain
*domain
= mono_domain_get ();
1376 MonoMethod
*invoke_wrapper
= mono_marshal_get_runtime_invoke_full (method
, FALSE
, TRUE
);
1378 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1380 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1381 args
= alloca (sizeof (stackval
) * 4);
1384 args
[0].data
.p
= obj
;
1386 args
[0].data
.p
= NULL
;
1387 args
[1].data
.p
= params
;
1388 args
[2].data
.p
= exc
;
1389 args
[3].data
.p
= method
;
1391 INIT_FRAME (&frame
, context
->current_frame
, args
, &result
, domain
, invoke_wrapper
, error
);
1394 frame
.invoke_trap
= 1;
1396 ves_exec_method_with_context (&frame
, context
, NULL
, NULL
, -1);
1398 if (context
== &context_struct
)
1401 context
->current_frame
= old_frame
;
1405 *exc
= (MonoObject
*) frame
.ex
;
1408 mono_set_pending_exception (frame
.ex
);
1411 return result
.data
.p
;
1415 InterpMethod
*rmethod
;
1419 gpointer
*many_args
;
1422 /* Main function for entering the interpreter from compiled code */
1424 interp_entry (InterpEntryData
*data
)
1427 InterpMethod
*rmethod
= data
->rmethod
;
1428 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
1429 ThreadContext context_struct
;
1430 InterpFrame
*old_frame
;
1434 MonoMethodSignature
*sig
;
1438 method
= rmethod
->method
;
1439 sig
= mono_method_signature (method
);
1441 // FIXME: Optimize this
1443 //printf ("%s\n", mono_method_full_name (method, 1));
1446 if (context
== NULL
) {
1447 context
= &context_struct
;
1448 memset (context
, 0, sizeof (ThreadContext
));
1449 set_context (context
);
1451 old_frame
= context
->current_frame
;
1454 args
= alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
1456 args
[0].data
.p
= data
->this_arg
;
1459 if (data
->many_args
)
1460 params
= data
->many_args
;
1462 params
= data
->args
;
1463 for (i
= 0; i
< sig
->param_count
; ++i
) {
1464 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1465 if (sig
->params
[i
]->byref
) {
1466 args
[a_index
].data
.p
= params
[i
];
1469 type
= rmethod
->param_types
[i
];
1470 switch (type
->type
) {
1473 args
[a_index
].data
.i
= *(MonoBoolean
*)params
[i
];
1477 args
[a_index
].data
.i
= *(gint16
*)params
[i
];
1480 #if SIZEOF_VOID_P == 4
1481 args
[a_index
].data
.p
= GINT_TO_POINTER (*(guint32
*)params
[i
]);
1483 args
[a_index
].data
.p
= GINT_TO_POINTER (*(guint64
*)params
[i
]);
1487 #if SIZEOF_VOID_P == 4
1488 args
[a_index
].data
.p
= GINT_TO_POINTER (*(gint32
*)params
[i
]);
1490 args
[a_index
].data
.p
= GINT_TO_POINTER (*(gint64
*)params
[i
]);
1494 args
[a_index
].data
.i
= *(guint32
*)params
[i
];
1497 args
[a_index
].data
.i
= *(gint32
*)params
[i
];
1500 args
[a_index
].data
.l
= *(guint64
*)params
[i
];
1503 args
[a_index
].data
.l
= *(gint64
*)params
[i
];
1506 case MONO_TYPE_OBJECT
:
1507 args
[a_index
].data
.p
= *(MonoObject
**)params
[i
];
1509 case MONO_TYPE_VALUETYPE
:
1510 args
[a_index
].data
.p
= params
[i
];
1512 case MONO_TYPE_GENERICINST
:
1513 if (MONO_TYPE_IS_REFERENCE (type
))
1514 args
[a_index
].data
.p
= params
[i
];
1516 args
[a_index
].data
.vt
= params
[i
];
1519 printf ("%s\n", mono_type_full_name (sig
->params
[i
]));
1525 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1527 type
= rmethod
->rtype
;
1528 switch (type
->type
) {
1529 case MONO_TYPE_GENERICINST
:
1530 if (!MONO_TYPE_IS_REFERENCE (type
))
1531 frame
.retval
->data
.vt
= data
->res
;
1533 case MONO_TYPE_VALUETYPE
:
1534 frame
.retval
->data
.vt
= data
->res
;
1540 ves_exec_method_with_context (&frame
, context
, NULL
, NULL
, -1);
1541 if (context
== &context_struct
)
1544 context
->current_frame
= old_frame
;
1547 g_assert (frame
.ex
== NULL
);
1549 type
= rmethod
->rtype
;
1550 switch (type
->type
) {
1551 case MONO_TYPE_VOID
:
1554 *(gint8
*)data
->res
= frame
.retval
->data
.i
;
1557 *(guint8
*)data
->res
= frame
.retval
->data
.i
;
1560 *(gint16
*)data
->res
= frame
.retval
->data
.i
;
1563 *(guint16
*)data
->res
= frame
.retval
->data
.i
;
1566 *(gint32
*)data
->res
= frame
.retval
->data
.i
;
1569 *(guint64
*)data
->res
= frame
.retval
->data
.i
;
1572 *(gint64
*)data
->res
= frame
.retval
->data
.i
;
1575 *(guint64
*)data
->res
= frame
.retval
->data
.i
;
1578 #if SIZEOF_VOID_P == 8
1579 *(gint64
*)data
->res
= (gint64
)frame
.retval
->data
.p
;
1581 *(gint32
*)data
->res
= (gint32
)frame
.retval
->data
.p
;
1585 #if SIZEOF_VOID_P == 8
1586 *(guint64
*)data
->res
= (guint64
)frame
.retval
->data
.p
;
1588 *(guint32
*)data
->res
= (guint32
)frame
.retval
->data
.p
;
1591 case MONO_TYPE_OBJECT
:
1592 /* No need for a write barrier */
1593 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1595 case MONO_TYPE_GENERICINST
:
1596 if (MONO_TYPE_IS_REFERENCE (type
)) {
1597 *(MonoObject
**)data
->res
= *(MonoObject
**)frame
.retval
->data
.p
;
1599 /* Already set before the call */
1602 case MONO_TYPE_VALUETYPE
:
1603 /* Already set before the call */
1606 printf ("%s\n", mono_type_full_name (sig
->ret
));
1613 do_icall (ThreadContext
*context
, int op
, stackval
*sp
, gpointer ptr
)
1616 interp_push_lmf (&ext
, context
->current_frame
);
1619 case MINT_ICALL_V_V
: {
1620 void (*func
)(void) = ptr
;
1624 case MINT_ICALL_V_P
: {
1625 gpointer (*func
)(void) = ptr
;
1627 sp
[-1].data
.p
= func ();
1630 case MINT_ICALL_P_V
: {
1631 void (*func
)(gpointer
) = ptr
;
1632 func (sp
[-1].data
.p
);
1636 case MINT_ICALL_P_P
: {
1637 gpointer (*func
)(gpointer
) = ptr
;
1638 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1641 case MINT_ICALL_PP_V
: {
1642 void (*func
)(gpointer
,gpointer
) = ptr
;
1644 func (sp
[0].data
.p
, sp
[1].data
.p
);
1647 case MINT_ICALL_PI_V
: {
1648 void (*func
)(gpointer
,int) = ptr
;
1650 func (sp
[0].data
.p
, sp
[1].data
.i
);
1653 case MINT_ICALL_PP_P
: {
1654 gpointer (*func
)(gpointer
,gpointer
) = ptr
;
1656 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1659 case MINT_ICALL_PI_P
: {
1660 gpointer (*func
)(gpointer
,int) = ptr
;
1662 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.i
);
1665 case MINT_ICALL_PPP_V
: {
1666 void (*func
)(gpointer
,gpointer
,gpointer
) = ptr
;
1668 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1671 case MINT_ICALL_PPI_V
: {
1672 void (*func
)(gpointer
,gpointer
,int) = ptr
;
1674 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
1678 g_assert_not_reached ();
1681 interp_pop_lmf (&ext
);
1686 do_jit_call (stackval
*sp
, unsigned char *vt_sp
, ThreadContext
*context
, InterpFrame
*frame
, InterpMethod
*rmethod
)
1688 MonoMethodSignature
*sig
;
1689 MonoFtnDesc ftndesc
;
1690 guint8 res_buf
[256];
1694 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
1697 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1698 * by ref and return a return value using an explicit return value argument.
1700 if (!rmethod
->jit_wrapper
) {
1701 MonoMethod
*method
= rmethod
->method
;
1704 sig
= mono_method_signature (method
);
1707 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
1708 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1710 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, &error
);
1711 mono_error_assert_ok (&error
);
1713 gpointer addr
= mono_jit_compile_method_jit_only (method
, &error
);
1715 mono_error_assert_ok (&error
);
1717 rmethod
->jit_addr
= addr
;
1718 rmethod
->jit_sig
= sig
;
1719 mono_memory_barrier ();
1720 rmethod
->jit_wrapper
= jit_wrapper
;
1723 sig
= rmethod
->jit_sig
;
1726 sp
-= sig
->param_count
;
1730 ftndesc
.addr
= rmethod
->jit_addr
;
1733 // FIXME: Optimize this
1737 int stack_index
= 0;
1738 if (rmethod
->hasthis
) {
1739 args
[pindex
++] = sp
[0].data
.p
;
1742 type
= rmethod
->rtype
;
1743 if (type
->type
!= MONO_TYPE_VOID
) {
1744 if (MONO_TYPE_ISSTRUCT (type
))
1745 args
[pindex
++] = vt_sp
;
1747 args
[pindex
++] = res_buf
;
1749 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
1750 MonoType
*t
= rmethod
->param_types
[i
];
1751 stackval
*sval
= &sp
[stack_index
+ i
];
1752 if (sig
->params
[i
]->byref
) {
1753 args
[pindex
++] = sval
->data
.p
;
1754 } else if (MONO_TYPE_ISSTRUCT (t
)) {
1755 args
[pindex
++] = sval
->data
.p
;
1756 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
1757 args
[pindex
++] = &sval
->data
.p
;
1766 case MONO_TYPE_VALUETYPE
:
1767 args
[pindex
++] = &sval
->data
.i
;
1770 case MONO_TYPE_FNPTR
:
1773 case MONO_TYPE_OBJECT
:
1774 args
[pindex
++] = &sval
->data
.p
;
1778 args
[pindex
++] = &sval
->data
.l
;
1781 printf ("%s\n", mono_type_full_name (t
));
1782 g_assert_not_reached ();
1787 interp_push_lmf (&ext
, frame
);
1791 void (*func
)(gpointer
) = rmethod
->jit_wrapper
;
1797 void (*func
)(gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1799 func (args
[0], &ftndesc
);
1803 void (*func
)(gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1805 func (args
[0], args
[1], &ftndesc
);
1809 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1811 func (args
[0], args
[1], args
[2], &ftndesc
);
1815 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1817 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
1821 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1823 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
1827 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1829 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
1833 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
1835 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
1839 g_assert_not_reached ();
1843 interp_pop_lmf (&ext
);
1845 MonoType
*rtype
= rmethod
->rtype
;
1846 switch (rtype
->type
) {
1847 case MONO_TYPE_VOID
:
1848 case MONO_TYPE_OBJECT
:
1849 case MONO_TYPE_STRING
:
1850 case MONO_TYPE_CLASS
:
1851 case MONO_TYPE_ARRAY
:
1852 case MONO_TYPE_SZARRAY
:
1855 sp
->data
.p
= *(gpointer
*)res_buf
;
1858 sp
->data
.i
= *(gint8
*)res_buf
;
1861 sp
->data
.i
= *(guint8
*)res_buf
;
1864 sp
->data
.i
= *(gint16
*)res_buf
;
1867 sp
->data
.i
= *(guint16
*)res_buf
;
1870 sp
->data
.i
= *(gint32
*)res_buf
;
1873 sp
->data
.i
= *(guint32
*)res_buf
;
1875 case MONO_TYPE_VALUETYPE
:
1876 /* The result was written to vt_sp */
1879 case MONO_TYPE_GENERICINST
:
1880 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
1881 sp
->data
.p
= *(gpointer
*)res_buf
;
1883 /* The result was written to vt_sp */
1888 g_print ("%s\n", mono_type_full_name (rtype
));
1889 g_assert_not_reached ();
1897 do_debugger_tramp (void (*tramp
) (void), InterpFrame
*frame
)
1900 interp_push_lmf (&ext
, frame
);
1902 interp_pop_lmf (&ext
);
1906 do_transform_method (InterpFrame
*frame
, ThreadContext
*context
)
1910 /* Use the parent frame as the current frame is not complete yet */
1911 interp_push_lmf (&ext
, frame
->parent
);
1913 frame
->ex
= mono_interp_transform_method (frame
->imethod
, context
, (MonoDelegate
*) frame
->stack_args
[0].data
.p
);
1915 interp_pop_lmf (&ext
);
1919 * These functions are the entry points into the interpreter from compiled code.
1920 * They are called by the interp_in wrappers. They have the following signature:
1921 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1922 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1923 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1924 * more wrappers then these functions.
1925 * this/static * ret/void * 16 arguments -> 64 functions.
1928 #define MAX_INTERP_ENTRY_ARGS 8
1930 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1931 InterpEntryData data; \
1932 (data).rmethod = (_method); \
1933 (data).res = (_res); \
1934 (data).this_arg = (_this_arg); \
1935 (data).many_args = NULL;
1937 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
1938 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1939 interp_entry (&data); \
1941 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
1942 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1943 (data).args [0] = arg1; \
1944 interp_entry (&data); \
1946 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
1947 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1948 (data).args [0] = arg1; \
1949 (data).args [1] = arg2; \
1950 interp_entry (&data); \
1952 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
1953 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1954 (data).args [0] = arg1; \
1955 (data).args [1] = arg2; \
1956 (data).args [2] = arg3; \
1957 interp_entry (&data); \
1959 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
1960 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1961 (data).args [0] = arg1; \
1962 (data).args [1] = arg2; \
1963 (data).args [2] = arg3; \
1964 (data).args [3] = arg4; \
1965 interp_entry (&data); \
1967 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
1968 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1969 (data).args [0] = arg1; \
1970 (data).args [1] = arg2; \
1971 (data).args [2] = arg3; \
1972 (data).args [3] = arg4; \
1973 (data).args [4] = arg5; \
1974 interp_entry (&data); \
1976 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
1977 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1978 (data).args [0] = arg1; \
1979 (data).args [1] = arg2; \
1980 (data).args [2] = arg3; \
1981 (data).args [3] = arg4; \
1982 (data).args [4] = arg5; \
1983 (data).args [5] = arg6; \
1984 interp_entry (&data); \
1986 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
1987 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1988 (data).args [0] = arg1; \
1989 (data).args [1] = arg2; \
1990 (data).args [2] = arg3; \
1991 (data).args [3] = arg4; \
1992 (data).args [4] = arg5; \
1993 (data).args [5] = arg6; \
1994 (data).args [6] = arg7; \
1995 interp_entry (&data); \
1997 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
1998 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1999 (data).args [0] = arg1; \
2000 (data).args [1] = arg2; \
2001 (data).args [2] = arg3; \
2002 (data).args [3] = arg4; \
2003 (data).args [4] = arg5; \
2004 (data).args [5] = arg6; \
2005 (data).args [6] = arg7; \
2006 (data).args [7] = arg8; \
2007 interp_entry (&data); \
2010 #define ARGLIST0 InterpMethod *rmethod
2011 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2012 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2013 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2014 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2015 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2016 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2017 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2018 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2020 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
2021 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
2022 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
2023 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
2024 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
2025 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
2026 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
2027 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
2028 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
2029 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
2030 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
2031 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
2032 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
2033 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
2034 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
2035 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
2036 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
2037 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
2038 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
2039 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
2040 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
2041 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
2042 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
2043 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
2044 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
2045 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
2046 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
2047 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
2048 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
2049 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
2050 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
2051 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
2052 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
2053 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2054 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2055 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
2057 #define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
2059 gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
2060 gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
2061 gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
2062 gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
2064 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2066 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
2068 INTERP_ENTRY_BASE (rmethod
, this_arg
, res
);
2069 data
.many_args
= args
;
2070 interp_entry (&data
);
2074 * mono_interp_create_method_pointer:
2076 * Return a function pointer which can be used to call METHOD using the
2077 * interpreter. Return NULL for methods which are not supported.
2080 mono_interp_create_method_pointer (MonoMethod
*method
, MonoError
*error
)
2083 MonoMethodSignature
*sig
= mono_method_signature (method
);
2084 MonoMethod
*wrapper
;
2085 InterpMethod
*rmethod
= mono_interp_get_imethod (mono_domain_get (), method
, error
);
2087 /* HACK: method_ptr of delegate should point to a runtime method*/
2088 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2091 if (rmethod
->jit_entry
)
2092 return rmethod
->jit_entry
;
2093 wrapper
= mini_get_interp_in_wrapper (sig
);
2095 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
2096 mono_error_assert_ok (error
);
2098 //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2099 gpointer entry_func
;
2100 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
2101 entry_func
= interp_entry_general
;
2102 } else if (sig
->hasthis
) {
2103 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2104 entry_func
= entry_funcs_instance
[sig
->param_count
];
2106 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
2108 if (sig
->ret
->type
== MONO_TYPE_VOID
)
2109 entry_func
= entry_funcs_static
[sig
->param_count
];
2111 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
2113 g_assert (entry_func
);
2115 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2116 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
2117 ftndesc
->addr
= entry_func
;
2118 ftndesc
->arg
= rmethod
;
2119 mono_error_assert_ok (error
);
2122 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2123 * rgctx register using a trampoline.
2127 addr
= mono_aot_get_static_rgctx_trampoline (ftndesc
, jit_wrapper
);
2129 addr
= mono_arch_get_static_rgctx_trampoline (ftndesc
, jit_wrapper
);
2131 mono_memory_barrier ();
2132 rmethod
->jit_entry
= addr
;
2138 static int opcode_counts
[512];
2140 #define COUNT_OP(op) opcode_counts[op]++
2142 #define COUNT_OP(op)
2146 #define DUMP_INSTR() \
2147 if (tracing > 1) { \
2149 if (sp > frame->stack) { \
2150 ins = dump_stack (frame->stack, sp); \
2152 ins = g_strdup (""); \
2156 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2157 g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
2159 mono_interp_dis_mintop(rtm->code, ip); \
2160 g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
2164 #define DUMP_INSTR()
2168 #define USE_COMPUTED_GOTO 1
2170 #if USE_COMPUTED_GOTO
2171 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2172 #define MINT_IN_CASE(x) LAB_ ## x:
2174 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2176 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2178 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2180 #define MINT_IN_SWITCH(op) switch (op)
2181 #define MINT_IN_CASE(x) case x:
2182 #define MINT_IN_BREAK break
2183 #define MINT_IN_DEFAULT default:
2187 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2190 ves_exec_method_with_context (InterpFrame
*frame
, ThreadContext
*context
, unsigned short *start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
)
2192 InterpFrame child_frame
;
2193 GSList
*finally_ips
= NULL
;
2194 const unsigned short *endfinally_ip
= NULL
;
2195 const unsigned short *ip
= NULL
;
2196 register stackval
*sp
;
2199 gint tracing
= global_tracing
;
2200 unsigned char *vtalloc
;
2205 unsigned char *vt_sp
;
2206 unsigned char *locals
;
2208 MonoObject
*o
= NULL
;
2210 #if USE_COMPUTED_GOTO
2211 static void *in_labels
[] = {
2212 #define OPDEF(a,b,c,d) \
2214 #include "mintops.def"
2219 frame
->ex_handler
= NULL
;
2221 context
->current_frame
= frame
;
2223 debug_enter (frame
, &tracing
);
2225 if (!frame
->imethod
->transformed
) {
2227 char *mn
= mono_method_full_name (frame
->imethod
->method
, TRUE
);
2228 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2232 do_transform_method (frame
, context
);
2234 context
->search_for_handler
= 1;
2241 rtm
= frame
->imethod
;
2242 if (!start_with_ip
) {
2243 frame
->args
= alloca (rtm
->alloca_size
);
2244 memset (frame
->args
, 0, rtm
->alloca_size
);
2250 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2251 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2255 locals
= (unsigned char *) vt_sp
+ rtm
->vt_stack_size
;
2256 frame
->locals
= locals
;
2257 child_frame
.parent
= frame
;
2259 if (filter_exception
) {
2260 sp
->data
.p
= filter_exception
;
2265 * using while (ip < end) may result in a 15% performance drop,
2266 * but it may be useful for debug
2270 /* g_assert (sp >= frame->stack); */
2271 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2273 MINT_IN_SWITCH (*ip
) {
2274 MINT_IN_CASE(MINT_INITLOCALS
)
2275 memset (locals
, 0, rtm
->locals_size
);
2278 MINT_IN_CASE(MINT_NOP
)
2281 MINT_IN_CASE(MINT_NIY
)
2282 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2284 MINT_IN_CASE(MINT_BREAK
)
2286 do_debugger_tramp (mono_debugger_agent_user_break
, frame
);
2288 MINT_IN_CASE(MINT_LDNULL
)
2293 MINT_IN_CASE(MINT_VTRESULT
) {
2294 int ret_size
= * (guint16
*)(ip
+ 1);
2295 unsigned char *ret_vt_sp
= vt_sp
;
2296 vt_sp
-= READ32(ip
+ 2);
2298 memmove (vt_sp
, ret_vt_sp
, ret_size
);
2299 sp
[-1].data
.p
= vt_sp
;
2300 vt_sp
+= (ret_size
+ 7) & ~7;
2305 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2306 MINT_IN_CASE(MINT_LDC_I4_M1
)
2309 MINT_IN_CASE(MINT_LDC_I4_0
)
2312 MINT_IN_CASE(MINT_LDC_I4_1
)
2315 MINT_IN_CASE(MINT_LDC_I4_2
)
2318 MINT_IN_CASE(MINT_LDC_I4_3
)
2321 MINT_IN_CASE(MINT_LDC_I4_4
)
2324 MINT_IN_CASE(MINT_LDC_I4_5
)
2327 MINT_IN_CASE(MINT_LDC_I4_6
)
2330 MINT_IN_CASE(MINT_LDC_I4_7
)
2333 MINT_IN_CASE(MINT_LDC_I4_8
)
2336 MINT_IN_CASE(MINT_LDC_I4_S
)
2337 sp
->data
.i
= *(const short *)(ip
+ 1);
2341 MINT_IN_CASE(MINT_LDC_I4
)
2343 sp
->data
.i
= READ32 (ip
);
2347 MINT_IN_CASE(MINT_LDC_I8
)
2349 sp
->data
.l
= READ64 (ip
);
2353 MINT_IN_CASE(MINT_LDC_R4
) {
2357 sp
->data
.f
= * (float *)&val
;
2362 MINT_IN_CASE(MINT_LDC_R8
)
2363 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
2367 MINT_IN_CASE(MINT_DUP
)
2372 MINT_IN_CASE(MINT_DUP_VT
)
2373 i32
= READ32 (ip
+ 1);
2375 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
2376 vt_sp
+= (i32
+ 7) & ~7;
2380 MINT_IN_CASE(MINT_POP
) {
2381 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
2383 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
2388 MINT_IN_CASE(MINT_JMP
) {
2389 InterpMethod
*new_method
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2391 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
)
2392 MONO_PROFILER_RAISE (method_tail_call
, (frame
->imethod
->method
, new_method
->method
));
2394 if (!new_method
->transformed
) {
2396 frame
->ex
= mono_interp_transform_method (new_method
, context
, NULL
);
2401 if (new_method
->alloca_size
> rtm
->alloca_size
)
2402 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method
->alloca_size
, rtm
->alloca_size
);
2403 rtm
= frame
->imethod
= new_method
;
2404 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2408 locals
= vt_sp
+ rtm
->vt_stack_size
;
2409 frame
->locals
= locals
;
2410 ip
= rtm
->new_body_start
; /* bypass storing input args from callers frame */
2413 MINT_IN_CASE(MINT_CALLI
) {
2414 MonoMethodSignature
*csignature
;
2415 stackval
*endsp
= sp
;
2419 csignature
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2423 child_frame
.imethod
= sp
->data
.p
;
2426 child_frame
.retval
= sp
;
2427 /* decrement by the actual number of args */
2428 sp
-= csignature
->param_count
;
2429 if (csignature
->hasthis
)
2431 child_frame
.stack_args
= sp
;
2433 if (child_frame
.imethod
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
2434 child_frame
.imethod
= mono_interp_get_imethod (rtm
->domain
, mono_marshal_get_native_wrapper (child_frame
.imethod
->method
, FALSE
, FALSE
), &error
);
2435 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
2438 if (csignature
->hasthis
) {
2439 MonoObject
*this_arg
= sp
->data
.p
;
2441 if (this_arg
->vtable
->klass
->valuetype
) {
2442 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2443 sp
[0].data
.p
= unboxed
;
2447 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2449 context
->current_frame
= frame
;
2451 if (context
->has_resume_state
) {
2452 if (frame
== context
->handler_frame
)
2453 SET_RESUME_STATE (context
);
2458 if (child_frame
.ex
) {
2460 * An exception occurred, need to run finally, fault and catch handlers..
2462 frame
->ex
= child_frame
.ex
;
2463 goto handle_finally
;
2466 /* need to handle typedbyref ... */
2467 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2473 MINT_IN_CASE(MINT_CALLI_NAT
) {
2474 MonoMethodSignature
*csignature
;
2475 stackval
*endsp
= sp
;
2476 unsigned char *code
= NULL
;
2480 csignature
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2485 child_frame
.imethod
= NULL
;
2488 child_frame
.retval
= sp
;
2489 /* decrement by the actual number of args */
2490 sp
-= csignature
->param_count
;
2491 if (csignature
->hasthis
)
2493 child_frame
.stack_args
= sp
;
2494 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
);
2496 context
->current_frame
= frame
;
2498 if (context
->has_resume_state
) {
2499 if (frame
== context
->handler_frame
)
2500 SET_RESUME_STATE (context
);
2505 if (child_frame
.ex
) {
2507 * An exception occurred, need to run finally, fault and catch handlers..
2509 frame
->ex
= child_frame
.ex
;
2510 if (context
->search_for_handler
) {
2511 context
->search_for_handler
= 0;
2512 goto handle_exception
;
2514 goto handle_finally
;
2517 /* need to handle typedbyref ... */
2518 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2524 MINT_IN_CASE(MINT_CALL
) {
2525 stackval
*endsp
= sp
;
2529 child_frame
.imethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2532 child_frame
.retval
= sp
;
2533 /* decrement by the actual number of args */
2534 sp
-= child_frame
.imethod
->param_count
;
2535 if (child_frame
.imethod
->hasthis
)
2537 child_frame
.stack_args
= sp
;
2539 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2541 context
->current_frame
= frame
;
2543 if (context
->has_resume_state
) {
2544 if (frame
== context
->handler_frame
)
2545 SET_RESUME_STATE (context
);
2550 if (child_frame
.ex
) {
2552 * An exception occurred, need to run finally, fault and catch handlers..
2554 frame
->ex
= child_frame
.ex
;
2555 goto handle_exception
;;
2558 /* need to handle typedbyref ... */
2563 MINT_IN_CASE(MINT_VCALL
) {
2566 child_frame
.imethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2570 child_frame
.retval
= sp
;
2571 /* decrement by the actual number of args */
2572 sp
-= child_frame
.imethod
->param_count
;
2573 if (child_frame
.imethod
->hasthis
) {
2575 MonoObject
*this_arg
= sp
->data
.p
;
2577 THROW_EX (mono_get_exception_null_reference(), ip
- 2);
2579 child_frame
.stack_args
= sp
;
2581 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2583 context
->current_frame
= frame
;
2585 if (context
->has_resume_state
) {
2586 if (frame
== context
->handler_frame
)
2587 SET_RESUME_STATE (context
);
2592 if (child_frame
.ex
) {
2594 * An exception occurred, need to run finally, fault and catch handlers..
2596 frame
->ex
= child_frame
.ex
;
2597 goto handle_finally
;
2602 MINT_IN_CASE(MINT_JIT_CALL
) {
2603 InterpMethod
*rmethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2606 sp
= do_jit_call (sp
, vt_sp
, context
, frame
, rmethod
);
2608 if (context
->has_resume_state
) {
2610 * If this bit is set, it means the call has thrown the exception, and we
2611 * reached this point because the EH code in mono_handle_exception ()
2612 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2613 * has set the fields in context to indicate where we have to resume execution.
2615 if (frame
== context
->handler_frame
)
2616 SET_RESUME_STATE (context
);
2620 if (rmethod
->rtype
->type
!= MONO_TYPE_VOID
)
2626 MINT_IN_CASE(MINT_CALLVIRT
) {
2627 stackval
*endsp
= sp
;
2628 MonoObject
*this_arg
;
2633 token
= * (unsigned short *)(ip
+ 1);
2635 child_frame
.imethod
= rtm
->data_items
[token
];
2637 child_frame
.retval
= sp
;
2639 /* decrement by the actual number of args */
2640 sp
-= child_frame
.imethod
->param_count
+ 1;
2641 child_frame
.stack_args
= sp
;
2642 this_arg
= sp
->data
.p
;
2644 THROW_EX (mono_get_exception_null_reference(), ip
- 2);
2645 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
2647 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2648 if (this_class
->valuetype
&& child_frame
.imethod
->method
->klass
->valuetype
) {
2650 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2651 sp
[0].data
.p
= unboxed
;
2654 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2656 context
->current_frame
= frame
;
2658 if (context
->has_resume_state
) {
2659 if (frame
== context
->handler_frame
)
2660 SET_RESUME_STATE (context
);
2665 if (child_frame
.ex
) {
2667 * An exception occurred, need to run finally, fault and catch handlers..
2669 frame
->ex
= child_frame
.ex
;
2670 if (context
->search_for_handler
) {
2671 context
->search_for_handler
= 0;
2672 goto handle_exception
;
2674 goto handle_finally
;
2677 /* need to handle typedbyref ... */
2682 MINT_IN_CASE(MINT_VCALLVIRT
) {
2683 MonoObject
*this_arg
;
2688 token
= * (unsigned short *)(ip
+ 1);
2690 child_frame
.imethod
= rtm
->data_items
[token
];
2692 child_frame
.retval
= sp
;
2694 /* decrement by the actual number of args */
2695 sp
-= child_frame
.imethod
->param_count
+ 1;
2696 child_frame
.stack_args
= sp
;
2697 this_arg
= sp
->data
.p
;
2699 THROW_EX (mono_get_exception_null_reference(), ip
- 2);
2700 child_frame
.imethod
= get_virtual_method (child_frame
.imethod
, this_arg
);
2702 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2703 if (this_class
->valuetype
&& child_frame
.imethod
->method
->klass
->valuetype
) {
2704 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2705 sp
[0].data
.p
= unboxed
;
2708 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2710 context
->current_frame
= frame
;
2712 if (context
->has_resume_state
) {
2713 if (frame
== context
->handler_frame
)
2714 SET_RESUME_STATE (context
);
2719 if (child_frame
.ex
) {
2721 * An exception occurred, need to run finally, fault and catch handlers..
2723 frame
->ex
= child_frame
.ex
;
2724 if (context
->search_for_handler
) {
2725 context
->search_for_handler
= 0;
2726 goto handle_exception
;
2728 goto handle_finally
;
2732 MINT_IN_CASE(MINT_CALLRUN
)
2733 ves_imethod (frame
, context
);
2736 goto handle_exception
;
2739 MINT_IN_CASE(MINT_RET
)
2741 *frame
->retval
= *sp
;
2742 if (sp
> frame
->stack
)
2743 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
2745 MINT_IN_CASE(MINT_RET_VOID
)
2746 if (sp
> frame
->stack
)
2747 g_warning ("ret.void: more values on stack: %d %s", sp
-frame
->stack
, mono_method_full_name (frame
->imethod
->method
, TRUE
));
2749 MINT_IN_CASE(MINT_RET_VT
)
2750 i32
= READ32(ip
+ 1);
2752 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
2753 if (sp
> frame
->stack
)
2754 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
2756 MINT_IN_CASE(MINT_BR_S
)
2757 /* Checkpoint to be able to handle aborts */
2758 if (*mono_thread_interruption_request_flag ()) {
2759 MonoException
*exc
= mono_thread_interruption_checkpoint ();
2763 ip
+= (short) *(ip
+ 1);
2765 MINT_IN_CASE(MINT_BR
)
2766 /* Checkpoint to be able to handle aborts */
2767 if (*mono_thread_interruption_request_flag ()) {
2768 MonoException
*exc
= mono_thread_interruption_checkpoint ();
2772 ip
+= (gint32
) READ32(ip
+ 1);
2774 #define ZEROP_S(datamem, op) \
2776 if (sp->data.datamem op 0) \
2777 ip += * (gint16 *)(ip + 1); \
2781 #define ZEROP(datamem, op) \
2783 if (sp->data.datamem op 0) \
2784 ip += READ32(ip + 1); \
2788 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
2791 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
2794 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
2797 MINT_IN_CASE(MINT_BRFALSE_I4
)
2800 MINT_IN_CASE(MINT_BRFALSE_I8
)
2803 MINT_IN_CASE(MINT_BRFALSE_R8
)
2806 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
2809 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
2812 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
2815 MINT_IN_CASE(MINT_BRTRUE_I4
)
2818 MINT_IN_CASE(MINT_BRTRUE_I8
)
2821 MINT_IN_CASE(MINT_BRTRUE_R8
)
2824 #define CONDBR_S(cond) \
2827 ip += * (gint16 *)(ip + 1); \
2830 #define BRELOP_S(datamem, op) \
2831 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2833 #define CONDBR(cond) \
2836 ip += READ32(ip + 1); \
2840 #define BRELOP(datamem, op) \
2841 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2843 MINT_IN_CASE(MINT_BEQ_I4_S
)
2846 MINT_IN_CASE(MINT_BEQ_I8_S
)
2849 MINT_IN_CASE(MINT_BEQ_R8_S
)
2850 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
2852 MINT_IN_CASE(MINT_BEQ_I4
)
2855 MINT_IN_CASE(MINT_BEQ_I8
)
2858 MINT_IN_CASE(MINT_BEQ_R8
)
2859 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
2861 MINT_IN_CASE(MINT_BGE_I4_S
)
2864 MINT_IN_CASE(MINT_BGE_I8_S
)
2867 MINT_IN_CASE(MINT_BGE_R8_S
)
2868 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
2870 MINT_IN_CASE(MINT_BGE_I4
)
2873 MINT_IN_CASE(MINT_BGE_I8
)
2876 MINT_IN_CASE(MINT_BGE_R8
)
2877 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
2879 MINT_IN_CASE(MINT_BGT_I4_S
)
2882 MINT_IN_CASE(MINT_BGT_I8_S
)
2885 MINT_IN_CASE(MINT_BGT_R8_S
)
2886 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
2888 MINT_IN_CASE(MINT_BGT_I4
)
2891 MINT_IN_CASE(MINT_BGT_I8
)
2894 MINT_IN_CASE(MINT_BGT_R8
)
2895 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
2897 MINT_IN_CASE(MINT_BLT_I4_S
)
2900 MINT_IN_CASE(MINT_BLT_I8_S
)
2903 MINT_IN_CASE(MINT_BLT_R8_S
)
2904 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
2906 MINT_IN_CASE(MINT_BLT_I4
)
2909 MINT_IN_CASE(MINT_BLT_I8
)
2912 MINT_IN_CASE(MINT_BLT_R8
)
2913 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
2915 MINT_IN_CASE(MINT_BLE_I4_S
)
2918 MINT_IN_CASE(MINT_BLE_I8_S
)
2921 MINT_IN_CASE(MINT_BLE_R8_S
)
2922 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
2924 MINT_IN_CASE(MINT_BLE_I4
)
2927 MINT_IN_CASE(MINT_BLE_I8
)
2930 MINT_IN_CASE(MINT_BLE_R8
)
2931 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
2933 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
2936 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
2939 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
2940 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
2942 MINT_IN_CASE(MINT_BNE_UN_I4
)
2945 MINT_IN_CASE(MINT_BNE_UN_I8
)
2948 MINT_IN_CASE(MINT_BNE_UN_R8
)
2949 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
2952 #define BRELOP_S_CAST(datamem, op, type) \
2954 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2955 ip += * (gint16 *)(ip + 1); \
2959 #define BRELOP_CAST(datamem, op, type) \
2961 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2962 ip += READ32(ip + 1); \
2966 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
2967 BRELOP_S_CAST(i
, >=, guint32
);
2969 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
2970 BRELOP_S_CAST(l
, >=, guint64
);
2972 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
2973 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
2975 MINT_IN_CASE(MINT_BGE_UN_I4
)
2976 BRELOP_CAST(i
, >=, guint32
);
2978 MINT_IN_CASE(MINT_BGE_UN_I8
)
2979 BRELOP_CAST(l
, >=, guint64
);
2981 MINT_IN_CASE(MINT_BGE_UN_R8
)
2982 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
2984 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
2985 BRELOP_S_CAST(i
, >, guint32
);
2987 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
2988 BRELOP_S_CAST(l
, >, guint64
);
2990 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
2991 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
2993 MINT_IN_CASE(MINT_BGT_UN_I4
)
2994 BRELOP_CAST(i
, >, guint32
);
2996 MINT_IN_CASE(MINT_BGT_UN_I8
)
2997 BRELOP_CAST(l
, >, guint64
);
2999 MINT_IN_CASE(MINT_BGT_UN_R8
)
3000 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3002 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3003 BRELOP_S_CAST(i
, <=, guint32
);
3005 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3006 BRELOP_S_CAST(l
, <=, guint64
);
3008 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3009 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3011 MINT_IN_CASE(MINT_BLE_UN_I4
)
3012 BRELOP_CAST(i
, <=, guint32
);
3014 MINT_IN_CASE(MINT_BLE_UN_I8
)
3015 BRELOP_CAST(l
, <=, guint64
);
3017 MINT_IN_CASE(MINT_BLE_UN_R8
)
3018 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3020 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3021 BRELOP_S_CAST(i
, <, guint32
);
3023 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3024 BRELOP_S_CAST(l
, <, guint64
);
3026 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3027 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3029 MINT_IN_CASE(MINT_BLT_UN_I4
)
3030 BRELOP_CAST(i
, <, guint32
);
3032 MINT_IN_CASE(MINT_BLT_UN_I8
)
3033 BRELOP_CAST(l
, <, guint64
);
3035 MINT_IN_CASE(MINT_BLT_UN_R8
)
3036 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3038 MINT_IN_CASE(MINT_SWITCH
) {
3040 const unsigned short *st
;
3046 if ((guint32
)sp
->data
.i
< n
) {
3048 ip
+= 2 * (guint32
)sp
->data
.i
;
3049 offset
= READ32 (ip
);
3056 MINT_IN_CASE(MINT_LDIND_I1
)
3058 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3060 MINT_IN_CASE(MINT_LDIND_U1
)
3062 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3064 MINT_IN_CASE(MINT_LDIND_I2
)
3066 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3068 MINT_IN_CASE(MINT_LDIND_U2
)
3070 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3072 MINT_IN_CASE(MINT_LDIND_I4
) /* Fall through */
3073 MINT_IN_CASE(MINT_LDIND_U4
)
3075 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3077 MINT_IN_CASE(MINT_LDIND_I8
)
3079 /* memmove handles unaligned case */
3080 memmove (&sp
[-1].data
.l
, sp
[-1].data
.p
, sizeof (gint64
));
3082 MINT_IN_CASE(MINT_LDIND_I
) {
3083 guint16 offset
= * (guint16
*)(ip
+ 1);
3084 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3088 MINT_IN_CASE(MINT_LDIND_R4
)
3090 sp
[-1].data
.f
= *(gfloat
*)sp
[-1].data
.p
;
3092 MINT_IN_CASE(MINT_LDIND_R8
)
3094 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3096 MINT_IN_CASE(MINT_LDIND_REF
)
3098 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3100 MINT_IN_CASE(MINT_STIND_REF
)
3103 mono_gc_wbarrier_generic_store (sp
->data
.p
, sp
[1].data
.p
);
3105 MINT_IN_CASE(MINT_STIND_I1
)
3108 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3110 MINT_IN_CASE(MINT_STIND_I2
)
3113 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3115 MINT_IN_CASE(MINT_STIND_I4
)
3118 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3120 MINT_IN_CASE(MINT_STIND_I
)
3123 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3125 MINT_IN_CASE(MINT_STIND_I8
)
3128 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3130 MINT_IN_CASE(MINT_STIND_R4
)
3133 * (float *) sp
->data
.p
= (gfloat
)sp
[1].data
.f
;
3135 MINT_IN_CASE(MINT_STIND_R8
)
3138 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3140 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3143 mono_atomic_store_i32 ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3145 #define BINOP(datamem, op) \
3147 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3149 MINT_IN_CASE(MINT_ADD_I4
)
3152 MINT_IN_CASE(MINT_ADD_I8
)
3155 MINT_IN_CASE(MINT_ADD_R8
)
3158 MINT_IN_CASE(MINT_ADD1_I4
)
3162 MINT_IN_CASE(MINT_SUB_I4
)
3165 MINT_IN_CASE(MINT_SUB_I8
)
3168 MINT_IN_CASE(MINT_SUB_R8
)
3171 MINT_IN_CASE(MINT_SUB1_I4
)
3175 MINT_IN_CASE(MINT_MUL_I4
)
3178 MINT_IN_CASE(MINT_MUL_I8
)
3181 MINT_IN_CASE(MINT_MUL_R8
)
3184 MINT_IN_CASE(MINT_DIV_I4
)
3185 if (sp
[-1].data
.i
== 0)
3186 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3187 if (sp
[-1].data
.i
== (-1))
3188 THROW_EX (mono_get_exception_overflow (), ip
);
3191 MINT_IN_CASE(MINT_DIV_I8
)
3192 if (sp
[-1].data
.l
== 0)
3193 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3194 if (sp
[-1].data
.l
== (-1))
3195 THROW_EX (mono_get_exception_overflow (), ip
);
3198 MINT_IN_CASE(MINT_DIV_R8
)
3202 #define BINOP_CAST(datamem, op, type) \
3204 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3206 MINT_IN_CASE(MINT_DIV_UN_I4
)
3207 if (sp
[-1].data
.i
== 0)
3208 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3209 BINOP_CAST(i
, /, guint32
);
3211 MINT_IN_CASE(MINT_DIV_UN_I8
)
3212 if (sp
[-1].data
.l
== 0)
3213 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3214 BINOP_CAST(l
, /, guint64
);
3216 MINT_IN_CASE(MINT_REM_I4
)
3217 if (sp
[-1].data
.i
== 0)
3218 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3219 if (sp
[-1].data
.i
== (-1))
3220 THROW_EX (mono_get_exception_overflow (), ip
);
3223 MINT_IN_CASE(MINT_REM_I8
)
3224 if (sp
[-1].data
.l
== 0)
3225 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3226 if (sp
[-1].data
.l
== (-1))
3227 THROW_EX (mono_get_exception_overflow (), ip
);
3230 MINT_IN_CASE(MINT_REM_R8
)
3231 /* FIXME: what do we actually do here? */
3233 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
3236 MINT_IN_CASE(MINT_REM_UN_I4
)
3237 if (sp
[-1].data
.i
== 0)
3238 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3239 BINOP_CAST(i
, %, guint32
);
3241 MINT_IN_CASE(MINT_REM_UN_I8
)
3242 if (sp
[-1].data
.l
== 0)
3243 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3244 BINOP_CAST(l
, %, guint64
);
3246 MINT_IN_CASE(MINT_AND_I4
)
3249 MINT_IN_CASE(MINT_AND_I8
)
3252 MINT_IN_CASE(MINT_OR_I4
)
3255 MINT_IN_CASE(MINT_OR_I8
)
3258 MINT_IN_CASE(MINT_XOR_I4
)
3261 MINT_IN_CASE(MINT_XOR_I8
)
3265 #define SHIFTOP(datamem, op) \
3267 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3270 MINT_IN_CASE(MINT_SHL_I4
)
3273 MINT_IN_CASE(MINT_SHL_I8
)
3276 MINT_IN_CASE(MINT_SHR_I4
)
3279 MINT_IN_CASE(MINT_SHR_I8
)
3282 MINT_IN_CASE(MINT_SHR_UN_I4
)
3284 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
3287 MINT_IN_CASE(MINT_SHR_UN_I8
)
3289 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
3292 MINT_IN_CASE(MINT_NEG_I4
)
3293 sp
[-1].data
.i
= - sp
[-1].data
.i
;
3296 MINT_IN_CASE(MINT_NEG_I8
)
3297 sp
[-1].data
.l
= - sp
[-1].data
.l
;
3300 MINT_IN_CASE(MINT_NEG_R8
)
3301 sp
[-1].data
.f
= - sp
[-1].data
.f
;
3304 MINT_IN_CASE(MINT_NOT_I4
)
3305 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
3308 MINT_IN_CASE(MINT_NOT_I8
)
3309 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
3312 MINT_IN_CASE(MINT_CONV_I1_I4
)
3313 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
3316 MINT_IN_CASE(MINT_CONV_I1_I8
)
3317 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
3320 MINT_IN_CASE(MINT_CONV_I1_R8
)
3321 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.f
;
3324 MINT_IN_CASE(MINT_CONV_U1_I4
)
3325 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
3328 MINT_IN_CASE(MINT_CONV_U1_I8
)
3329 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
3332 MINT_IN_CASE(MINT_CONV_U1_R8
)
3333 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.f
;
3336 MINT_IN_CASE(MINT_CONV_I2_I4
)
3337 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
3340 MINT_IN_CASE(MINT_CONV_I2_I8
)
3341 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
3344 MINT_IN_CASE(MINT_CONV_I2_R8
)
3345 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.f
;
3348 MINT_IN_CASE(MINT_CONV_U2_I4
)
3349 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
3352 MINT_IN_CASE(MINT_CONV_U2_I8
)
3353 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
3356 MINT_IN_CASE(MINT_CONV_U2_R8
)
3357 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.f
;
3360 MINT_IN_CASE(MINT_CONV_I4_R8
)
3361 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
3364 MINT_IN_CASE(MINT_CONV_U4_I8
)
3365 MINT_IN_CASE(MINT_CONV_I4_I8
)
3366 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
3369 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
3370 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
3373 MINT_IN_CASE(MINT_CONV_U4_R8
)
3374 /* needed on arm64 */
3375 if (isinf (sp
[-1].data
.f
))
3377 /* needed by wasm */
3378 else if (isnan (sp
[-1].data
.f
))
3381 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3384 MINT_IN_CASE(MINT_CONV_I8_I4
)
3385 sp
[-1].data
.l
= sp
[-1].data
.i
;
3388 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
3389 sp
[-2].data
.l
= sp
[-2].data
.i
;
3392 MINT_IN_CASE(MINT_CONV_I8_U4
)
3393 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
3396 MINT_IN_CASE(MINT_CONV_I8_R8
)
3397 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
3400 MINT_IN_CASE(MINT_CONV_R4_I4
)
3401 sp
[-1].data
.f
= (float)sp
[-1].data
.i
;
3404 MINT_IN_CASE(MINT_CONV_R4_I8
)
3405 sp
[-1].data
.f
= (float)sp
[-1].data
.l
;
3408 MINT_IN_CASE(MINT_CONV_R4_R8
)
3409 sp
[-1].data
.f
= (float)sp
[-1].data
.f
;
3412 MINT_IN_CASE(MINT_CONV_R8_I4
)
3413 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
3416 MINT_IN_CASE(MINT_CONV_R8_I8
)
3417 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
3420 MINT_IN_CASE(MINT_CONV_U8_I4
)
3421 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
3424 MINT_IN_CASE(MINT_CONV_U8_R8
)
3425 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
3428 MINT_IN_CASE(MINT_CPOBJ
) {
3429 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3430 g_assert (c
->valuetype
);
3431 /* if this assertion fails, we need to add a write barrier */
3432 g_assert (!MONO_TYPE_IS_REFERENCE (&c
->byval_arg
));
3433 if (mint_type (&c
->byval_arg
) == MINT_TYPE_VT
)
3434 stackval_from_data (&c
->byval_arg
, &sp
[-2], sp
[-1].data
.p
, FALSE
);
3436 stackval_from_data (&c
->byval_arg
, sp
[-2].data
.p
, sp
[-1].data
.p
, FALSE
);
3441 MINT_IN_CASE(MINT_LDOBJ
) {
3443 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3446 if (mint_type (&c
->byval_arg
) == MINT_TYPE_VT
&& !c
->enumtype
) {
3447 int size
= mono_class_value_size (c
, NULL
);
3448 sp
[-1].data
.p
= vt_sp
;
3449 vt_sp
+= (size
+ 7) & ~7;
3451 stackval_from_data (&c
->byval_arg
, &sp
[-1], p
, FALSE
);
3454 MINT_IN_CASE(MINT_LDSTR
)
3455 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3459 MINT_IN_CASE(MINT_NEWOBJ
) {
3460 MonoClass
*newobj_class
;
3461 MonoMethodSignature
*csig
;
3462 stackval valuetype_this
;
3468 token
= * (guint16
*)(ip
+ 1);
3471 child_frame
.ip
= NULL
;
3472 child_frame
.ex
= NULL
;
3474 child_frame
.imethod
= rtm
->data_items
[token
];
3475 csig
= mono_method_signature (child_frame
.imethod
->method
);
3476 newobj_class
= child_frame
.imethod
->method
->klass
;
3477 /*if (profiling_classes) {
3478 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3480 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3483 if (newobj_class
->parent
== mono_defaults
.array_class
) {
3484 sp
-= csig
->param_count
;
3485 child_frame
.stack_args
= sp
;
3486 o
= ves_array_create (&child_frame
, rtm
->domain
, newobj_class
, csig
, sp
);
3488 THROW_EX (child_frame
.ex
, ip
);
3489 goto array_constructed
;
3492 g_assert (csig
->hasthis
);
3493 if (csig
->param_count
) {
3494 sp
-= csig
->param_count
;
3495 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
3497 child_frame
.stack_args
= sp
;
3500 * First arg is the object.
3502 if (newobj_class
->valuetype
) {
3503 MonoType
*t
= &newobj_class
->byval_arg
;
3504 memset (&valuetype_this
, 0, sizeof (stackval
));
3505 if (!newobj_class
->enumtype
&& (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3507 valuetype_this
.data
.p
= vt_sp
;
3509 sp
->data
.p
= &valuetype_this
;
3512 if (newobj_class
!= mono_defaults
.string_class
) {
3513 o
= mono_object_new_checked (rtm
->domain
, newobj_class
, &error
);
3514 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3515 if (*mono_thread_interruption_request_flag ())
3516 mono_thread_interruption_checkpoint ();
3520 child_frame
.retval
= &retval
;
3524 g_assert (csig
->call_convention
== MONO_CALL_DEFAULT
);
3526 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
3528 context
->current_frame
= frame
;
3530 if (context
->has_resume_state
) {
3531 if (frame
== context
->handler_frame
)
3532 SET_RESUME_STATE (context
);
3537 if (child_frame
.ex
) {
3539 * An exception occurred, need to run finally, fault and catch handlers..
3541 frame
->ex
= child_frame
.ex
;
3542 goto handle_finally
;
3545 * a constructor returns void, but we need to return the object we created
3548 if (newobj_class
->valuetype
&& !newobj_class
->enumtype
) {
3549 *sp
= valuetype_this
;
3550 } else if (newobj_class
== mono_defaults
.string_class
) {
3558 MINT_IN_CASE(MINT_NEWOBJ_MAGIC
) {
3562 token
= * (guint16
*)(ip
+ 1);
3567 MINT_IN_CASE(MINT_CASTCLASS
)
3568 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3569 if ((o
= sp
[-1].data
.p
)) {
3570 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, &error
);
3571 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3573 THROW_EX (mono_get_exception_invalid_cast (), ip
);
3577 MINT_IN_CASE(MINT_ISINST
)
3578 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3579 if ((o
= sp
[-1].data
.p
)) {
3580 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, &error
);
3581 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3583 sp
[-1].data
.p
= NULL
;
3587 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
3588 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
3591 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
3592 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
3595 MINT_IN_CASE(MINT_UNBOX
)
3596 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3600 THROW_EX (mono_get_exception_null_reference (), ip
);
3602 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, &error
);
3603 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3604 if (!(isinst_obj
|| ((o
->vtable
->klass
->rank
== 0) && (o
->vtable
->klass
->element_class
== c
->element_class
))))
3605 THROW_EX (mono_get_exception_invalid_cast (), ip
);
3607 sp
[-1].data
.p
= mono_object_unbox (o
);
3610 MINT_IN_CASE(MINT_THROW
)
3612 frame
->ex_handler
= NULL
;
3614 sp
->data
.p
= mono_get_exception_null_reference ();
3616 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
3618 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
3620 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
3623 MINT_IN_CASE(MINT_LDFLDA
)
3626 THROW_EX (mono_get_exception_null_reference (), ip
);
3627 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
3630 MINT_IN_CASE(MINT_CKNULL
)
3633 THROW_EX (mono_get_exception_null_reference (), ip
);
3637 #define LDFLD(datamem, fieldtype) \
3638 o = sp [-1].data.p; \
3640 THROW_EX (mono_get_exception_null_reference (), ip); \
3641 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3644 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
3645 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
3646 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
3647 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
3648 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
3649 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
3650 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f
, float); MINT_IN_BREAK
;
3651 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
3652 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
3653 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
3655 MINT_IN_CASE(MINT_LDFLD_VT
)
3658 THROW_EX (mono_get_exception_null_reference (), ip
);
3660 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 2)];
3661 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3662 i32
= mono_class_value_size (klass
, NULL
);
3664 sp
[-1].data
.p
= vt_sp
;
3665 memcpy (sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
3666 vt_sp
+= (i32
+ 7) & ~7;
3670 MINT_IN_CASE(MINT_LDRMFLD
) {
3672 MonoClassField
*field
;
3677 THROW_EX (mono_get_exception_null_reference (), ip
);
3678 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3680 #ifndef DISABLE_REMOTING
3681 if (mono_object_is_transparent_proxy (o
)) {
3682 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3684 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, &error
);
3685 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3688 addr
= (char*)o
+ field
->offset
;
3690 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
3694 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
3695 MonoClassField
*field
;
3701 THROW_EX (mono_get_exception_null_reference (), ip
);
3703 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3704 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3705 i32
= mono_class_value_size (klass
, NULL
);
3708 #ifndef DISABLE_REMOTING
3709 if (mono_object_is_transparent_proxy (o
)) {
3710 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3711 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, &error
);
3712 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3715 addr
= (char*)o
+ field
->offset
;
3717 sp
[-1].data
.p
= vt_sp
;
3718 memcpy(sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
3719 vt_sp
+= (i32
+ 7) & ~7;
3720 memcpy(sp
[-1].data
.p
, addr
, i32
);
3724 #define STFLD(datamem, fieldtype) \
3725 o = sp [-2].data.p; \
3727 THROW_EX (mono_get_exception_null_reference (), ip); \
3729 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3732 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
3733 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
3734 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
3735 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
3736 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
3737 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
3738 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f
, float); MINT_IN_BREAK
;
3739 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
3740 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
3741 MINT_IN_CASE(MINT_STFLD_O
)
3744 THROW_EX (mono_get_exception_null_reference (), ip
);
3746 mono_gc_wbarrier_set_field (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.p
);
3750 MINT_IN_CASE(MINT_STFLD_VT
) {
3753 THROW_EX (mono_get_exception_null_reference (), ip
);
3756 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 2)];
3757 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3758 i32
= mono_class_value_size (klass
, NULL
);
3760 guint16 offset
= * (guint16
*)(ip
+ 1);
3761 mono_value_copy ((char *) o
+ offset
, sp
[1].data
.p
, klass
);
3763 vt_sp
-= (i32
+ 7) & ~7;
3767 MINT_IN_CASE(MINT_STRMFLD
) {
3768 MonoClassField
*field
;
3772 THROW_EX (mono_get_exception_null_reference (), ip
);
3774 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3777 #ifndef DISABLE_REMOTING
3778 if (mono_object_is_transparent_proxy (o
)) {
3779 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3780 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, &error
);
3781 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3784 stackval_to_data (field
->type
, &sp
[-1], (char*)o
+ field
->offset
, FALSE
);
3789 MINT_IN_CASE(MINT_STRMFLD_VT
) {
3790 MonoClassField
*field
;
3794 THROW_EX (mono_get_exception_null_reference (), ip
);
3795 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3796 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3797 i32
= mono_class_value_size (klass
, NULL
);
3800 #ifndef DISABLE_REMOTING
3801 if (mono_object_is_transparent_proxy (o
)) {
3802 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3803 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, &error
);
3804 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3807 mono_value_copy ((char *) o
+ field
->offset
, sp
[-1].data
.p
, klass
);
3810 vt_sp
-= (i32
+ 7) & ~7;
3813 MINT_IN_CASE(MINT_LDSFLDA
) {
3814 MonoClassField
*field
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3815 sp
->data
.p
= mono_class_static_field_address (rtm
->domain
, field
);
3820 MINT_IN_CASE(MINT_LDSFLD
) {
3821 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3822 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3823 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
3828 MINT_IN_CASE(MINT_LDSFLD_VT
) {
3829 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3830 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3831 int size
= READ32 (ip
+ 2);
3835 vt_sp
+= (size
+ 7) & ~7;
3836 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
3840 MINT_IN_CASE(MINT_STSFLD
) {
3841 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3842 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3845 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
3848 MINT_IN_CASE(MINT_STSFLD_VT
) {
3849 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3850 gpointer addr
= mono_class_static_field_address (rtm
->domain
, field
);
3851 MonoClass
*klass
= mono_class_from_mono_type (field
->type
);
3852 i32
= mono_class_value_size (klass
, NULL
);
3856 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
3857 vt_sp
-= (i32
+ 7) & ~7;
3860 MINT_IN_CASE(MINT_STOBJ_VT
) {
3862 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3864 size
= mono_class_value_size (c
, NULL
);
3865 memcpy(sp
[-2].data
.p
, sp
[-1].data
.p
, size
);
3866 vt_sp
-= (size
+ 7) & ~7;
3870 MINT_IN_CASE(MINT_STOBJ
) {
3871 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3874 g_assert (!c
->byval_arg
.byref
);
3875 if (MONO_TYPE_IS_REFERENCE (&c
->byval_arg
))
3876 mono_gc_wbarrier_generic_store (sp
[-2].data
.p
, sp
[-1].data
.p
);
3878 stackval_from_data (&c
->byval_arg
, sp
[-2].data
.p
, (char *) &sp
[-1].data
.p
, FALSE
);
3882 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
3883 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGUINT32_MAX
)
3884 THROW_EX (mono_get_exception_overflow (), ip
);
3885 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3888 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
3889 if (sp
[-1].data
.i
< 0)
3890 THROW_EX (mono_get_exception_overflow (), ip
);
3891 sp
[-1].data
.l
= sp
[-1].data
.i
;
3894 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
3895 if (sp
[-1].data
.l
< 0)
3896 THROW_EX (mono_get_exception_overflow (), ip
);
3899 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
3900 if ((guint64
) sp
[-1].data
.l
> MYGINT64_MAX
)
3901 THROW_EX (mono_get_exception_overflow (), ip
);
3904 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
3905 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
3906 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGINT64_MAX
)
3907 THROW_EX (mono_get_exception_overflow (), ip
);
3908 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
3911 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
3912 if (sp
[-1].data
.f
< MYGINT64_MIN
|| sp
[-1].data
.f
> MYGINT64_MAX
)
3913 THROW_EX (mono_get_exception_overflow (), ip
);
3914 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
3917 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
3918 if ((mono_u
)sp
[-1].data
.l
> MYGUINT32_MAX
)
3919 THROW_EX (mono_get_exception_overflow (), ip
);
3920 sp
[-1].data
.i
= (mono_u
)sp
[-1].data
.l
;
3923 MINT_IN_CASE(MINT_BOX
) {
3924 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3925 guint16 offset
= * (guint16
*)(ip
+ 2);
3926 gboolean pop_vt_sp
= !(offset
& BOX_NOT_CLEAR_VT_SP
);
3927 offset
&= ~BOX_NOT_CLEAR_VT_SP
;
3929 if (mint_type (&c
->byval_arg
) == MINT_TYPE_VT
&& !c
->enumtype
&& !(mono_class_is_magic_int (c
) || mono_class_is_magic_float (c
))) {
3930 int size
= mono_class_value_size (c
, NULL
);
3931 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, sp
[-1 - offset
].data
.p
, &error
);
3932 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3933 size
= (size
+ 7) & ~7;
3937 stackval_to_data (&c
->byval_arg
, &sp
[-1 - offset
], (char *) &sp
[-1 - offset
], FALSE
);
3938 sp
[-1 - offset
].data
.p
= mono_value_box_checked (rtm
->domain
, c
, &sp
[-1 - offset
], &error
);
3939 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3944 MINT_IN_CASE(MINT_NEWARR
)
3945 sp
[-1].data
.p
= (MonoObject
*) mono_array_new_checked (rtm
->domain
, rtm
->data_items
[*(guint16
*)(ip
+ 1)], sp
[-1].data
.i
, &error
);
3946 if (!mono_error_ok (&error
)) {
3947 THROW_EX (mono_error_convert_to_exception (&error
), ip
);
3949 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3951 /*if (profiling_classes) {
3952 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3954 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3958 MINT_IN_CASE(MINT_LDLEN
)
3961 THROW_EX (mono_get_exception_null_reference (), ip
);
3962 sp
[-1].data
.nati
= mono_array_length ((MonoArray
*)o
);
3965 MINT_IN_CASE(MINT_GETCHR
) {
3969 THROW_EX (mono_get_exception_null_reference (), ip
);
3970 i32
= sp
[-1].data
.i
;
3971 if (i32
< 0 || i32
>= mono_string_length (s
))
3972 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
3974 sp
[-1].data
.i
= mono_string_chars(s
)[i32
];
3978 MINT_IN_CASE(MINT_STRLEN
)
3982 THROW_EX (mono_get_exception_null_reference (), ip
);
3983 sp
[-1].data
.i
= mono_string_length ((MonoString
*) o
);
3985 MINT_IN_CASE(MINT_ARRAY_RANK
)
3988 THROW_EX (mono_get_exception_null_reference (), ip
);
3989 sp
[-1].data
.i
= mono_object_class (sp
[-1].data
.p
)->rank
;
3992 MINT_IN_CASE(MINT_LDELEMA
)
3993 MINT_IN_CASE(MINT_LDELEMA_TC
) {
3994 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
3996 MonoClass
*klass
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
3997 guint16 numargs
= *(guint16
*) (ip
+ 2);
4002 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
4004 THROW_EX (frame
->ex
, ip
);
4009 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
4010 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
4011 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
4012 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
4013 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
4014 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
4015 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
4016 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
4017 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
4018 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
4019 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
4020 MINT_IN_CASE(MINT_LDELEM_VT
) {
4028 THROW_EX (mono_get_exception_null_reference (), ip
);
4030 aindex
= sp
[1].data
.i
;
4031 if (aindex
>= mono_array_length (o
))
4032 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4035 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4038 case MINT_LDELEM_I1
:
4039 sp
[0].data
.i
= mono_array_get (o
, gint8
, aindex
);
4041 case MINT_LDELEM_U1
:
4042 sp
[0].data
.i
= mono_array_get (o
, guint8
, aindex
);
4044 case MINT_LDELEM_I2
:
4045 sp
[0].data
.i
= mono_array_get (o
, gint16
, aindex
);
4047 case MINT_LDELEM_U2
:
4048 sp
[0].data
.i
= mono_array_get (o
, guint16
, aindex
);
4051 sp
[0].data
.nati
= mono_array_get (o
, mono_i
, aindex
);
4053 case MINT_LDELEM_I4
:
4054 sp
[0].data
.i
= mono_array_get (o
, gint32
, aindex
);
4056 case MINT_LDELEM_U4
:
4057 sp
[0].data
.i
= mono_array_get (o
, guint32
, aindex
);
4059 case MINT_LDELEM_I8
:
4060 sp
[0].data
.l
= mono_array_get (o
, guint64
, aindex
);
4062 case MINT_LDELEM_R4
:
4063 sp
[0].data
.f
= mono_array_get (o
, float, aindex
);
4065 case MINT_LDELEM_R8
:
4066 sp
[0].data
.f
= mono_array_get (o
, double, aindex
);
4068 case MINT_LDELEM_REF
:
4069 sp
[0].data
.p
= mono_array_get (o
, gpointer
, aindex
);
4071 case MINT_LDELEM_VT
: {
4072 MonoClass
*klass_vt
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4073 i32
= READ32 (ip
+ 2);
4074 char *src_addr
= mono_array_addr_with_size ((MonoArray
*) o
, i32
, aindex
);
4075 sp
[0].data
.vt
= vt_sp
;
4076 stackval_from_data (&klass_vt
->byval_arg
, sp
, src_addr
, FALSE
);
4077 vt_sp
+= (i32
+ 7) & ~7;
4089 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
4090 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
4091 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
4092 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
4093 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
4094 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
4095 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
4096 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
4097 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
4098 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
4099 MINT_IN_CASE(MINT_STELEM_VT
) {
4106 THROW_EX (mono_get_exception_null_reference (), ip
);
4108 aindex
= sp
[1].data
.i
;
4109 if (aindex
>= mono_array_length ((MonoArray
*)o
))
4110 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4114 mono_array_set ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
4116 case MINT_STELEM_I1
:
4117 mono_array_set ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
4119 case MINT_STELEM_U1
:
4120 mono_array_set ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
4122 case MINT_STELEM_I2
:
4123 mono_array_set ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
4125 case MINT_STELEM_U2
:
4126 mono_array_set ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
4128 case MINT_STELEM_I4
:
4129 mono_array_set ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
4131 case MINT_STELEM_I8
:
4132 mono_array_set ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
4134 case MINT_STELEM_R4
:
4135 mono_array_set ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f
);
4137 case MINT_STELEM_R8
:
4138 mono_array_set ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
4140 case MINT_STELEM_REF
: {
4141 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.p
, mono_object_class (o
)->element_class
, &error
);
4142 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4143 if (sp
[2].data
.p
&& !isinst_obj
)
4144 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
4145 mono_array_setref ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
4148 case MINT_STELEM_VT
: {
4149 MonoClass
*klass_vt
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4150 i32
= READ32 (ip
+ 2);
4151 char *dst_addr
= mono_array_addr_with_size ((MonoArray
*) o
, i32
, aindex
);
4153 stackval_to_data (&klass_vt
->byval_arg
, &sp
[2], dst_addr
, FALSE
);
4154 vt_sp
-= (i32
+ 7) & ~7;
4165 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
4166 if (sp
[-1].data
.i
< 0)
4167 THROW_EX (mono_get_exception_overflow (), ip
);
4170 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
4171 if (sp
[-1].data
.l
< MYGINT32_MIN
|| sp
[-1].data
.l
> MYGINT32_MAX
)
4172 THROW_EX (mono_get_exception_overflow (), ip
);
4173 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4176 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
4177 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> MYGINT32_MAX
)
4178 THROW_EX (mono_get_exception_overflow (), ip
);
4179 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4182 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
4183 if (sp
[-1].data
.f
< MYGINT32_MIN
|| sp
[-1].data
.f
> MYGINT32_MAX
)
4184 THROW_EX (mono_get_exception_overflow (), ip
);
4185 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
4188 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
4189 if (sp
[-1].data
.i
< 0)
4190 THROW_EX (mono_get_exception_overflow (), ip
);
4193 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
4194 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> MYGUINT32_MAX
)
4195 THROW_EX (mono_get_exception_overflow (), ip
);
4196 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
4199 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
4200 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGUINT32_MAX
)
4201 THROW_EX (mono_get_exception_overflow (), ip
);
4202 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4205 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
4206 if (sp
[-1].data
.i
< -32768 || sp
[-1].data
.i
> 32767)
4207 THROW_EX (mono_get_exception_overflow (), ip
);
4210 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
4211 if (sp
[-1].data
.l
< -32768 || sp
[-1].data
.l
> 32767)
4212 THROW_EX (mono_get_exception_overflow (), ip
);
4213 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
4216 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
4217 if (sp
[-1].data
.f
< -32768 || sp
[-1].data
.f
> 32767)
4218 THROW_EX (mono_get_exception_overflow (), ip
);
4219 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
4222 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
4223 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> 65535)
4224 THROW_EX (mono_get_exception_overflow (), ip
);
4227 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
4228 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> 65535)
4229 THROW_EX (mono_get_exception_overflow (), ip
);
4230 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
4233 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
4234 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> 65535)
4235 THROW_EX (mono_get_exception_overflow (), ip
);
4236 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
4239 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
4240 if (sp
[-1].data
.i
< -128 || sp
[-1].data
.i
> 127)
4241 THROW_EX (mono_get_exception_overflow (), ip
);
4244 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
4245 if (sp
[-1].data
.l
< -128 || sp
[-1].data
.l
> 127)
4246 THROW_EX (mono_get_exception_overflow (), ip
);
4247 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
4250 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
4251 if (sp
[-1].data
.f
< -128 || sp
[-1].data
.f
> 127)
4252 THROW_EX (mono_get_exception_overflow (), ip
);
4253 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
4256 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
4257 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> 255)
4258 THROW_EX (mono_get_exception_overflow (), ip
);
4261 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
4262 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> 255)
4263 THROW_EX (mono_get_exception_overflow (), ip
);
4264 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
4267 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
4268 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> 255)
4269 THROW_EX (mono_get_exception_overflow (), ip
);
4270 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
4274 MINT_IN_CASE(MINT_LDELEM
)
4275 MINT_IN_CASE(MINT_STELEM
)
4276 MINT_IN_CASE(MINT_UNBOX_ANY
)
4278 MINT_IN_CASE(MINT_CKFINITE
)
4279 if (!isfinite(sp
[-1].data
.f
))
4280 THROW_EX (mono_get_exception_arithmetic (), ip
);
4283 MINT_IN_CASE(MINT_MKREFANY
) {
4284 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4286 /* The value address is on the stack */
4287 gpointer addr
= sp
[-1].data
.p
;
4288 /* Push the typedref value on the stack */
4289 sp
[-1].data
.p
= vt_sp
;
4290 vt_sp
+= sizeof (MonoTypedRef
);
4292 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4294 tref
->type
= &c
->byval_arg
;
4300 MINT_IN_CASE(MINT_REFANYTYPE
) {
4301 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4302 MonoType
*type
= tref
->type
;
4304 vt_sp
-= sizeof (MonoTypedRef
);
4305 sp
[-1].data
.p
= vt_sp
;
4307 *(gpointer
*)sp
[-1].data
.p
= type
;
4311 MINT_IN_CASE(MINT_REFANYVAL
) {
4312 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4313 gpointer addr
= tref
->value
;
4315 vt_sp
-= sizeof (MonoTypedRef
);
4317 sp
[-1].data
.p
= addr
;
4321 MINT_IN_CASE(MINT_LDTOKEN
)
4324 * (gpointer
*)sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4328 MINT_IN_CASE(MINT_ADD_OVF_I4
)
4329 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4330 THROW_EX (mono_get_exception_overflow (), ip
);
4333 MINT_IN_CASE(MINT_ADD_OVF_I8
)
4334 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4335 THROW_EX (mono_get_exception_overflow (), ip
);
4338 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
4339 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4340 THROW_EX (mono_get_exception_overflow (), ip
);
4341 BINOP_CAST(i
, +, guint32
);
4343 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
4344 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4345 THROW_EX (mono_get_exception_overflow (), ip
);
4346 BINOP_CAST(l
, +, guint64
);
4348 MINT_IN_CASE(MINT_MUL_OVF_I4
)
4349 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4350 THROW_EX (mono_get_exception_overflow (), ip
);
4353 MINT_IN_CASE(MINT_MUL_OVF_I8
)
4354 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4355 THROW_EX (mono_get_exception_overflow (), ip
);
4358 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
4359 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4360 THROW_EX (mono_get_exception_overflow (), ip
);
4361 BINOP_CAST(i
, *, guint32
);
4363 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
4364 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4365 THROW_EX (mono_get_exception_overflow (), ip
);
4366 BINOP_CAST(l
, *, guint64
);
4368 MINT_IN_CASE(MINT_SUB_OVF_I4
)
4369 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4370 THROW_EX (mono_get_exception_overflow (), ip
);
4373 MINT_IN_CASE(MINT_SUB_OVF_I8
)
4374 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4375 THROW_EX (mono_get_exception_overflow (), ip
);
4378 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
4379 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4380 THROW_EX (mono_get_exception_overflow (), ip
);
4381 BINOP_CAST(i
, -, guint32
);
4383 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
4384 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4385 THROW_EX (mono_get_exception_overflow (), ip
);
4386 BINOP_CAST(l
, -, guint64
);
4388 MINT_IN_CASE(MINT_ENDFINALLY
)
4390 int clause_index
= *ip
;
4391 if (clause_index
== exit_at_finally
)
4393 while (sp
> frame
->stack
) {
4397 ip
= finally_ips
->data
;
4398 finally_ips
= g_slist_remove (finally_ips
, ip
);
4405 MINT_IN_CASE(MINT_LEAVE
) /* Fall through */
4406 MINT_IN_CASE(MINT_LEAVE_S
)
4407 while (sp
> frame
->stack
) {
4412 if (frame
->ex_handler
!= NULL
&& MONO_OFFSET_IN_HANDLER(frame
->ex_handler
, frame
->ip
- rtm
->code
)) {
4413 MonoException
*exc
= frame
->ex
;
4414 frame
->ex_handler
= NULL
;
4416 if (frame
->imethod
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
) {
4417 MonoException
*abort_exc
= mono_thread_get_undeniable_exception ();
4419 THROW_EX (abort_exc
, frame
->ip
);
4424 if (*ip
== MINT_LEAVE_S
) {
4425 ip
+= (short) *(ip
+ 1);
4427 ip
+= (gint32
) READ32 (ip
+ 1);
4430 goto handle_finally
;
4432 MINT_IN_CASE(MINT_ICALL_V_V
)
4433 MINT_IN_CASE(MINT_ICALL_V_P
)
4434 MINT_IN_CASE(MINT_ICALL_P_V
)
4435 MINT_IN_CASE(MINT_ICALL_P_P
)
4436 MINT_IN_CASE(MINT_ICALL_PP_V
)
4437 MINT_IN_CASE(MINT_ICALL_PI_V
)
4438 MINT_IN_CASE(MINT_ICALL_PP_P
)
4439 MINT_IN_CASE(MINT_ICALL_PI_P
)
4440 MINT_IN_CASE(MINT_ICALL_PPP_V
)
4441 MINT_IN_CASE(MINT_ICALL_PPI_V
)
4442 sp
= do_icall (context
, *ip
, sp
, rtm
->data_items
[*(guint16
*)(ip
+ 1)]);
4443 if (*mono_thread_interruption_request_flag ()) {
4444 MonoException
*exc
= mono_thread_interruption_checkpoint ();
4447 context
->search_for_handler
= 1;
4450 if (frame
->ex
!= NULL
)
4451 goto handle_exception
;
4454 MINT_IN_CASE(MINT_MONO_LDPTR
)
4455 sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4459 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
4460 sp
->data
.p
= mono_object_new_checked (rtm
->domain
, rtm
->data_items
[*(guint16
*)(ip
+ 1)], &error
);
4461 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4465 MINT_IN_CASE(MINT_MONO_FREE
)
4468 g_error ("that doesn't seem right");
4469 g_free (sp
->data
.p
);
4471 MINT_IN_CASE(MINT_MONO_RETOBJ
)
4474 stackval_from_data (mono_method_signature (frame
->imethod
->method
)->ret
, frame
->retval
, sp
->data
.p
,
4475 mono_method_signature (frame
->imethod
->method
)->pinvoke
);
4476 if (sp
> frame
->stack
)
4477 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
4479 MINT_IN_CASE(MINT_MONO_TLS
) {
4480 MonoTlsKey key
= *(gint32
*)(ip
+ 1);
4481 sp
->data
.p
= ((gpointer (*)(void)) mono_tls_get_tls_getter (key
, FALSE
)) ();
4486 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER
) {
4488 mono_memory_barrier ();
4491 MINT_IN_CASE(MINT_MONO_JIT_ATTACH
) {
4494 context
->original_domain
= NULL
;
4495 MonoDomain
*tls_domain
= (MonoDomain
*) ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_DOMAIN
, FALSE
)) ();
4496 gpointer tls_jit
= ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_JIT_TLS
, FALSE
)) ();
4498 if (tls_domain
!= rtm
->domain
|| !tls_jit
)
4499 context
->original_domain
= mono_jit_thread_attach (rtm
->domain
);
4502 MINT_IN_CASE(MINT_MONO_JIT_DETACH
)
4504 mono_jit_set_domain (context
->original_domain
);
4506 MINT_IN_CASE(MINT_MONO_LDDOMAIN
)
4507 sp
->data
.p
= mono_domain_get ();
4511 MINT_IN_CASE(MINT_SDB_INTR_LOC
)
4512 if (G_UNLIKELY (ss_enabled
)) {
4513 static void (*ss_tramp
) (void);
4516 void *tramp
= mini_get_single_step_trampoline ();
4517 mono_memory_barrier ();
4522 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
4523 * the address of that instruction is stored as the seq point address.
4528 * Use the same trampoline as the JIT. This ensures that
4529 * the debugger has the context for the last interpreter
4532 do_debugger_tramp (ss_tramp
, frame
);
4534 if (context
->has_resume_state
) {
4535 if (frame
== context
->handler_frame
)
4536 SET_RESUME_STATE (context
);
4543 MINT_IN_CASE(MINT_SDB_SEQ_POINT
)
4544 /* Just a placeholder for a breakpoint */
4547 MINT_IN_CASE(MINT_SDB_BREAKPOINT
) {
4548 static void (*bp_tramp
) (void);
4550 void *tramp
= mini_get_breakpoint_trampoline ();
4551 mono_memory_barrier ();
4557 /* Use the same trampoline as the JIT */
4558 do_debugger_tramp (bp_tramp
, frame
);
4560 if (context
->has_resume_state
) {
4561 if (frame
== context
->handler_frame
)
4562 SET_RESUME_STATE (context
);
4571 #define RELOP(datamem, op) \
4573 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4576 #define RELOP_FP(datamem, op, noorder) \
4578 if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
4579 sp [-1].data.i = noorder; \
4581 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4584 MINT_IN_CASE(MINT_CEQ_I4
)
4587 MINT_IN_CASE(MINT_CEQ0_I4
)
4588 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
4591 MINT_IN_CASE(MINT_CEQ_I8
)
4594 MINT_IN_CASE(MINT_CEQ_R8
)
4597 MINT_IN_CASE(MINT_CNE_I4
)
4600 MINT_IN_CASE(MINT_CNE_I8
)
4603 MINT_IN_CASE(MINT_CNE_R8
)
4606 MINT_IN_CASE(MINT_CGT_I4
)
4609 MINT_IN_CASE(MINT_CGT_I8
)
4612 MINT_IN_CASE(MINT_CGT_R8
)
4615 MINT_IN_CASE(MINT_CGE_I4
)
4618 MINT_IN_CASE(MINT_CGE_I8
)
4621 MINT_IN_CASE(MINT_CGE_R8
)
4625 #define RELOP_CAST(datamem, op, type) \
4627 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4630 MINT_IN_CASE(MINT_CGE_UN_I4
)
4631 RELOP_CAST(l
, >=, guint32
);
4633 MINT_IN_CASE(MINT_CGE_UN_I8
)
4634 RELOP_CAST(l
, >=, guint64
);
4637 MINT_IN_CASE(MINT_CGT_UN_I4
)
4638 RELOP_CAST(i
, >, guint32
);
4640 MINT_IN_CASE(MINT_CGT_UN_I8
)
4641 RELOP_CAST(l
, >, guint64
);
4643 MINT_IN_CASE(MINT_CGT_UN_R8
)
4646 MINT_IN_CASE(MINT_CLT_I4
)
4649 MINT_IN_CASE(MINT_CLT_I8
)
4652 MINT_IN_CASE(MINT_CLT_R8
)
4655 MINT_IN_CASE(MINT_CLT_UN_I4
)
4656 RELOP_CAST(i
, <, guint32
);
4658 MINT_IN_CASE(MINT_CLT_UN_I8
)
4659 RELOP_CAST(l
, <, guint64
);
4661 MINT_IN_CASE(MINT_CLT_UN_R8
)
4664 MINT_IN_CASE(MINT_CLE_I4
)
4667 MINT_IN_CASE(MINT_CLE_I8
)
4670 MINT_IN_CASE(MINT_CLE_UN_I4
)
4671 RELOP_CAST(l
, <=, guint32
);
4673 MINT_IN_CASE(MINT_CLE_UN_I8
)
4674 RELOP_CAST(l
, <=, guint64
);
4676 MINT_IN_CASE(MINT_CLE_R8
)
4684 MINT_IN_CASE(MINT_LDFTN
) {
4685 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4690 MINT_IN_CASE(MINT_LDVIRTFTN
) {
4691 InterpMethod
*m
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4695 THROW_EX (mono_get_exception_null_reference (), ip
- 2);
4697 sp
->data
.p
= get_virtual_method (m
, sp
->data
.p
);
4702 #define LDARG(datamem, argtype) \
4703 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4707 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
4708 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
4709 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
4710 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
4711 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
4712 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
4713 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f
, float); MINT_IN_BREAK
;
4714 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
4715 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
4716 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
4718 MINT_IN_CASE(MINT_LDARG_VT
)
4720 i32
= READ32(ip
+ 2);
4721 memcpy(sp
->data
.p
, frame
->args
+ * (guint16
*)(ip
+ 1), i32
);
4722 vt_sp
+= (i32
+ 7) & ~7;
4727 #define STARG(datamem, argtype) \
4729 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4732 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
4733 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
4734 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
4735 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
4736 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
4737 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
4738 MINT_IN_CASE(MINT_STARG_R4
) STARG(f
, float); MINT_IN_BREAK
;
4739 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
4740 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
4741 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
4743 MINT_IN_CASE(MINT_STARG_VT
)
4744 i32
= READ32(ip
+ 2);
4746 memcpy(frame
->args
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
4747 vt_sp
-= (i32
+ 7) & ~7;
4751 #define STINARG(datamem, argtype) \
4753 int n = * (guint16 *)(ip + 1); \
4754 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4758 MINT_IN_CASE(MINT_STINARG_I1
) STINARG(i
, gint8
); MINT_IN_BREAK
;
4759 MINT_IN_CASE(MINT_STINARG_U1
) STINARG(i
, guint8
); MINT_IN_BREAK
;
4760 MINT_IN_CASE(MINT_STINARG_I2
) STINARG(i
, gint16
); MINT_IN_BREAK
;
4761 MINT_IN_CASE(MINT_STINARG_U2
) STINARG(i
, guint16
); MINT_IN_BREAK
;
4762 MINT_IN_CASE(MINT_STINARG_I4
) STINARG(i
, gint32
); MINT_IN_BREAK
;
4763 MINT_IN_CASE(MINT_STINARG_I8
) STINARG(l
, gint64
); MINT_IN_BREAK
;
4764 MINT_IN_CASE(MINT_STINARG_R4
) STINARG(f
, float); MINT_IN_BREAK
;
4765 MINT_IN_CASE(MINT_STINARG_R8
) STINARG(f
, double); MINT_IN_BREAK
;
4766 MINT_IN_CASE(MINT_STINARG_O
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
4767 MINT_IN_CASE(MINT_STINARG_P
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
4769 MINT_IN_CASE(MINT_STINARG_VT
) {
4770 int n
= * (guint16
*)(ip
+ 1);
4771 i32
= READ32(ip
+ 2);
4772 memcpy (frame
->args
+ rtm
->arg_offsets
[n
], frame
->stack_args
[n
].data
.p
, i32
);
4777 MINT_IN_CASE(MINT_PROF_ENTER
) {
4780 if (MONO_PROFILER_ENABLED (method_enter
)) {
4781 MonoProfilerCallContext
*prof_ctx
= NULL
;
4783 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT
) {
4784 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
4785 prof_ctx
->interp_frame
= frame
;
4786 prof_ctx
->method
= frame
->imethod
->method
;
4789 MONO_PROFILER_RAISE (method_enter
, (frame
->imethod
->method
, prof_ctx
));
4797 MINT_IN_CASE(MINT_LDARGA
)
4798 sp
->data
.p
= frame
->args
+ * (guint16
*)(ip
+ 1);
4803 #define LDLOC(datamem, argtype) \
4804 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4808 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
4809 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
4810 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
4811 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
4812 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
4813 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
4814 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f
, float); MINT_IN_BREAK
;
4815 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
4816 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
4817 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
4819 MINT_IN_CASE(MINT_LDLOC_VT
)
4821 i32
= READ32(ip
+ 2);
4822 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
4823 vt_sp
+= (i32
+ 7) & ~7;
4828 MINT_IN_CASE(MINT_LDLOCA_S
)
4829 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
4834 #define STLOC(datamem, argtype) \
4836 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4839 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
4840 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
4841 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
4842 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
4843 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
4844 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
4845 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f
, float); MINT_IN_BREAK
;
4846 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
4847 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
4848 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
4850 #define STLOC_NP(datamem, argtype) \
4851 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4854 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
4855 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
4857 MINT_IN_CASE(MINT_STLOC_VT
)
4858 i32
= READ32(ip
+ 2);
4860 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
4861 vt_sp
-= (i32
+ 7) & ~7;
4865 MINT_IN_CASE(MINT_LOCALLOC
) {
4866 if (sp
!= frame
->stack
+ 1) /*FIX?*/
4867 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
4869 int len
= sp
[-1].data
.i
;
4870 sp
[-1].data
.p
= alloca (len
);
4872 if (frame
->imethod
->init_locals
)
4873 memset (sp
[-1].data
.p
, 0, len
);
4877 MINT_IN_CASE(MINT_ENDFILTER
)
4878 /* top of stack is result of filter */
4879 frame
->retval
= &sp
[-1];
4881 MINT_IN_CASE(MINT_INITOBJ
)
4883 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
4886 MINT_IN_CASE(MINT_CPBLK
)
4888 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
4889 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
4891 /* FIXME: value and size may be int64... */
4892 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
4895 MINT_IN_CASE(MINT_CONSTRAINED_
) {
4897 /* FIXME: implement */
4899 token
= READ32 (ip
);
4904 MINT_IN_CASE(MINT_INITBLK
)
4907 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
4909 /* FIXME: value and size may be int64... */
4910 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
4913 MINT_IN_CASE(MINT_NO_
)
4914 /* FIXME: implement */
4918 MINT_IN_CASE(MINT_RETHROW
) {
4920 * need to clarify what this should actually do:
4921 * start the search from the last found handler in
4922 * this method or continue in the caller or what.
4923 * Also, do we need to run finally/fault handlers after a retrow?
4924 * Well, this implementation will follow the usual search
4925 * for an handler, considering the current ip as throw spot.
4926 * We need to NULL frame->ex_handler for the later code to
4927 * actually run the new found handler.
4929 int exvar_offset
= *(guint16
*)(ip
+ 1);
4930 frame
->ex_handler
= NULL
;
4931 THROW_EX_GENERAL (*(MonoException
**)(frame
->locals
+ exvar_offset
), ip
- 1, TRUE
);
4935 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-rtm
->code
);
4936 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip
);
4940 g_assert_not_reached ();
4942 * Exception handling code.
4943 * The exception object is stored in frame->ex.
4951 MonoExceptionClause
*clause
;
4957 g_print ("* Handling exception '%s' at IL_%04x\n",
4958 frame
->ex
== NULL
? "** Unknown **" : mono_object_class (frame
->ex
)->name
,
4959 rtm
== NULL
? 0 : frame
->ip
- rtm
->code
);
4961 if (die_on_exception
)
4964 for (inv
= frame
; inv
; inv
= inv
->parent
) {
4966 if (inv
->imethod
== NULL
)
4968 method
= inv
->imethod
->method
;
4969 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
4971 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))
4973 if (inv
->ip
== NULL
)
4975 ip_offset
= inv
->ip
- inv
->imethod
->code
;
4976 inv
->ex_handler
= NULL
; /* clear this in case we are trhowing an exception while handling one - this one wins */
4977 for (i
= 0; i
< inv
->imethod
->num_clauses
; ++i
) {
4978 clause
= &inv
->imethod
->clauses
[i
];
4980 g_print ("* clause [%d]: %p\n", i
, clause
);
4982 if (!MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
)) {
4985 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4988 g_print ("* Filter found at '%s'\n", method
->name
);
4990 InterpFrame dup_frame
;
4992 memcpy (&dup_frame
, inv
, sizeof (InterpFrame
));
4993 dup_frame
.retval
= &retval
;
4994 ves_exec_method_with_context (&dup_frame
, context
, inv
->imethod
->code
+ clause
->data
.filter_offset
, frame
->ex
, -1);
4995 if (dup_frame
.retval
->data
.i
) {
4998 g_print ("* Matched Filter at '%s'\n", method
->name
);
5000 inv
->ex_handler
= clause
;
5001 *(MonoException
**)(inv
->locals
+ inv
->imethod
->exvar_offsets
[i
]) = frame
->ex
;
5002 goto handle_finally
;
5004 } else if (clause
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) {
5005 MonoObject
*isinst_obj
= mono_object_isinst_checked ((MonoObject
*)frame
->ex
, clause
->data
.catch_class
, &error
);
5006 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
5009 * OK, we found an handler, now we need to execute the finally
5010 * and fault blocks before branching to the handler code.
5014 g_print ("* Found handler at '%s'\n", method
->name
);
5016 inv
->ex_handler
= clause
;
5017 *(MonoException
**)(inv
->locals
+ inv
->imethod
->exvar_offsets
[i
]) = frame
->ex
;
5018 goto handle_finally
;
5024 * If we get here, no handler was found: print a stack trace.
5026 for (inv
= frame
; inv
; inv
= inv
->parent
) {
5027 if (inv
->invoke_trap
)
5028 goto handle_finally
;
5031 ex_obj
= (MonoObject
*) frame
->ex
;
5032 mono_unhandled_exception (ex_obj
);
5033 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*) mono_tls_get_jit_tls ();
5034 jit_tls
->abort_func (ex_obj
);
5035 g_assert_not_reached ();
5041 MonoExceptionClause
*clause
;
5042 GSList
*old_list
= finally_ips
;
5043 MonoMethod
*method
= frame
->imethod
->method
;
5047 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- rtm
->code
);
5049 if (rtm
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
5050 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
5053 ip_offset
= frame
->ip
- rtm
->code
;
5055 if (endfinally_ip
!= NULL
)
5056 finally_ips
= g_slist_prepend(finally_ips
, (void *)endfinally_ip
);
5057 for (i
= 0; i
< rtm
->num_clauses
; ++i
)
5058 if (frame
->ex_handler
== &rtm
->clauses
[i
])
5063 clause
= &rtm
->clauses
[i
];
5064 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- rtm
->code
)))) {
5065 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5066 ip
= rtm
->code
+ clause
->handler_offset
;
5067 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5070 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
5076 endfinally_ip
= NULL
;
5078 if (old_list
!= finally_ips
&& finally_ips
) {
5079 ip
= finally_ips
->data
;
5080 finally_ips
= g_slist_remove (finally_ips
, ip
);
5081 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5086 * If an exception is set, we need to execute the fault handler, too,
5087 * otherwise, we continue normally.
5097 MonoExceptionClause
*clause
;
5098 GSList
*old_list
= finally_ips
;
5102 g_print ("* Handle fault\n");
5104 ip_offset
= frame
->ip
- rtm
->code
;
5106 for (i
= 0; i
< rtm
->num_clauses
; ++i
) {
5107 clause
= &rtm
->clauses
[i
];
5108 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
&& MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
)) {
5109 ip
= rtm
->code
+ clause
->handler_offset
;
5110 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
5113 g_print ("* Executing handler at IL_%04x\n", clause
->handler_offset
);
5118 if (old_list
!= finally_ips
&& finally_ips
) {
5119 ip
= finally_ips
->data
;
5120 finally_ips
= g_slist_remove (finally_ips
, ip
);
5121 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
5128 * If the handler for the exception was found in this method, we jump
5129 * to it right away, otherwise we return and let the caller run
5130 * the finally, fault and catch blocks.
5131 * This same code should be present in the endfault opcode, but it
5132 * is corrently not assigned in the ECMA specs: LAMESPEC.
5134 if (frame
->ex_handler
) {
5137 g_print ("* Executing handler at IL_%04x\n", frame
->ex_handler
->handler_offset
);
5139 ip
= rtm
->code
+ frame
->ex_handler
->handler_offset
;
5141 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
5142 sp
->data
.p
= frame
->ex
;
5151 /* make sure we don't miss to pop a LMF */
5152 MonoLMF
*lmf
= mono_get_lmf ();
5153 if (lmf
&& (gsize
) lmf
->previous_lmf
& 2) {
5154 MonoLMFExt
*ext
= (MonoLMFExt
*) lmf
;
5155 if (ext
->interp_exit
&& ext
->interp_exit_data
== frame
->parent
)
5156 interp_pop_lmf (ext
);
5162 if (!frame
->ex
&& MONO_PROFILER_ENABLED (method_leave
) &&
5163 frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
) {
5164 MonoProfilerCallContext
*prof_ctx
= NULL
;
5166 if (frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT
) {
5167 prof_ctx
= g_new0 (MonoProfilerCallContext
, 1);
5168 prof_ctx
->interp_frame
= frame
;
5169 prof_ctx
->method
= frame
->imethod
->method
;
5171 MonoType
*rtype
= mono_method_signature (frame
->imethod
->method
)->ret
;
5173 switch (rtype
->type
) {
5174 case MONO_TYPE_VOID
:
5176 case MONO_TYPE_VALUETYPE
:
5177 prof_ctx
->return_value
= frame
->retval
->data
.p
;
5180 prof_ctx
->return_value
= frame
->retval
;
5185 MONO_PROFILER_RAISE (method_leave
, (frame
->imethod
->method
, prof_ctx
));
5188 } else if (frame
->ex
&& frame
->imethod
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
)
5189 MONO_PROFILER_RAISE (method_exception_leave
, (frame
->imethod
->method
, &frame
->ex
->object
));
5195 mono_interp_parse_options (const char *options
)
5199 args
= g_strsplit (options
, ",", -1);
5200 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
5203 if (strncmp (arg
, "jit=", 4) == 0)
5204 jit_classes
= g_slist_prepend (jit_classes
, arg
+ 4);
5211 mono_native_tls_alloc (&thread_context_id
, NULL
);
5214 mono_interp_transform_init ();
5217 typedef int (*TestMethod
) (void);
5220 interp_regression_step (MonoImage
*image
, int verbose
, int *total_run
, int *total
, GTimer
*timer
, MonoDomain
*domain
)
5222 int result
, expected
, failed
, cfailed
, run
;
5223 double elapsed
, transform_time
;
5225 MonoObject
*result_obj
;
5226 static gboolean filter_method_init
= FALSE
;
5227 static const char *filter_method
= NULL
;
5229 g_print ("Test run: image=%s\n", mono_image_get_filename (image
));
5230 cfailed
= failed
= run
= 0;
5231 transform_time
= elapsed
= 0.0;
5233 g_timer_start (timer
);
5234 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
5235 MonoObject
*exc
= NULL
;
5237 MonoMethod
*method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
5239 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
5243 if (!filter_method_init
) {
5244 filter_method
= g_getenv ("INTERP_FILTER_METHOD");
5245 filter_method_init
= TRUE
;
5247 gboolean filter
= FALSE
;
5248 if (filter_method
) {
5249 const char *name
= filter_method
;
5251 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
5252 MonoMethodDesc
*desc
= mono_method_desc_new (name
, TRUE
);
5253 filter
= mono_method_desc_full_match (desc
, method
);
5254 mono_method_desc_free (desc
);
5256 filter
= strcmp (method
->name
, name
) == 0;
5258 } else { /* no filter, check for `Category' attribute on method */
5260 MonoCustomAttrInfo
* ainfo
= mono_custom_attrs_from_method_checked (method
, &error
);
5261 mono_error_cleanup (&error
);
5265 for (j
= 0; j
< ainfo
->num_attrs
&& filter
; ++j
) {
5266 MonoCustomAttrEntry
*centry
= &ainfo
->attrs
[j
];
5267 if (centry
->ctor
== NULL
)
5270 MonoClass
*klass
= centry
->ctor
->klass
;
5271 if (strcmp (klass
->name
, "CategoryAttribute"))
5274 MonoObject
*obj
= mono_custom_attrs_get_attr_checked (ainfo
, klass
, &error
);
5275 /* FIXME: there is an ordering problem if there're multiple attributes, do this instead:
5276 * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */
5277 mono_error_cleanup (&error
);
5278 MonoMethod
*getter
= mono_class_get_method_from_name (klass
, "get_Category", -1);
5279 MonoObject
*str
= mono_interp_runtime_invoke (getter
, obj
, NULL
, &exc
, &error
);
5280 mono_error_cleanup (&error
);
5281 char *utf8_str
= mono_string_to_utf8_checked ((MonoString
*) str
, &error
);
5282 mono_error_cleanup (&error
);
5283 if (!strcmp (utf8_str
, "!INTERPRETER")) {
5284 g_print ("skip %s...\n", method
->name
);
5290 if (strncmp (method
->name
, "test_", 5) == 0 && filter
) {
5291 MonoError interp_error
;
5292 MonoObject
*exc
= NULL
;
5294 result_obj
= mono_interp_runtime_invoke (method
, NULL
, NULL
, &exc
, &interp_error
);
5295 if (!mono_error_ok (&interp_error
)) {
5297 g_print ("Test '%s' execution failed.\n", method
->name
);
5298 } else if (exc
!= NULL
) {
5299 g_print ("Exception in Test '%s' occured:\n", method
->name
);
5300 mono_object_describe (exc
);
5304 result
= *(gint32
*) mono_object_unbox (result_obj
);
5305 expected
= atoi (method
->name
+ 5); // FIXME: oh no.
5308 if (result
!= expected
) {
5310 g_print ("Test '%s' failed result (got %d, expected %d).\n", method
->name
, result
, expected
);
5315 g_timer_stop (timer
);
5316 elapsed
= g_timer_elapsed (timer
, NULL
);
5317 if (failed
> 0 || cfailed
> 0){
5318 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
5319 run
, failed
, cfailed
, 100.0*(run
-failed
-cfailed
)/run
);
5321 g_print ("Results: total tests: %d, all pass \n", run
);
5324 g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed
,
5325 elapsed
- transform_time
, transform_time
);
5326 *total
+= failed
+ cfailed
;
5331 interp_regression (MonoImage
*image
, int verbose
, int *total_run
)
5334 GTimer
*timer
= g_timer_new ();
5335 MonoDomain
*domain
= mono_domain_get ();
5339 /* load the metadata */
5340 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
5342 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
5344 mono_error_cleanup (&error
);
5347 mono_class_init (method
->klass
);
5352 interp_regression_step (image
, verbose
, total_run
, &total
, timer
, domain
);
5354 g_timer_destroy (timer
);
5359 mono_interp_regression_list (int verbose
, int count
, char *images
[])
5361 int i
, total
, total_run
, run
;
5363 total_run
= total
= 0;
5364 for (i
= 0; i
< count
; ++i
) {
5365 MonoAssembly
*ass
= mono_assembly_open_predicate (images
[i
], FALSE
, FALSE
, NULL
, NULL
, NULL
);
5367 g_warning ("failed to load assembly: %s", images
[i
]);
5370 total
+= interp_regression (mono_assembly_get_image (ass
), verbose
, &run
);
5374 g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run
, total
, 100.0*(total_run
-total
)/total_run
);
5376 g_print ("Overall results: tests: %d, 100%% pass\n", total_run
);
5383 * mono_interp_set_resume_state:
5385 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5388 mono_interp_set_resume_state (MonoJitTlsData
*jit_tls
, MonoException
*ex
, MonoInterpFrameHandle interp_frame
, gpointer handler_ip
)
5390 ThreadContext
*context
;
5393 context
= jit_tls
->interp_context
;
5396 context
->has_resume_state
= TRUE
;
5397 context
->handler_frame
= interp_frame
;
5398 /* This is on the stack, so it doesn't need a wbarrier */
5399 context
->handler_frame
->ex
= ex
;
5400 context
->handler_ip
= handler_ip
;
5404 * mono_interp_run_finally:
5406 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5407 * frame->interp_frame.
5410 mono_interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
)
5412 InterpFrame
*iframe
= frame
->interp_frame
;
5413 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
5415 ves_exec_method_with_context (iframe
, context
, handler_ip
, NULL
, clause_index
);
5419 InterpFrame
*current
;
5423 * mono_interp_frame_iter_init:
5425 * Initialize an iterator for iterating through interpreted frames.
5428 mono_interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
5430 StackIter
*stack_iter
= (StackIter
*)iter
;
5432 stack_iter
->current
= (InterpFrame
*)interp_exit_data
;
5436 mono_interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
5438 StackIter
*stack_iter
= (StackIter
*)iter
;
5439 InterpFrame
*iframe
= stack_iter
->current
;
5441 memset (frame
, 0, sizeof (StackFrameInfo
));
5442 /* pinvoke frames doesn't have imethod set */
5443 while (iframe
&& !(iframe
->imethod
&& iframe
->imethod
->code
))
5444 iframe
= iframe
->parent
;
5448 frame
->type
= FRAME_TYPE_INTERP
;
5450 frame
->domain
= mono_domain_get ();
5451 frame
->interp_frame
= iframe
;
5452 frame
->method
= iframe
->imethod
->method
;
5453 frame
->actual_method
= frame
->method
;
5454 /* This is the offset in the interpreter IR */
5455 frame
->native_offset
= (guint8
*)iframe
->ip
- (guint8
*)iframe
->imethod
->code
;
5456 frame
->ji
= iframe
->imethod
->jinfo
;
5458 stack_iter
->current
= iframe
->parent
;
5464 mono_interp_find_jit_info (MonoDomain
*domain
, MonoMethod
*method
)
5468 rtm
= lookup_imethod (domain
, method
);
5476 mono_interp_set_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
5478 guint16
*code
= (guint16
*)ip
;
5479 g_assert (*code
== MINT_SDB_SEQ_POINT
);
5480 *code
= MINT_SDB_BREAKPOINT
;
5484 mono_interp_clear_breakpoint (MonoJitInfo
*jinfo
, gpointer ip
)
5486 guint16
*code
= (guint16
*)ip
;
5487 g_assert (*code
== MINT_SDB_BREAKPOINT
);
5488 *code
= MINT_SDB_SEQ_POINT
;
5492 mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame
)
5494 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5496 g_assert (iframe
->imethod
);
5497 return iframe
->imethod
->jinfo
;
5501 mono_interp_frame_get_ip (MonoInterpFrameHandle frame
)
5503 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5505 g_assert (iframe
->imethod
);
5506 return (gpointer
)iframe
->ip
;
5510 mono_interp_frame_get_arg (MonoInterpFrameHandle frame
, int pos
)
5512 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5514 g_assert (iframe
->imethod
);
5516 int arg_offset
= iframe
->imethod
->arg_offsets
[pos
+ (iframe
->imethod
->hasthis
? 1 : 0)];
5518 return iframe
->args
+ arg_offset
;
5522 mono_interp_frame_get_local (MonoInterpFrameHandle frame
, int pos
)
5524 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5526 g_assert (iframe
->imethod
);
5528 return iframe
->locals
+ iframe
->imethod
->local_offsets
[pos
];
5532 mono_interp_frame_get_this (MonoInterpFrameHandle frame
)
5534 InterpFrame
*iframe
= (InterpFrame
*)frame
;
5536 g_assert (iframe
->imethod
);
5537 g_assert (iframe
->imethod
->hasthis
);
5539 int arg_offset
= iframe
->imethod
->arg_offsets
[0];
5541 return iframe
->args
+ arg_offset
;
5545 mono_interp_start_single_stepping (void)
5551 mono_interp_stop_single_stepping (void)