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.
28 #include <mono/utils/gc_wrapper.h>
34 # define alloca __builtin_alloca
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/utils/atomic.h>
63 #include "interp-internals.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/jit-icalls.h>
71 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
74 #define finite _finite
78 #define finite isfinite
83 init_frame (MonoInvocation
*frame
, MonoInvocation
*parent_frame
, RuntimeMethod
*rmethod
, stackval
*method_args
, stackval
*method_retval
)
85 frame
->parent
= parent_frame
;
86 frame
->stack_args
= method_args
;
87 frame
->retval
= method_retval
;
88 frame
->runtime_method
= rmethod
;
91 frame
->invoke_trap
= 0;
94 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
95 RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
96 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
100 * List of classes whose methods will be executed by transitioning to JITted code.
105 void ves_exec_method (MonoInvocation
*frame
);
107 static char* dump_frame (MonoInvocation
*inv
);
108 static MonoArray
*get_trace_ips (MonoDomain
*domain
, MonoInvocation
*top
);
109 static void ves_exec_method_with_context (MonoInvocation
*frame
, ThreadContext
*context
, unsigned short *start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
);
111 typedef void (*ICallMethod
) (MonoInvocation
*frame
);
113 static guint32 die_on_exception
= 0;
114 static MonoNativeTlsKey thread_context_id
;
116 static char* dump_args (MonoInvocation
*inv
);
118 #define DEBUG_INTERP 0
121 int mono_interp_traceopt
= 2;
122 /* If true, then we output the opcodes as we interpret them */
123 static int global_tracing
= 2;
125 static int debug_indent_level
= 0;
127 static int break_on_method
= 0;
128 static int nested_trace
= 0;
129 static GList
*db_methods
= NULL
;
136 for (h
= 0; h
< debug_indent_level
; h
++)
141 db_match_method (gpointer data
, gpointer user_data
)
143 MonoMethod
*m
= (MonoMethod
*)user_data
;
144 MonoMethodDesc
*desc
= data
;
146 if (mono_method_desc_full_match (desc
, m
))
151 debug_enter (MonoInvocation
*frame
, int *tracing
)
154 g_list_foreach (db_methods
, db_match_method
, (gpointer
)frame
->runtime_method
->method
);
156 *tracing
= nested_trace
? (global_tracing
= 2, 3) : 2;
160 MonoMethod
*method
= frame
->runtime_method
->method
;
161 char *mn
, *args
= dump_args (frame
);
162 debug_indent_level
++;
164 mn
= mono_method_full_name (method
, FALSE
);
165 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn
);
167 g_print ("%s)\n", args
);
170 if (mono_profiler_events
& MONO_PROFILE_ENTER_LEAVE
)
171 mono_profiler_method_enter (frame
->runtime_method
->method
);
175 #define DEBUG_LEAVE() \
178 args = dump_retval (frame); \
180 mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
181 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
183 g_print (" => %s\n", args); \
185 debug_indent_level--; \
186 if (tracing == 3) global_tracing = 0; \
188 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
189 mono_profiler_method_leave (frame->runtime_method->method);
193 int mono_interp_traceopt
= 0;
194 static void debug_enter (MonoInvocation
*frame
, int *tracing
)
197 #define DEBUG_LEAVE()
201 /* Set the current execution state to the resume state in context */
202 #define SET_RESUME_STATE(context) do { \
203 ip = (context)->handler_ip; \
204 sp->data.p = frame->ex; \
207 (context)->has_resume_state = 0; \
208 (context)->handler_frame = NULL; \
213 ves_real_abort (int line
, MonoMethod
*mh
,
214 const unsigned short *ip
, stackval
*stack
, stackval
*sp
)
217 fprintf (stderr
, "Execution aborted in method: %s::%s\n", mh
->klass
->name
, mh
->name
);
218 fprintf (stderr
, "Line=%d IP=0x%04lx, Aborted execution\n", line
,
219 ip
-(const unsigned short *)mono_method_get_header_checked (mh
, &error
)->code
);
220 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
221 g_print ("0x%04x %02x\n",
222 ip
-(const unsigned short *)mono_method_get_header_checked (mh
, &error
)->code
, *ip
);
223 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
225 printf ("\t[%ld] 0x%08x %0.5f\n", sp
-stack
, sp
[-1].data
.i
, sp
[-1].data
.f
);
228 #define ves_abort() \
230 ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
231 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
235 mono_interp_get_runtime_method (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
238 MonoJitDomainInfo
*info
;
239 MonoMethodSignature
*sig
;
244 info
= domain_jit_info (domain
);
245 mono_domain_jit_code_hash_lock (domain
);
246 rtm
= mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
);
247 mono_domain_jit_code_hash_unlock (domain
);
251 sig
= mono_method_signature (method
);
253 rtm
= mono_domain_alloc0 (domain
, sizeof (RuntimeMethod
));
254 rtm
->method
= method
;
255 rtm
->param_count
= sig
->param_count
;
256 rtm
->hasthis
= sig
->hasthis
;
257 rtm
->rtype
= mini_get_underlying_type (sig
->ret
);
258 rtm
->param_types
= mono_domain_alloc0 (domain
, sizeof (MonoType
*) * sig
->param_count
);
259 for (i
= 0; i
< sig
->param_count
; ++i
)
260 rtm
->param_types
[i
] = mini_get_underlying_type (sig
->params
[i
]);
262 mono_domain_jit_code_hash_lock (domain
);
263 if (!mono_internal_hash_table_lookup (&info
->interp_code_hash
, method
))
264 mono_internal_hash_table_insert (&info
->interp_code_hash
, method
, rtm
);
265 mono_domain_jit_code_hash_unlock (domain
);
271 mono_interp_create_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
273 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
274 method
= mono_marshal_get_synchronized_wrapper (method
);
275 return mono_interp_get_runtime_method (domain
, method
, error
);
278 static inline RuntimeMethod
*
279 get_virtual_method (MonoDomain
*domain
, RuntimeMethod
*runtime_method
, MonoObject
*obj
)
281 MonoMethod
*m
= runtime_method
->method
;
284 if ((m
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(m
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
285 RuntimeMethod
*ret
= NULL
;
286 if (mono_object_is_transparent_proxy (obj
)) {
287 ret
= mono_interp_get_runtime_method (domain
, mono_marshal_get_remoting_invoke (m
), &error
);
288 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
289 } else if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
290 ret
= mono_interp_get_runtime_method (domain
, mono_marshal_get_synchronized_wrapper (m
), &error
);
291 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
293 ret
= runtime_method
;
298 mono_class_setup_vtable (obj
->vtable
->klass
);
300 int slot
= mono_method_get_vtable_slot (m
);
301 if (mono_class_is_interface (m
->klass
)) {
302 g_assert (obj
->vtable
->klass
!= m
->klass
);
303 /* TODO: interface offset lookup is slow, go through IMT instead */
304 gboolean non_exact_match
;
305 slot
+= mono_class_interface_offset_with_variance (obj
->vtable
->klass
, m
->klass
, &non_exact_match
);
308 MonoMethod
*virtual_method
= obj
->vtable
->klass
->vtable
[slot
];
309 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
310 MonoGenericContext context
= { NULL
, NULL
};
312 if (mono_class_is_ginst (virtual_method
->klass
))
313 context
.class_inst
= mono_class_get_generic_class (virtual_method
->klass
)->context
.class_inst
;
314 else if (mono_class_is_gtd (virtual_method
->klass
))
315 context
.class_inst
= mono_class_get_generic_container (virtual_method
->klass
)->context
.class_inst
;
316 context
.method_inst
= mono_method_get_context (m
)->method_inst
;
318 virtual_method
= mono_class_inflate_generic_method_checked (virtual_method
, &context
, &error
);
319 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
322 if (virtual_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
323 virtual_method
= mono_marshal_get_synchronized_wrapper (virtual_method
);
326 RuntimeMethod
*virtual_runtime_method
= mono_interp_get_runtime_method (domain
, virtual_method
, &error
);
327 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
328 return virtual_runtime_method
;
332 stackval_from_data (MonoType
*type
, stackval
*result
, char *data
, gboolean pinvoke
)
335 switch (type
->type
) {
336 case MONO_TYPE_OBJECT
:
337 case MONO_TYPE_CLASS
:
338 case MONO_TYPE_STRING
:
339 case MONO_TYPE_ARRAY
:
340 case MONO_TYPE_SZARRAY
:
345 result
->data
.p
= *(gpointer
*)data
;
348 switch (type
->type
) {
352 result
->data
.i
= *(gint8
*)data
;
355 case MONO_TYPE_BOOLEAN
:
356 result
->data
.i
= *(guint8
*)data
;
359 result
->data
.i
= *(gint16
*)data
;
363 result
->data
.i
= *(guint16
*)data
;
366 result
->data
.i
= *(gint32
*)data
;
370 result
->data
.nati
= *(mono_i
*)data
;
373 result
->data
.p
= *(gpointer
*)data
;
376 result
->data
.i
= *(guint32
*)data
;
379 result
->data
.f
= *(float*)data
;
383 result
->data
.l
= *(gint64
*)data
;
386 result
->data
.f
= *(double*)data
;
388 case MONO_TYPE_STRING
:
389 case MONO_TYPE_SZARRAY
:
390 case MONO_TYPE_CLASS
:
391 case MONO_TYPE_OBJECT
:
392 case MONO_TYPE_ARRAY
:
393 result
->data
.p
= *(gpointer
*)data
;
395 case MONO_TYPE_VALUETYPE
:
396 if (type
->data
.klass
->enumtype
) {
397 stackval_from_data (mono_class_enum_basetype (type
->data
.klass
), result
, data
, pinvoke
);
400 mono_value_copy (result
->data
.vt
, data
, type
->data
.klass
);
402 case MONO_TYPE_GENERICINST
:
403 stackval_from_data (&type
->data
.generic_class
->container_class
->byval_arg
, result
, data
, pinvoke
);
406 g_warning ("got type 0x%02x", type
->type
);
407 g_assert_not_reached ();
412 stackval_to_data (MonoType
*type
, stackval
*val
, char *data
, gboolean pinvoke
)
415 gpointer
*p
= (gpointer
*)data
;
419 /* printf ("TODAT0 %p\n", data); */
420 switch (type
->type
) {
423 guint8
*p
= (guint8
*)data
;
427 case MONO_TYPE_BOOLEAN
: {
428 guint8
*p
= (guint8
*)data
;
429 *p
= (val
->data
.i
!= 0);
434 case MONO_TYPE_CHAR
: {
435 guint16
*p
= (guint16
*)data
;
440 mono_i
*p
= (mono_i
*)data
;
441 /* In theory the value used by stloc should match the local var type
442 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
443 a native int - both by csc and mcs). Not sure what to do about sign extension
444 as it is outside the spec... doing the obvious */
445 *p
= (mono_i
)val
->data
.nati
;
449 mono_u
*p
= (mono_u
*)data
;
451 *p
= (mono_u
)val
->data
.nati
;
456 gint32
*p
= (gint32
*)data
;
462 gint64
*p
= (gint64
*)data
;
467 float *p
= (float*)data
;
472 double *p
= (double*)data
;
476 case MONO_TYPE_STRING
:
477 case MONO_TYPE_SZARRAY
:
478 case MONO_TYPE_CLASS
:
479 case MONO_TYPE_OBJECT
:
480 case MONO_TYPE_ARRAY
: {
481 gpointer
*p
= (gpointer
*) data
;
482 mono_gc_wbarrier_generic_store (p
, val
->data
.p
);
485 case MONO_TYPE_PTR
: {
486 gpointer
*p
= (gpointer
*) data
;
490 case MONO_TYPE_VALUETYPE
:
491 if (type
->data
.klass
->enumtype
) {
492 stackval_to_data (mono_class_enum_basetype (type
->data
.klass
), val
, data
, pinvoke
);
495 mono_value_copy (data
, val
->data
.vt
, type
->data
.klass
);
497 case MONO_TYPE_GENERICINST
: {
498 MonoClass
*container_class
= type
->data
.generic_class
->container_class
;
500 if (container_class
->valuetype
&& !container_class
->enumtype
) {
501 mono_value_copy (data
, val
->data
.vt
, mono_class_from_mono_type (type
));
504 stackval_to_data (&type
->data
.generic_class
->container_class
->byval_arg
, val
, data
, pinvoke
);
508 g_warning ("got type %x", type
->type
);
509 g_assert_not_reached ();
514 fill_in_trace (MonoException
*exception
, MonoInvocation
*frame
)
517 char *stack_trace
= dump_frame (frame
);
518 MonoDomain
*domain
= mono_domain_get();
519 (exception
)->stack_trace
= mono_string_new_checked (domain
, stack_trace
, &error
);
520 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
521 (exception
)->trace_ips
= get_trace_ips (domain
, frame
);
522 g_free (stack_trace
);
525 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
527 #define THROW_EX(exception,ex_ip) \
529 frame->ip = (ex_ip); \
530 frame->ex = (MonoException*)(exception); \
531 FILL_IN_TRACE(frame->ex, frame); \
532 goto handle_exception; \
536 ves_array_create (MonoInvocation
*frame
, MonoDomain
*domain
, MonoClass
*klass
, MonoMethodSignature
*sig
, stackval
*values
)
539 intptr_t *lower_bounds
;
544 lengths
= alloca (sizeof (uintptr_t) * klass
->rank
* 2);
545 for (i
= 0; i
< sig
->param_count
; ++i
) {
546 lengths
[i
] = values
->data
.i
;
549 if (klass
->rank
== sig
->param_count
) {
550 /* Only lengths provided. */
553 /* lower bounds are first. */
554 lower_bounds
= (intptr_t *) lengths
;
555 lengths
+= klass
->rank
;
557 obj
= (MonoObject
*) mono_array_new_full_checked (domain
, klass
, lengths
, lower_bounds
, &error
);
558 if (!mono_error_ok (&error
)) {
559 frame
->ex
= mono_error_convert_to_exception (&error
);
560 FILL_IN_TRACE (frame
->ex
, frame
);
562 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
567 ves_array_calculate_index (MonoArray
*ao
, stackval
*sp
, MonoInvocation
*frame
, gboolean safe
)
569 g_assert (!frame
->ex
);
570 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
574 for (gint32 i
= 0; i
< ac
->rank
; i
++) {
575 guint32 idx
= sp
[i
].data
.i
;
576 guint32 lower
= ao
->bounds
[i
].lower_bound
;
577 guint32 len
= ao
->bounds
[i
].length
;
578 if (safe
&& (idx
< lower
|| (idx
- lower
) >= len
)) {
579 frame
->ex
= mono_get_exception_index_out_of_range ();
580 FILL_IN_TRACE (frame
->ex
, frame
);
583 pos
= (pos
* len
) + idx
- lower
;
587 if (safe
&& pos
>= ao
->max_length
) {
588 frame
->ex
= mono_get_exception_index_out_of_range ();
589 FILL_IN_TRACE (frame
->ex
, frame
);
597 ves_array_set (MonoInvocation
*frame
)
599 stackval
*sp
= frame
->stack_args
+ 1;
601 MonoObject
*o
= frame
->stack_args
->data
.p
;
602 MonoArray
*ao
= (MonoArray
*) o
;
603 MonoClass
*ac
= o
->vtable
->klass
;
605 g_assert (ac
->rank
>= 1);
607 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
611 if (sp
[ac
->rank
].data
.p
&& !mono_object_class (o
)->element_class
->valuetype
) {
613 MonoObject
*isinst
= mono_object_isinst_checked (sp
[ac
->rank
].data
.p
, mono_object_class (o
)->element_class
, &error
);
614 mono_error_cleanup (&error
);
616 frame
->ex
= mono_get_exception_array_type_mismatch ();
617 FILL_IN_TRACE (frame
->ex
, frame
);
622 gint32 esize
= mono_array_element_size (ac
);
623 gpointer ea
= mono_array_addr_with_size (ao
, esize
, pos
);
625 MonoType
*mt
= mono_method_signature (frame
->runtime_method
->method
)->params
[ac
->rank
];
626 stackval_to_data (mt
, &sp
[ac
->rank
], ea
, FALSE
);
630 ves_array_get (MonoInvocation
*frame
, gboolean safe
)
632 stackval
*sp
= frame
->stack_args
+ 1;
634 MonoObject
*o
= frame
->stack_args
->data
.p
;
635 MonoArray
*ao
= (MonoArray
*) o
;
636 MonoClass
*ac
= o
->vtable
->klass
;
638 g_assert (ac
->rank
>= 1);
640 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, safe
);
644 gint32 esize
= mono_array_element_size (ac
);
645 gpointer ea
= mono_array_addr_with_size (ao
, esize
, pos
);
647 MonoType
*mt
= mono_method_signature (frame
->runtime_method
->method
)->ret
;
648 stackval_from_data (mt
, frame
->retval
, ea
, FALSE
);
652 ves_array_element_address (MonoInvocation
*frame
, MonoClass
*required_type
, MonoArray
*ao
, stackval
*sp
, gboolean needs_typecheck
)
654 MonoClass
*ac
= ((MonoObject
*) ao
)->vtable
->klass
;
656 g_assert (ac
->rank
>= 1);
658 gint32 pos
= ves_array_calculate_index (ao
, sp
, frame
, TRUE
);
662 if (needs_typecheck
&& !mono_class_is_assignable_from (mono_object_class ((MonoObject
*) ao
)->element_class
, required_type
->element_class
)) {
663 frame
->ex
= mono_get_exception_array_type_mismatch ();
664 FILL_IN_TRACE (frame
->ex
, frame
);
667 gint32 esize
= mono_array_element_size (ac
);
668 return mono_array_addr_with_size (ao
, esize
, pos
);
672 interp_walk_stack_with_ctx (MonoInternalStackWalk func
, MonoContext
*ctx
, MonoUnwindOptions options
, void *user_data
)
675 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
680 MonoInvocation
*frame
= context
->current_frame
;
683 MonoStackFrameInfo fi
;
684 memset (&fi
, 0, sizeof (MonoStackFrameInfo
));
686 /* TODO: hack to make some asserts happy. */
687 fi
.ji
= (MonoJitInfo
*) frame
->runtime_method
;
689 if (frame
->runtime_method
)
690 fi
.method
= fi
.actual_method
= frame
->runtime_method
->method
;
692 if (!fi
.method
|| (fi
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) || (fi
.method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
694 fi
.type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
696 MonoMethodHeader
*hd
= mono_method_get_header_checked (fi
.method
, &error
);
697 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
698 fi
.type
= FRAME_TYPE_MANAGED
;
699 fi
.il_offset
= frame
->ip
- (const unsigned short *) hd
->code
;
700 if (!fi
.method
->wrapper_type
)
704 if (func (&fi
, ctx
, user_data
))
706 frame
= frame
->parent
;
710 static MonoPIFunc mono_interp_enter_icall_trampoline
= NULL
;
712 static InterpMethodArguments
* build_args_from_sig (MonoMethodSignature
*sig
, MonoInvocation
*frame
)
714 InterpMethodArguments
*margs
= g_malloc0 (sizeof (InterpMethodArguments
));
719 for (int i
= 0; i
< sig
->param_count
; i
++) {
720 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
722 case MONO_TYPE_BOOLEAN
:
733 case MONO_TYPE_SZARRAY
:
734 case MONO_TYPE_CLASS
:
735 case MONO_TYPE_OBJECT
:
736 case MONO_TYPE_STRING
:
737 case MONO_TYPE_VALUETYPE
:
738 case MONO_TYPE_GENERICINST
:
739 #if SIZEOF_VOID_P == 8
744 #if SIZEOF_VOID_P == 4
750 #if SIZEOF_VOID_P == 8
755 #if SIZEOF_VOID_P == 4
761 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype
);
766 margs
->iargs
= g_malloc0 (sizeof (gpointer
) * margs
->ilen
);
769 margs
->fargs
= g_malloc0 (sizeof (double) * margs
->flen
);
771 if (margs
->ilen
> INTERP_ICALL_TRAMP_IARGS
)
772 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs
->ilen
);
774 if (margs
->flen
> INTERP_ICALL_TRAMP_FARGS
)
775 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs
->flen
);
782 margs
->iargs
[0] = frame
->stack_args
->data
.p
;
786 for (int i
= 0; i
< sig
->param_count
; i
++) {
787 guint32 ptype
= sig
->params
[i
]->byref
? MONO_TYPE_PTR
: sig
->params
[i
]->type
;
789 case MONO_TYPE_BOOLEAN
:
800 case MONO_TYPE_SZARRAY
:
801 case MONO_TYPE_CLASS
:
802 case MONO_TYPE_OBJECT
:
803 case MONO_TYPE_STRING
:
804 case MONO_TYPE_VALUETYPE
:
805 case MONO_TYPE_GENERICINST
:
806 #if SIZEOF_VOID_P == 8
809 margs
->iargs
[int_i
] = frame
->stack_args
[i
].data
.p
;
811 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i
, margs
->iargs
[int_i
], i
);
815 #if SIZEOF_VOID_P == 4
822 if (ptype
== MONO_TYPE_R4
)
823 * (float *) &(margs
->fargs
[int_f
]) = (float) frame
->stack_args
[i
].data
.f
;
825 margs
->fargs
[int_f
] = frame
->stack_args
[i
].data
.f
;
827 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
);
829 #if SIZEOF_VOID_P == 4
836 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype
);
840 switch (sig
->ret
->type
) {
841 case MONO_TYPE_BOOLEAN
:
852 case MONO_TYPE_SZARRAY
:
853 case MONO_TYPE_CLASS
:
854 case MONO_TYPE_OBJECT
:
855 case MONO_TYPE_STRING
:
857 case MONO_TYPE_VALUETYPE
:
858 case MONO_TYPE_GENERICINST
:
859 margs
->retval
= &(frame
->retval
->data
.p
);
860 margs
->is_float_ret
= 0;
864 margs
->retval
= &(frame
->retval
->data
.p
);
865 margs
->is_float_ret
= 1;
868 margs
->retval
= NULL
;
871 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig
->ret
->type
);
878 ves_pinvoke_method (MonoInvocation
*frame
, MonoMethodSignature
*sig
, MonoFuncV addr
, gboolean string_ctor
, ThreadContext
*context
)
881 MonoInvocation
*old_frame
= context
->current_frame
;
882 MonoInvocation
*old_env_frame
= context
->env_frame
;
883 jmp_buf *old_env
= context
->current_env
;
887 context
->current_frame
= old_frame
;
888 context
->env_frame
= old_env_frame
;
889 context
->current_env
= old_env
;
890 context
->managed_code
= 1;
895 context
->env_frame
= frame
;
896 context
->current_env
= &env
;
898 g_assert (!frame
->runtime_method
);
899 if (!mono_interp_enter_icall_trampoline
) {
901 mono_interp_enter_icall_trampoline
= mono_arch_get_enter_icall_trampoline (&info
);
903 // mono_tramp_info_register (info, NULL);
906 InterpMethodArguments
*margs
= build_args_from_sig (sig
, frame
);
908 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline
, addr
);
909 g_print ("margs(out): ilen=%d, flen=%d\n", margs
->ilen
, margs
->flen
);
912 context
->current_frame
= frame
;
913 context
->managed_code
= 0;
916 * Push an LMF frame on the LMF stack
917 * to mark the transition to native code.
919 memset (&ext
, 0, sizeof (ext
));
920 ext
.interp_exit
= TRUE
;
921 ext
.interp_exit_data
= frame
;
923 mono_push_lmf (&ext
);
925 mono_interp_enter_icall_trampoline (addr
, margs
);
927 mono_pop_lmf (&ext
.lmf
);
929 context
->managed_code
= 1;
930 /* domain can only be changed by native code */
931 context
->domain
= mono_domain_get ();
933 if (*mono_thread_interruption_request_flag ()) {
934 MonoException
*exc
= mono_thread_interruption_checkpoint ();
937 context
->search_for_handler
= 1;
941 if (!frame
->ex
&& !MONO_TYPE_ISSTRUCT (sig
->ret
))
942 stackval_from_data (sig
->ret
, frame
->retval
, (char*)&frame
->retval
->data
.p
, sig
->pinvoke
);
944 context
->current_frame
= old_frame
;
945 context
->env_frame
= old_env_frame
;
946 context
->current_env
= old_env
;
948 g_free (margs
->iargs
);
949 g_free (margs
->fargs
);
954 mono_interp_init_delegate (MonoDelegate
*del
)
958 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
959 del
->method
= ((RuntimeMethod
*) del
->method_ptr
)->method
;
964 * runtime specifies that the implementation of the method is automatically
965 * provided by the runtime and is primarily used for the methods of delegates.
968 ves_runtime_method (MonoInvocation
*frame
, ThreadContext
*context
)
970 MonoMethod
*method
= frame
->runtime_method
->method
;
971 const char *name
= method
->name
;
972 MonoObject
*obj
= (MonoObject
*) frame
->stack_args
->data
.p
;
973 MonoObject
*isinst_obj
;
976 mono_class_init (method
->klass
);
978 if (method
->klass
== mono_defaults
.array_class
) {
979 if (!strcmp (method
->name
, "UnsafeMov")) {
980 /* TODO: layout checks */
981 MonoType
*mt
= mono_method_signature (method
)->ret
;
982 stackval_from_data (mt
, frame
->retval
, (char *) frame
->stack_args
, FALSE
);
985 if (!strcmp (method
->name
, "UnsafeLoad")) {
986 ves_array_get (frame
, FALSE
);
991 isinst_obj
= mono_object_isinst_checked (obj
, mono_defaults
.array_class
, &error
);
992 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
993 if (obj
&& isinst_obj
) {
994 if (*name
== 'S' && (strcmp (name
, "Set") == 0)) {
995 ves_array_set (frame
);
998 if (*name
== 'G' && (strcmp (name
, "Get") == 0)) {
999 ves_array_get (frame
, TRUE
);
1004 g_error ("Don't know how to exec runtime method %s.%s::%s",
1005 method
->klass
->name_space
, method
->klass
->name
,
1011 dump_stack (stackval
*stack
, stackval
*sp
)
1013 stackval
*s
= stack
;
1014 GString
*str
= g_string_new ("");
1017 return g_string_free (str
, FALSE
);
1020 g_string_append_printf (str
, "[%p (%lld)] ", s
->data
.l
, s
->data
.l
);
1023 return g_string_free (str
, FALSE
);
1028 dump_stackval (GString
*str
, stackval
*s
, MonoType
*type
)
1030 switch (type
->type
) {
1037 case MONO_TYPE_CHAR
:
1038 case MONO_TYPE_BOOLEAN
:
1039 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1041 case MONO_TYPE_STRING
:
1042 case MONO_TYPE_SZARRAY
:
1043 case MONO_TYPE_CLASS
:
1044 case MONO_TYPE_OBJECT
:
1045 case MONO_TYPE_ARRAY
:
1049 g_string_append_printf (str
, "[%p] ", s
->data
.p
);
1051 case MONO_TYPE_VALUETYPE
:
1052 if (type
->data
.klass
->enumtype
)
1053 g_string_append_printf (str
, "[%d] ", s
->data
.i
);
1055 g_string_append_printf (str
, "[vt:%p] ", s
->data
.p
);
1059 g_string_append_printf (str
, "[%g] ", s
->data
.f
);
1064 GString
*res
= g_string_new ("");
1065 mono_type_get_desc (res
, type
, TRUE
);
1066 g_string_append_printf (str
, "[{%s} %lld/0x%0llx] ", res
->str
, s
->data
.l
, s
->data
.l
);
1067 g_string_free (res
, TRUE
);
1075 dump_retval (MonoInvocation
*inv
)
1077 GString
*str
= g_string_new ("");
1078 MonoType
*ret
= mono_method_signature (inv
->runtime_method
->method
)->ret
;
1080 if (ret
->type
!= MONO_TYPE_VOID
)
1081 dump_stackval (str
, inv
->retval
, ret
);
1083 return g_string_free (str
, FALSE
);
1088 dump_args (MonoInvocation
*inv
)
1090 GString
*str
= g_string_new ("");
1092 MonoMethodSignature
*signature
= mono_method_signature (inv
->runtime_method
->method
);
1094 if (signature
->param_count
== 0 && !signature
->hasthis
)
1095 return g_string_free (str
, FALSE
);
1097 if (signature
->hasthis
) {
1098 MonoMethod
*method
= inv
->runtime_method
->method
;
1099 dump_stackval (str
, inv
->stack_args
, &method
->klass
->byval_arg
);
1102 for (i
= 0; i
< signature
->param_count
; ++i
)
1103 dump_stackval (str
, inv
->stack_args
+ (!!signature
->hasthis
) + i
, signature
->params
[i
]);
1105 return g_string_free (str
, FALSE
);
1109 dump_frame (MonoInvocation
*inv
)
1111 GString
*str
= g_string_new ("");
1116 for (i
= 0; inv
; inv
= inv
->parent
) {
1117 if (inv
->runtime_method
!= NULL
) {
1118 MonoMethod
*method
= inv
->runtime_method
->method
;
1122 const char * opname
= "";
1124 gchar
*source
= NULL
;
1128 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1129 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) == 0) {
1130 MonoMethodHeader
*hd
= mono_method_get_header_checked (method
, &error
);
1131 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
1135 opname
= mono_interp_opname
[*inv
->ip
];
1136 codep
= inv
->ip
- inv
->runtime_method
->code
;
1137 source
= g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method
->name
, codep
);
1142 MonoDebugSourceLocation
*minfo
= mono_debug_lookup_method (method
);
1143 source
= mono_debug_method_lookup_location (minfo
, codep
);
1147 args
= dump_args (inv
);
1148 name
= mono_method_full_name (method
, TRUE
);
1150 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i
, codep
, opname
, name
, args
, source
);
1152 g_string_append_printf (str
, "#%d: 0x%05x %-10s in %s (%s)\n", i
, codep
, opname
, name
, args
);
1159 return g_string_free (str
, FALSE
);
1163 get_trace_ips (MonoDomain
*domain
, MonoInvocation
*top
)
1167 MonoInvocation
*inv
;
1170 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1171 if (inv
->runtime_method
!= NULL
)
1174 res
= mono_array_new_checked (domain
, mono_defaults
.int_class
, 2 * i
, &error
);
1175 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
1177 for (i
= 0, inv
= top
; inv
; inv
= inv
->parent
)
1178 if (inv
->runtime_method
!= NULL
) {
1179 mono_array_set (res
, gpointer
, i
, inv
->runtime_method
);
1181 mono_array_set (res
, gpointer
, i
, (gpointer
)inv
->ip
);
1189 #define MYGUINT64_MAX 18446744073709551615ULL
1190 #define MYGINT64_MAX 9223372036854775807LL
1191 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1193 #define MYGUINT32_MAX 4294967295U
1194 #define MYGINT32_MAX 2147483647
1195 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1197 #define CHECK_ADD_OVERFLOW(a,b) \
1198 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1199 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1201 #define CHECK_SUB_OVERFLOW(a,b) \
1202 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1203 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1205 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1206 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1208 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1209 (guint32)(a) < (guint32)(b) ? -1 : 0
1211 #define CHECK_ADD_OVERFLOW64(a,b) \
1212 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1213 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1215 #define CHECK_SUB_OVERFLOW64(a,b) \
1216 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1217 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1219 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1220 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1222 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1223 (guint64)(a) < (guint64)(b) ? -1 : 0
1225 #if SIZEOF_VOID_P == 4
1226 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1227 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1229 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1230 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1233 /* Resolves to TRUE if the operands would overflow */
1234 #define CHECK_MUL_OVERFLOW(a,b) \
1235 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1236 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1237 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1238 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1239 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1240 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1241 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1243 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1244 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1245 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1247 #define CHECK_MUL_OVERFLOW64(a,b) \
1248 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1249 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1250 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1251 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1252 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1253 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1254 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1256 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1257 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1258 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1260 #if SIZEOF_VOID_P == 4
1261 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1262 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1264 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1265 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1269 mono_interp_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
1271 MonoInvocation frame
;
1272 ThreadContext
* volatile context
= mono_native_tls_get_value (thread_context_id
);
1273 MonoObject
*retval
= NULL
;
1274 MonoMethodSignature
*sig
= mono_method_signature (method
);
1275 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
1276 int i
, type
, isobject
= 0;
1279 stackval
*args
= alloca (sizeof (stackval
) * (sig
->param_count
+ !!sig
->hasthis
));
1280 ThreadContext context_struct
;
1281 MonoInvocation
*old_frame
= NULL
;
1291 if (context
!= &context_struct
) {
1292 context
->domain
= mono_domain_get ();
1293 context
->current_frame
= old_frame
;
1294 context
->managed_code
= 0;
1296 mono_native_tls_set_value (thread_context_id
, NULL
);
1298 *exc
= (MonoObject
*)frame
.ex
;
1302 if (context
== NULL
) {
1303 context
= &context_struct
;
1304 memset (context
, 0, sizeof (ThreadContext
));
1305 context_struct
.base_frame
= &frame
;
1306 context_struct
.env_frame
= &frame
;
1307 context_struct
.current_env
= &env
;
1308 mono_native_tls_set_value (thread_context_id
, context
);
1311 old_frame
= context
->current_frame
;
1313 context
->domain
= mono_domain_get ();
1315 switch (sig
->ret
->type
) {
1316 case MONO_TYPE_VOID
:
1318 case MONO_TYPE_STRING
:
1319 case MONO_TYPE_OBJECT
:
1320 case MONO_TYPE_CLASS
:
1321 case MONO_TYPE_ARRAY
:
1322 case MONO_TYPE_SZARRAY
:
1325 case MONO_TYPE_VALUETYPE
:
1326 retval
= mono_object_new_checked (context
->domain
, klass
, error
);
1327 ret
= mono_object_unbox (retval
);
1328 if (!sig
->ret
->data
.klass
->enumtype
)
1329 result
.data
.vt
= ret
;
1331 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1333 case MONO_TYPE_GENERICINST
:
1334 if (!MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
1335 retval
= mono_object_new_checked (context
->domain
, klass
, error
);
1336 ret
= mono_object_unbox (retval
);
1337 if (!sig
->ret
->data
.klass
->enumtype
)
1338 result
.data
.vt
= ret
;
1340 result
.data
.vt
= alloca (mono_class_instance_size (klass
));
1347 retval
= mono_object_new_checked (context
->domain
, mono_defaults
.int_class
, error
);
1348 ret
= mono_object_unbox (retval
);
1351 retval
= mono_object_new_checked (context
->domain
, klass
, error
);
1352 ret
= mono_object_unbox (retval
);
1357 args
[0].data
.p
= obj
;
1359 for (i
= 0; i
< sig
->param_count
; ++i
) {
1360 int a_index
= i
+ !!sig
->hasthis
;
1361 if (sig
->params
[i
]->byref
) {
1362 args
[a_index
].data
.p
= params
[i
];
1365 type
= sig
->params
[i
]->type
;
1370 case MONO_TYPE_BOOLEAN
:
1371 args
[a_index
].data
.i
= *(MonoBoolean
*)params
[i
];
1375 case MONO_TYPE_CHAR
:
1376 args
[a_index
].data
.i
= *(gint16
*)params
[i
];
1378 #if SIZEOF_VOID_P == 4
1379 case MONO_TYPE_U
: /* use VAL_POINTER? */
1384 args
[a_index
].data
.i
= *(gint32
*)params
[i
];
1386 #if SIZEOF_VOID_P == 8
1392 args
[a_index
].data
.l
= *(gint64
*)params
[i
];
1395 args
[a_index
].data
.f
= *(gfloat
*) params
[i
];
1398 args
[a_index
].data
.f
= *(gdouble
*) params
[i
];
1400 case MONO_TYPE_VALUETYPE
:
1401 if (sig
->params
[i
]->data
.klass
->enumtype
) {
1402 type
= mono_class_enum_basetype (sig
->params
[i
]->data
.klass
)->type
;
1405 args
[a_index
].data
.p
= params
[i
];
1408 case MONO_TYPE_STRING
:
1410 case MONO_TYPE_CLASS
:
1411 case MONO_TYPE_ARRAY
:
1412 case MONO_TYPE_SZARRAY
:
1413 case MONO_TYPE_OBJECT
:
1414 case MONO_TYPE_GENERICINST
:
1415 args
[a_index
].data
.p
= params
[i
];
1418 g_error ("type 0x%x not handled in runtime invoke", sig
->params
[i
]->type
);
1422 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1423 method
= mono_marshal_get_native_wrapper (method
, FALSE
, FALSE
);
1424 INIT_FRAME (&frame
,context
->current_frame
,args
,&result
,mono_get_root_domain (),method
,error
);
1426 frame
.invoke_trap
= 1;
1427 context
->managed_code
= 1;
1428 ves_exec_method_with_context (&frame
, context
, NULL
, NULL
, -1);
1429 context
->managed_code
= 0;
1430 if (context
== &context_struct
)
1431 mono_native_tls_set_value (thread_context_id
, NULL
);
1433 context
->current_frame
= old_frame
;
1434 if (frame
.ex
!= NULL
) {
1436 *exc
= (MonoObject
*) frame
.ex
;
1439 if (context
->current_env
!= NULL
) {
1440 context
->env_frame
->ex
= frame
.ex
;
1441 longjmp(*context
->current_env
, 1);
1444 printf("dropped exception...\n");
1446 if (sig
->ret
->type
== MONO_TYPE_VOID
&& !method
->string_ctor
)
1448 if (isobject
|| method
->string_ctor
)
1449 return result
.data
.p
;
1450 stackval_to_data (sig
->ret
, &result
, ret
, sig
->pinvoke
);
1455 RuntimeMethod
*rmethod
;
1459 gpointer
*many_args
;
1462 /* Main function for entering the interpreter from compiled code */
1464 interp_entry (InterpEntryData
*data
)
1466 MonoInvocation frame
;
1467 RuntimeMethod
*rmethod
= data
->rmethod
;
1468 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
1469 ThreadContext context_struct
;
1470 MonoInvocation
*old_frame
;
1474 MonoMethodSignature
*sig
;
1478 method
= rmethod
->method
;
1479 sig
= mono_method_signature (method
);
1481 // FIXME: Optimize this
1483 //printf ("%s\n", mono_method_full_name (method, 1));
1486 if (context
== NULL
) {
1487 context
= &context_struct
;
1488 memset (context
, 0, sizeof (ThreadContext
));
1489 context_struct
.base_frame
= &frame
;
1490 context_struct
.env_frame
= &frame
;
1491 mono_native_tls_set_value (thread_context_id
, context
);
1494 old_frame
= context
->current_frame
;
1495 context
->domain
= mono_domain_get ();
1497 args
= alloca (sizeof (stackval
) * (sig
->param_count
+ (sig
->hasthis
? 1 : 0)));
1499 args
[0].data
.p
= data
->this_arg
;
1502 if (data
->many_args
)
1503 params
= data
->many_args
;
1505 params
= data
->args
;
1506 for (i
= 0; i
< sig
->param_count
; ++i
) {
1507 int a_index
= i
+ (sig
->hasthis
? 1 : 0);
1508 if (sig
->params
[i
]->byref
) {
1509 args
[a_index
].data
.p
= params
[i
];
1512 type
= rmethod
->param_types
[i
];
1513 switch (type
->type
) {
1516 args
[a_index
].data
.i
= *(MonoBoolean
*)params
[i
];
1520 args
[a_index
].data
.i
= *(gint16
*)params
[i
];
1523 #if SIZEOF_VOID_P == 4
1524 args
[a_index
].data
.p
= GINT_TO_POINTER (*(guint32
*)params
[i
]);
1526 args
[a_index
].data
.p
= GINT_TO_POINTER (*(guint64
*)params
[i
]);
1530 #if SIZEOF_VOID_P == 4
1531 args
[a_index
].data
.p
= GINT_TO_POINTER (*(gint32
*)params
[i
]);
1533 args
[a_index
].data
.p
= GINT_TO_POINTER (*(gint64
*)params
[i
]);
1537 args
[a_index
].data
.i
= *(guint32
*)params
[i
];
1540 args
[a_index
].data
.i
= *(gint32
*)params
[i
];
1543 args
[a_index
].data
.l
= *(guint64
*)params
[i
];
1546 args
[a_index
].data
.l
= *(gint64
*)params
[i
];
1549 case MONO_TYPE_OBJECT
:
1550 args
[a_index
].data
.p
= *(MonoObject
**)params
[i
];
1552 case MONO_TYPE_VALUETYPE
:
1553 args
[a_index
].data
.p
= params
[i
];
1555 case MONO_TYPE_GENERICINST
:
1556 if (MONO_TYPE_IS_REFERENCE (type
))
1557 args
[a_index
].data
.p
= params
[i
];
1559 args
[a_index
].data
.vt
= params
[i
];
1562 printf ("%s\n", mono_type_full_name (sig
->params
[i
]));
1568 init_frame (&frame
, NULL
, data
->rmethod
, args
, &result
);
1569 context
->managed_code
= 1;
1571 type
= rmethod
->rtype
;
1572 switch (type
->type
) {
1573 case MONO_TYPE_GENERICINST
:
1574 if (!MONO_TYPE_IS_REFERENCE (type
))
1575 frame
.retval
->data
.vt
= data
->res
;
1577 case MONO_TYPE_VALUETYPE
:
1578 frame
.retval
->data
.vt
= data
->res
;
1584 ves_exec_method_with_context (&frame
, context
, NULL
, NULL
, -1);
1585 context
->managed_code
= 0;
1586 if (context
== &context_struct
)
1587 mono_native_tls_set_value (thread_context_id
, NULL
);
1589 context
->current_frame
= old_frame
;
1592 g_assert (frame
.ex
== NULL
);
1594 type
= rmethod
->rtype
;
1595 switch (type
->type
) {
1596 case MONO_TYPE_VOID
:
1599 *(gint8
*)data
->res
= frame
.retval
->data
.i
;
1602 *(guint8
*)data
->res
= frame
.retval
->data
.i
;
1605 *(gint16
*)data
->res
= frame
.retval
->data
.i
;
1608 *(guint16
*)data
->res
= frame
.retval
->data
.i
;
1611 *(gint32
*)data
->res
= frame
.retval
->data
.i
;
1614 *(guint64
*)data
->res
= frame
.retval
->data
.i
;
1617 *(gint64
*)data
->res
= frame
.retval
->data
.i
;
1620 *(guint64
*)data
->res
= frame
.retval
->data
.i
;
1623 #if SIZEOF_VOID_P == 8
1624 *(gint64
*)data
->res
= (gint64
)frame
.retval
->data
.p
;
1626 *(gint32
*)data
->res
= (gint32
)frame
.retval
->data
.p
;
1630 #if SIZEOF_VOID_P == 8
1631 *(guint64
*)data
->res
= (guint64
)frame
.retval
->data
.p
;
1633 *(guint32
*)data
->res
= (guint32
)frame
.retval
->data
.p
;
1636 case MONO_TYPE_OBJECT
:
1637 /* No need for a write barrier */
1638 *(MonoObject
**)data
->res
= (MonoObject
*)frame
.retval
->data
.p
;
1640 case MONO_TYPE_GENERICINST
:
1641 if (MONO_TYPE_IS_REFERENCE (type
)) {
1642 *(MonoObject
**)data
->res
= *(MonoObject
**)frame
.retval
->data
.p
;
1644 /* Already set before the call */
1647 case MONO_TYPE_VALUETYPE
:
1648 /* Already set before the call */
1651 printf ("%s\n", mono_type_full_name (sig
->ret
));
1658 do_icall (ThreadContext
*context
, int op
, stackval
*sp
, gpointer ptr
)
1660 MonoInvocation
*old_frame
= context
->current_frame
;
1661 MonoInvocation
*old_env_frame
= context
->env_frame
;
1662 jmp_buf *old_env
= context
->current_env
;
1666 context
->current_frame
= old_frame
;
1667 context
->env_frame
= old_env_frame
;
1668 context
->current_env
= old_env
;
1669 context
->managed_code
= 1;
1673 context
->env_frame
= context
->current_frame
;
1674 context
->current_env
= &env
;
1675 context
->managed_code
= 0;
1678 case MINT_ICALL_V_V
: {
1679 void (*func
)(void) = ptr
;
1683 case MINT_ICALL_V_P
: {
1684 gpointer (*func
)(void) = ptr
;
1686 sp
[-1].data
.p
= func ();
1689 case MINT_ICALL_P_V
: {
1690 void (*func
)(gpointer
) = ptr
;
1691 func (sp
[-1].data
.p
);
1695 case MINT_ICALL_P_P
: {
1696 gpointer (*func
)(gpointer
) = ptr
;
1697 sp
[-1].data
.p
= func (sp
[-1].data
.p
);
1700 case MINT_ICALL_PP_V
: {
1701 void (*func
)(gpointer
,gpointer
) = ptr
;
1703 func (sp
[0].data
.p
, sp
[1].data
.p
);
1706 case MINT_ICALL_PI_V
: {
1707 void (*func
)(gpointer
,int) = ptr
;
1709 func (sp
[0].data
.p
, sp
[1].data
.i
);
1712 case MINT_ICALL_PP_P
: {
1713 gpointer (*func
)(gpointer
,gpointer
) = ptr
;
1715 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.p
);
1718 case MINT_ICALL_PI_P
: {
1719 gpointer (*func
)(gpointer
,int) = ptr
;
1721 sp
[-1].data
.p
= func (sp
[-1].data
.p
, sp
[0].data
.i
);
1724 case MINT_ICALL_PPP_V
: {
1725 void (*func
)(gpointer
,gpointer
,gpointer
) = ptr
;
1727 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.p
);
1730 case MINT_ICALL_PPI_V
: {
1731 void (*func
)(gpointer
,gpointer
,int) = ptr
;
1733 func (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
1737 g_assert_not_reached ();
1740 context
->env_frame
= old_env_frame
;
1741 context
->current_env
= old_env
;
1747 * These functions are the entry points into the interpreter from compiled code.
1748 * They are called by the interp_in wrappers. They have the following signature:
1749 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1750 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1751 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1752 * more wrappers then these functions.
1753 * this/static * ret/void * 16 arguments -> 64 functions.
1756 #define MAX_INTERP_ENTRY_ARGS 8
1758 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1759 InterpEntryData data; \
1760 (data).rmethod = (_method); \
1761 (data).res = (_res); \
1762 (data).this_arg = (_this_arg); \
1763 (data).many_args = NULL;
1765 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
1766 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1767 interp_entry (&data); \
1769 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
1770 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1771 (data).args [0] = arg1; \
1772 interp_entry (&data); \
1774 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
1775 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1776 (data).args [0] = arg1; \
1777 (data).args [1] = arg2; \
1778 interp_entry (&data); \
1780 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
1781 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1782 (data).args [0] = arg1; \
1783 (data).args [1] = arg2; \
1784 (data).args [2] = arg3; \
1785 interp_entry (&data); \
1787 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
1788 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1789 (data).args [0] = arg1; \
1790 (data).args [1] = arg2; \
1791 (data).args [2] = arg3; \
1792 (data).args [3] = arg4; \
1793 interp_entry (&data); \
1795 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
1796 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1797 (data).args [0] = arg1; \
1798 (data).args [1] = arg2; \
1799 (data).args [2] = arg3; \
1800 (data).args [3] = arg4; \
1801 (data).args [4] = arg5; \
1802 interp_entry (&data); \
1804 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
1805 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1806 (data).args [0] = arg1; \
1807 (data).args [1] = arg2; \
1808 (data).args [2] = arg3; \
1809 (data).args [3] = arg4; \
1810 (data).args [4] = arg5; \
1811 (data).args [5] = arg6; \
1812 interp_entry (&data); \
1814 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
1815 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1816 (data).args [0] = arg1; \
1817 (data).args [1] = arg2; \
1818 (data).args [2] = arg3; \
1819 (data).args [3] = arg4; \
1820 (data).args [4] = arg5; \
1821 (data).args [5] = arg6; \
1822 (data).args [6] = arg7; \
1823 interp_entry (&data); \
1825 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
1826 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1827 (data).args [0] = arg1; \
1828 (data).args [1] = arg2; \
1829 (data).args [2] = arg3; \
1830 (data).args [3] = arg4; \
1831 (data).args [4] = arg5; \
1832 (data).args [5] = arg6; \
1833 (data).args [6] = arg7; \
1834 (data).args [7] = arg8; \
1835 interp_entry (&data); \
1838 #define ARGLIST0 RuntimeMethod *rmethod
1839 #define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
1840 #define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
1841 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
1842 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
1843 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
1844 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
1845 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
1846 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *rmethod
1848 static void interp_entry_static_0 (ARGLIST0
) INTERP_ENTRY0 (NULL
, NULL
, rmethod
)
1849 static void interp_entry_static_1 (ARGLIST1
) INTERP_ENTRY1 (NULL
, NULL
, rmethod
)
1850 static void interp_entry_static_2 (ARGLIST2
) INTERP_ENTRY2 (NULL
, NULL
, rmethod
)
1851 static void interp_entry_static_3 (ARGLIST3
) INTERP_ENTRY3 (NULL
, NULL
, rmethod
)
1852 static void interp_entry_static_4 (ARGLIST4
) INTERP_ENTRY4 (NULL
, NULL
, rmethod
)
1853 static void interp_entry_static_5 (ARGLIST5
) INTERP_ENTRY5 (NULL
, NULL
, rmethod
)
1854 static void interp_entry_static_6 (ARGLIST6
) INTERP_ENTRY6 (NULL
, NULL
, rmethod
)
1855 static void interp_entry_static_7 (ARGLIST7
) INTERP_ENTRY7 (NULL
, NULL
, rmethod
)
1856 static void interp_entry_static_8 (ARGLIST8
) INTERP_ENTRY8 (NULL
, NULL
, rmethod
)
1857 static void interp_entry_static_ret_0 (gpointer res
, ARGLIST0
) INTERP_ENTRY0 (NULL
, res
, rmethod
)
1858 static void interp_entry_static_ret_1 (gpointer res
, ARGLIST1
) INTERP_ENTRY1 (NULL
, res
, rmethod
)
1859 static void interp_entry_static_ret_2 (gpointer res
, ARGLIST2
) INTERP_ENTRY2 (NULL
, res
, rmethod
)
1860 static void interp_entry_static_ret_3 (gpointer res
, ARGLIST3
) INTERP_ENTRY3 (NULL
, res
, rmethod
)
1861 static void interp_entry_static_ret_4 (gpointer res
, ARGLIST4
) INTERP_ENTRY4 (NULL
, res
, rmethod
)
1862 static void interp_entry_static_ret_5 (gpointer res
, ARGLIST5
) INTERP_ENTRY5 (NULL
, res
, rmethod
)
1863 static void interp_entry_static_ret_6 (gpointer res
, ARGLIST6
) INTERP_ENTRY6 (NULL
, res
, rmethod
)
1864 static void interp_entry_static_ret_7 (gpointer res
, ARGLIST7
) INTERP_ENTRY7 (NULL
, res
, rmethod
)
1865 static void interp_entry_static_ret_8 (gpointer res
, ARGLIST8
) INTERP_ENTRY8 (NULL
, res
, rmethod
)
1866 static void interp_entry_instance_0 (gpointer this_arg
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, NULL
, rmethod
)
1867 static void interp_entry_instance_1 (gpointer this_arg
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, NULL
, rmethod
)
1868 static void interp_entry_instance_2 (gpointer this_arg
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, NULL
, rmethod
)
1869 static void interp_entry_instance_3 (gpointer this_arg
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, NULL
, rmethod
)
1870 static void interp_entry_instance_4 (gpointer this_arg
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, NULL
, rmethod
)
1871 static void interp_entry_instance_5 (gpointer this_arg
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, NULL
, rmethod
)
1872 static void interp_entry_instance_6 (gpointer this_arg
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, NULL
, rmethod
)
1873 static void interp_entry_instance_7 (gpointer this_arg
, ARGLIST7
) INTERP_ENTRY7 (this_arg
, NULL
, rmethod
)
1874 static void interp_entry_instance_8 (gpointer this_arg
, ARGLIST8
) INTERP_ENTRY8 (this_arg
, NULL
, rmethod
)
1875 static void interp_entry_instance_ret_0 (gpointer this_arg
, gpointer res
, ARGLIST0
) INTERP_ENTRY0 (this_arg
, res
, rmethod
)
1876 static void interp_entry_instance_ret_1 (gpointer this_arg
, gpointer res
, ARGLIST1
) INTERP_ENTRY1 (this_arg
, res
, rmethod
)
1877 static void interp_entry_instance_ret_2 (gpointer this_arg
, gpointer res
, ARGLIST2
) INTERP_ENTRY2 (this_arg
, res
, rmethod
)
1878 static void interp_entry_instance_ret_3 (gpointer this_arg
, gpointer res
, ARGLIST3
) INTERP_ENTRY3 (this_arg
, res
, rmethod
)
1879 static void interp_entry_instance_ret_4 (gpointer this_arg
, gpointer res
, ARGLIST4
) INTERP_ENTRY4 (this_arg
, res
, rmethod
)
1880 static void interp_entry_instance_ret_5 (gpointer this_arg
, gpointer res
, ARGLIST5
) INTERP_ENTRY5 (this_arg
, res
, rmethod
)
1881 static void interp_entry_instance_ret_6 (gpointer this_arg
, gpointer res
, ARGLIST6
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
1882 static void interp_entry_instance_ret_7 (gpointer this_arg
, gpointer res
, ARGLIST7
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
1883 static void interp_entry_instance_ret_8 (gpointer this_arg
, gpointer res
, ARGLIST8
) INTERP_ENTRY6 (this_arg
, res
, rmethod
)
1885 #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
1887 gpointer entry_funcs_static
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static) };
1888 gpointer entry_funcs_static_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (static_ret
) };
1889 gpointer entry_funcs_instance
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance
) };
1890 gpointer entry_funcs_instance_ret
[MAX_INTERP_ENTRY_ARGS
+ 1] = { INTERP_ENTRY_FUNCLIST (instance_ret
) };
1892 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
1894 interp_entry_general (gpointer this_arg
, gpointer res
, gpointer
*args
, gpointer rmethod
)
1896 INTERP_ENTRY_BASE (rmethod
, this_arg
, res
);
1897 data
.many_args
= args
;
1898 interp_entry (&data
);
1902 * mono_interp_create_method_pointer:
1904 * Return a function pointer which can be used to call METHOD using the
1905 * interpreter. Return NULL for methods which are not supported.
1908 mono_interp_create_method_pointer (MonoMethod
*method
, MonoError
*error
)
1911 MonoMethodSignature
*sig
= mono_method_signature (method
);
1912 MonoMethod
*wrapper
;
1913 RuntimeMethod
*rmethod
;
1915 /* HACK: method_ptr of delegate should point to a runtime method*/
1916 if (method
->wrapper_type
&& method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1917 return mono_interp_get_runtime_method (mono_domain_get (), method
, error
);
1919 rmethod
= mono_interp_get_runtime_method (mono_domain_get (), method
, error
);
1920 if (rmethod
->jit_entry
)
1921 return rmethod
->jit_entry
;
1922 wrapper
= mini_get_interp_in_wrapper (sig
);
1924 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, error
);
1925 mono_error_assert_ok (error
);
1927 //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1928 gpointer entry_func
;
1929 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
) {
1930 entry_func
= interp_entry_general
;
1931 } else if (sig
->hasthis
) {
1932 if (sig
->ret
->type
== MONO_TYPE_VOID
)
1933 entry_func
= entry_funcs_instance
[sig
->param_count
];
1935 entry_func
= entry_funcs_instance_ret
[sig
->param_count
];
1937 if (sig
->ret
->type
== MONO_TYPE_VOID
)
1938 entry_func
= entry_funcs_static
[sig
->param_count
];
1940 entry_func
= entry_funcs_static_ret
[sig
->param_count
];
1942 g_assert (entry_func
);
1944 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
1945 MonoFtnDesc
*ftndesc
= g_new0 (MonoFtnDesc
, 1);
1946 ftndesc
->addr
= entry_func
;
1947 ftndesc
->arg
= rmethod
;
1948 mono_error_assert_ok (error
);
1951 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
1952 * rgctx register using a trampoline.
1956 g_assert (!mono_aot_only
);
1957 addr
= mono_arch_get_static_rgctx_trampoline (ftndesc
, jit_wrapper
);
1959 mono_memory_barrier ();
1960 rmethod
->jit_entry
= addr
;
1966 static int opcode_counts
[512];
1968 #define COUNT_OP(op) opcode_counts[op]++
1970 #define COUNT_OP(op)
1974 #define DUMP_INSTR() \
1975 if (tracing > 1) { \
1977 if (sp > frame->stack) { \
1978 ins = dump_stack (frame->stack, sp); \
1980 ins = g_strdup (""); \
1984 char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
1985 g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
1987 mono_interp_dis_mintop(rtm->code, ip); \
1988 g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
1992 #define DUMP_INSTR()
1996 #define USE_COMPUTED_GOTO 1
1998 #if USE_COMPUTED_GOTO
1999 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2000 #define MINT_IN_CASE(x) LAB_ ## x:
2002 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2004 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2006 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2008 #define MINT_IN_SWITCH(op) switch (op)
2009 #define MINT_IN_CASE(x) case x:
2010 #define MINT_IN_BREAK break
2011 #define MINT_IN_DEFAULT default:
2015 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2018 ves_exec_method_with_context (MonoInvocation
*frame
, ThreadContext
*context
, unsigned short *start_with_ip
, MonoException
*filter_exception
, int exit_at_finally
)
2020 MonoInvocation child_frame
;
2021 GSList
*finally_ips
= NULL
;
2022 const unsigned short *endfinally_ip
= NULL
;
2023 const unsigned short *ip
= NULL
;
2024 register stackval
*sp
;
2027 gint tracing
= global_tracing
;
2028 unsigned char *vtalloc
;
2033 unsigned char *vt_sp
;
2034 unsigned char *locals
;
2036 MonoObject
*o
= NULL
;
2038 #if USE_COMPUTED_GOTO
2039 static void *in_labels
[] = {
2040 #define OPDEF(a,b,c,d) \
2042 #include "mintops.def"
2047 frame
->ex_handler
= NULL
;
2049 context
->current_frame
= frame
;
2051 debug_enter (frame
, &tracing
);
2053 if (!frame
->runtime_method
->transformed
) {
2054 context
->managed_code
= 0;
2056 char *mn
= mono_method_full_name (frame
->runtime_method
->method
, TRUE
);
2057 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn
);
2060 frame
->ex
= mono_interp_transform_method (frame
->runtime_method
, context
);
2061 context
->managed_code
= 1;
2069 rtm
= frame
->runtime_method
;
2070 if (!start_with_ip
) {
2071 frame
->args
= alloca (rtm
->alloca_size
);
2072 memset (frame
->args
, 0, rtm
->alloca_size
);
2078 sp
= frame
->stack
= (stackval
*) ((char *) frame
->args
+ rtm
->args_size
);
2079 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2083 locals
= (unsigned char *) vt_sp
+ rtm
->vt_stack_size
;
2084 child_frame
.parent
= frame
;
2086 if (filter_exception
) {
2087 sp
->data
.p
= filter_exception
;
2092 * using while (ip < end) may result in a 15% performance drop,
2093 * but it may be useful for debug
2097 /* g_assert (sp >= frame->stack); */
2098 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2100 MINT_IN_SWITCH (*ip
) {
2101 MINT_IN_CASE(MINT_INITLOCALS
)
2102 memset (locals
, 0, rtm
->locals_size
);
2105 MINT_IN_CASE(MINT_NOP
)
2108 MINT_IN_CASE(MINT_BREAK
)
2110 G_BREAKPOINT (); /* this is not portable... */
2112 MINT_IN_CASE(MINT_LDNULL
)
2117 MINT_IN_CASE(MINT_VTRESULT
) {
2118 int ret_size
= * (guint16
*)(ip
+ 1);
2119 unsigned char *ret_vt_sp
= vt_sp
;
2120 vt_sp
-= READ32(ip
+ 2);
2122 memmove (vt_sp
, ret_vt_sp
, ret_size
);
2123 sp
[-1].data
.p
= vt_sp
;
2124 vt_sp
+= (ret_size
+ 7) & ~7;
2129 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2130 MINT_IN_CASE(MINT_LDC_I4_M1
)
2133 MINT_IN_CASE(MINT_LDC_I4_0
)
2136 MINT_IN_CASE(MINT_LDC_I4_1
)
2139 MINT_IN_CASE(MINT_LDC_I4_2
)
2142 MINT_IN_CASE(MINT_LDC_I4_3
)
2145 MINT_IN_CASE(MINT_LDC_I4_4
)
2148 MINT_IN_CASE(MINT_LDC_I4_5
)
2151 MINT_IN_CASE(MINT_LDC_I4_6
)
2154 MINT_IN_CASE(MINT_LDC_I4_7
)
2157 MINT_IN_CASE(MINT_LDC_I4_8
)
2160 MINT_IN_CASE(MINT_LDC_I4_S
)
2161 sp
->data
.i
= *(const short *)(ip
+ 1);
2165 MINT_IN_CASE(MINT_LDC_I4
)
2167 sp
->data
.i
= READ32 (ip
);
2171 MINT_IN_CASE(MINT_LDC_I8
)
2173 sp
->data
.l
= READ64 (ip
);
2177 MINT_IN_CASE(MINT_LDC_R4
) {
2181 sp
->data
.f
= * (float *)&val
;
2186 MINT_IN_CASE(MINT_LDC_R8
)
2187 sp
->data
.l
= READ64 (ip
+ 1); /* note union usage */
2191 MINT_IN_CASE(MINT_DUP
)
2196 MINT_IN_CASE(MINT_DUP_VT
)
2197 i32
= READ32 (ip
+ 1);
2199 memcpy(sp
->data
.p
, sp
[-1].data
.p
, i32
);
2200 vt_sp
+= (i32
+ 7) & ~7;
2204 MINT_IN_CASE(MINT_POP
) {
2205 guint16 u16
= (* (guint16
*)(ip
+ 1)) + 1;
2207 memmove (sp
- u16
, sp
- 1, (u16
- 1) * sizeof (stackval
));
2212 MINT_IN_CASE(MINT_JMP
) {
2213 RuntimeMethod
*new_method
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2214 if (!new_method
->transformed
) {
2216 frame
->ex
= mono_interp_transform_method (new_method
, context
);
2221 if (new_method
->alloca_size
> rtm
->alloca_size
)
2222 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method
->alloca_size
, rtm
->alloca_size
);
2223 rtm
= frame
->runtime_method
= new_method
;
2224 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
2228 locals
= vt_sp
+ rtm
->vt_stack_size
;
2229 ip
= rtm
->new_body_start
; /* bypass storing input args from callers frame */
2232 MINT_IN_CASE(MINT_CALLI
) {
2233 MonoMethodSignature
*csignature
;
2234 stackval
*endsp
= sp
;
2238 csignature
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2242 child_frame
.runtime_method
= sp
->data
.p
;
2245 child_frame
.retval
= sp
;
2246 /* decrement by the actual number of args */
2247 sp
-= csignature
->param_count
;
2248 if (csignature
->hasthis
)
2250 child_frame
.stack_args
= sp
;
2252 /* `this' can be NULL for string:.ctor */
2253 if (csignature
->hasthis
&& sp
->data
.p
&& mono_object_is_transparent_proxy (sp
->data
.p
)) {
2254 child_frame
.runtime_method
= mono_interp_get_runtime_method (context
->domain
, mono_marshal_get_remoting_invoke (child_frame
.runtime_method
->method
), &error
);
2255 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
2256 } else if (child_frame
.runtime_method
->method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
2257 child_frame
.runtime_method
= mono_interp_get_runtime_method (context
->domain
, mono_marshal_get_native_wrapper (child_frame
.runtime_method
->method
, FALSE
, FALSE
), &error
);
2258 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
2261 if (csignature
->hasthis
) {
2262 MonoObject
*this_arg
= sp
->data
.p
;
2264 if (this_arg
->vtable
->klass
->valuetype
) {
2265 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2266 sp
[0].data
.p
= unboxed
;
2270 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2272 context
->current_frame
= frame
;
2274 if (context
->has_resume_state
) {
2275 if (frame
== context
->handler_frame
)
2276 SET_RESUME_STATE (context
);
2281 if (child_frame
.ex
) {
2283 * An exception occurred, need to run finally, fault and catch handlers..
2285 frame
->ex
= child_frame
.ex
;
2286 goto handle_finally
;
2289 /* need to handle typedbyref ... */
2290 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2296 MINT_IN_CASE(MINT_CALLI_NAT
) {
2297 MonoMethodSignature
*csignature
;
2298 stackval
*endsp
= sp
;
2299 unsigned char *code
= NULL
;
2303 csignature
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2308 child_frame
.runtime_method
= NULL
;
2311 child_frame
.retval
= sp
;
2312 /* decrement by the actual number of args */
2313 sp
-= csignature
->param_count
;
2314 if (csignature
->hasthis
)
2316 child_frame
.stack_args
= sp
;
2317 ves_pinvoke_method (&child_frame
, csignature
, (MonoFuncV
) code
, FALSE
, context
);
2319 context
->current_frame
= frame
;
2321 if (context
->has_resume_state
) {
2322 if (frame
== context
->handler_frame
)
2323 SET_RESUME_STATE (context
);
2328 if (child_frame
.ex
) {
2330 * An exception occurred, need to run finally, fault and catch handlers..
2332 frame
->ex
= child_frame
.ex
;
2333 if (context
->search_for_handler
) {
2334 context
->search_for_handler
= 0;
2335 goto handle_exception
;
2337 goto handle_finally
;
2340 /* need to handle typedbyref ... */
2341 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2347 MINT_IN_CASE(MINT_CALL
) {
2348 stackval
*endsp
= sp
;
2352 child_frame
.runtime_method
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2355 child_frame
.retval
= sp
;
2356 /* decrement by the actual number of args */
2357 sp
-= child_frame
.runtime_method
->param_count
;
2358 if (child_frame
.runtime_method
->hasthis
)
2360 child_frame
.stack_args
= sp
;
2362 /* `this' can be NULL for string:.ctor */
2363 if (child_frame
.runtime_method
->hasthis
&& !child_frame
.runtime_method
->method
->klass
->valuetype
&& sp
->data
.p
&& mono_object_is_transparent_proxy (sp
->data
.p
)) {
2364 child_frame
.runtime_method
= mono_interp_get_runtime_method (context
->domain
, mono_marshal_get_remoting_invoke (child_frame
.runtime_method
->method
), &error
);
2365 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
2368 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2370 context
->current_frame
= frame
;
2372 if (context
->has_resume_state
) {
2373 if (frame
== context
->handler_frame
)
2374 SET_RESUME_STATE (context
);
2379 if (child_frame
.ex
) {
2381 * An exception occurred, need to run finally, fault and catch handlers..
2383 frame
->ex
= child_frame
.ex
;
2384 goto handle_exception
;;
2387 /* need to handle typedbyref ... */
2392 MINT_IN_CASE(MINT_VCALL
) {
2395 child_frame
.runtime_method
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2399 child_frame
.retval
= sp
;
2400 /* decrement by the actual number of args */
2401 sp
-= child_frame
.runtime_method
->param_count
;
2402 if (child_frame
.runtime_method
->hasthis
) {
2404 MonoObject
*this_arg
= sp
->data
.p
;
2406 THROW_EX (mono_get_exception_null_reference(), ip
- 2);
2408 child_frame
.stack_args
= sp
;
2410 if (child_frame
.runtime_method
->hasthis
&& !child_frame
.runtime_method
->method
->klass
->valuetype
&& mono_object_is_transparent_proxy (sp
->data
.p
)) {
2411 child_frame
.runtime_method
= mono_interp_get_runtime_method (context
->domain
, mono_marshal_get_remoting_invoke (child_frame
.runtime_method
->method
), &error
);
2412 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
2415 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2417 context
->current_frame
= frame
;
2419 if (context
->has_resume_state
) {
2420 if (frame
== context
->handler_frame
)
2421 SET_RESUME_STATE (context
);
2426 if (child_frame
.ex
) {
2428 * An exception occurred, need to run finally, fault and catch handlers..
2430 frame
->ex
= child_frame
.ex
;
2431 goto handle_finally
;
2436 MINT_IN_CASE(MINT_JIT_CALL
) {
2437 MonoMethodSignature
*sig
;
2438 RuntimeMethod
*rmethod
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
2439 MonoFtnDesc ftndesc
;
2440 guint8 res_buf
[256];
2444 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
2447 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2448 * by ref and return a return value using an explicit return value argument.
2450 if (!rmethod
->jit_wrapper
) {
2451 MonoMethod
*method
= rmethod
->method
;
2454 sig
= mono_method_signature (method
);
2457 MonoMethod
*wrapper
= mini_get_gsharedvt_out_sig_wrapper (sig
);
2458 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2460 gpointer jit_wrapper
= mono_jit_compile_method_jit_only (wrapper
, &error
);
2461 mono_error_assert_ok (&error
);
2463 gpointer addr
= mono_jit_compile_method_jit_only (method
, &error
);
2465 mono_error_assert_ok (&error
);
2467 rmethod
->jit_addr
= addr
;
2468 rmethod
->jit_sig
= sig
;
2469 mono_memory_barrier ();
2470 rmethod
->jit_wrapper
= jit_wrapper
;
2473 sig
= rmethod
->jit_sig
;
2478 sp
-= sig
->param_count
;
2482 ftndesc
.addr
= rmethod
->jit_addr
;
2485 // FIXME: Optimize this
2489 int stack_index
= 0;
2490 if (rmethod
->hasthis
) {
2491 args
[pindex
++] = sp
[0].data
.p
;
2494 type
= rmethod
->rtype
;
2495 if (type
->type
!= MONO_TYPE_VOID
) {
2496 if (MONO_TYPE_ISSTRUCT (type
))
2497 args
[pindex
++] = vt_sp
;
2499 args
[pindex
++] = res_buf
;
2501 for (int i
= 0; i
< rmethod
->param_count
; ++i
) {
2502 MonoType
*t
= rmethod
->param_types
[i
];
2503 stackval
*sval
= &sp
[stack_index
+ i
];
2504 if (sig
->params
[i
]->byref
) {
2505 args
[pindex
++] = sval
->data
.p
;
2506 } else if (MONO_TYPE_ISSTRUCT (t
)) {
2507 args
[pindex
++] = sval
->data
.p
;
2508 } else if (MONO_TYPE_IS_REFERENCE (t
)) {
2509 args
[pindex
++] = &sval
->data
.p
;
2518 case MONO_TYPE_VALUETYPE
:
2519 args
[pindex
++] = &sval
->data
.i
;
2522 case MONO_TYPE_FNPTR
:
2525 case MONO_TYPE_OBJECT
:
2526 args
[pindex
++] = &sval
->data
.p
;
2530 args
[pindex
++] = &sval
->data
.l
;
2533 printf ("%s\n", mono_type_full_name (t
));
2534 g_assert_not_reached ();
2540 * Push an LMF frame on the LMF stack
2541 * to mark the transition to compiled code.
2543 memset (&ext
, 0, sizeof (ext
));
2544 ext
.interp_exit
= TRUE
;
2545 ext
.interp_exit_data
= frame
;
2547 mono_push_lmf (&ext
);
2551 void (*func
)(gpointer
) = rmethod
->jit_wrapper
;
2557 void (*func
)(gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2559 func (args
[0], &ftndesc
);
2563 void (*func
)(gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2565 func (args
[0], args
[1], &ftndesc
);
2569 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2571 func (args
[0], args
[1], args
[2], &ftndesc
);
2575 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2577 func (args
[0], args
[1], args
[2], args
[3], &ftndesc
);
2581 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2583 func (args
[0], args
[1], args
[2], args
[3], args
[4], &ftndesc
);
2587 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2589 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], &ftndesc
);
2593 void (*func
)(gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
, gpointer
) = rmethod
->jit_wrapper
;
2595 func (args
[0], args
[1], args
[2], args
[3], args
[4], args
[5], args
[6], &ftndesc
);
2599 g_assert_not_reached ();
2603 mono_pop_lmf (&ext
.lmf
);
2605 if (context
->has_resume_state
) {
2607 * If this bit is set, it means the call has thrown the exception, and we
2608 * reached this point because the EH code in mono_handle_exception ()
2609 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2610 * has set the fields in context to indicate where we have to resume execution.
2612 if (frame
== context
->handler_frame
)
2613 SET_RESUME_STATE (context
);
2618 MonoType
*rtype
= rmethod
->rtype
;
2619 switch (rtype
->type
) {
2620 case MONO_TYPE_VOID
:
2621 case MONO_TYPE_OBJECT
:
2622 case MONO_TYPE_STRING
:
2623 case MONO_TYPE_CLASS
:
2624 case MONO_TYPE_ARRAY
:
2625 case MONO_TYPE_SZARRAY
:
2628 sp
->data
.p
= *(gpointer
*)res_buf
;
2631 sp
->data
.i
= *(gint8
*)res_buf
;
2634 sp
->data
.i
= *(guint8
*)res_buf
;
2637 sp
->data
.i
= *(gint16
*)res_buf
;
2640 sp
->data
.i
= *(guint16
*)res_buf
;
2643 sp
->data
.i
= *(gint32
*)res_buf
;
2646 sp
->data
.i
= *(guint32
*)res_buf
;
2648 case MONO_TYPE_VALUETYPE
:
2649 /* The result was written to vt_sp */
2652 case MONO_TYPE_GENERICINST
:
2653 if (MONO_TYPE_IS_REFERENCE (rtype
)) {
2654 sp
->data
.p
= *(gpointer
*)res_buf
;
2656 /* The result was written to vt_sp */
2661 printf ("%s\n", mono_type_full_name (rtype
));
2662 g_assert_not_reached ();
2665 if (rtype
->type
!= MONO_TYPE_VOID
)
2670 MINT_IN_CASE(MINT_CALLVIRT
) {
2671 stackval
*endsp
= sp
;
2672 MonoObject
*this_arg
;
2677 token
= * (unsigned short *)(ip
+ 1);
2679 child_frame
.runtime_method
= rtm
->data_items
[token
];
2681 child_frame
.retval
= sp
;
2683 /* decrement by the actual number of args */
2684 sp
-= child_frame
.runtime_method
->param_count
+ 1;
2685 child_frame
.stack_args
= sp
;
2686 this_arg
= sp
->data
.p
;
2688 THROW_EX (mono_get_exception_null_reference(), ip
- 2);
2689 child_frame
.runtime_method
= get_virtual_method (context
->domain
, child_frame
.runtime_method
, this_arg
);
2691 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2692 if (this_class
->valuetype
&& child_frame
.runtime_method
->method
->klass
->valuetype
) {
2694 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2695 sp
[0].data
.p
= unboxed
;
2698 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2700 context
->current_frame
= frame
;
2702 if (context
->has_resume_state
) {
2703 if (frame
== context
->handler_frame
)
2704 SET_RESUME_STATE (context
);
2709 if (child_frame
.ex
) {
2711 * An exception occurred, need to run finally, fault and catch handlers..
2713 frame
->ex
= child_frame
.ex
;
2714 if (context
->search_for_handler
) {
2715 context
->search_for_handler
= 0;
2716 goto handle_exception
;
2718 goto handle_finally
;
2721 /* need to handle typedbyref ... */
2726 MINT_IN_CASE(MINT_VCALLVIRT
) {
2727 MonoObject
*this_arg
;
2732 token
= * (unsigned short *)(ip
+ 1);
2734 child_frame
.runtime_method
= rtm
->data_items
[token
];
2736 child_frame
.retval
= sp
;
2738 /* decrement by the actual number of args */
2739 sp
-= child_frame
.runtime_method
->param_count
+ 1;
2740 child_frame
.stack_args
= sp
;
2741 this_arg
= sp
->data
.p
;
2743 THROW_EX (mono_get_exception_null_reference(), ip
- 2);
2744 child_frame
.runtime_method
= get_virtual_method (context
->domain
, child_frame
.runtime_method
, this_arg
);
2746 MonoClass
*this_class
= this_arg
->vtable
->klass
;
2747 if (this_class
->valuetype
&& child_frame
.runtime_method
->method
->klass
->valuetype
) {
2748 gpointer
*unboxed
= mono_object_unbox (this_arg
);
2749 sp
[0].data
.p
= unboxed
;
2752 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
2754 context
->current_frame
= frame
;
2756 if (context
->has_resume_state
) {
2757 if (frame
== context
->handler_frame
)
2758 SET_RESUME_STATE (context
);
2763 if (child_frame
.ex
) {
2765 * An exception occurred, need to run finally, fault and catch handlers..
2767 frame
->ex
= child_frame
.ex
;
2768 if (context
->search_for_handler
) {
2769 context
->search_for_handler
= 0;
2770 goto handle_exception
;
2772 goto handle_finally
;
2776 MINT_IN_CASE(MINT_CALLRUN
)
2777 ves_runtime_method (frame
, context
);
2780 goto handle_exception
;
2783 MINT_IN_CASE(MINT_RET
)
2785 *frame
->retval
= *sp
;
2786 if (sp
> frame
->stack
)
2787 g_warning ("ret: more values on stack: %d", sp
-frame
->stack
);
2789 MINT_IN_CASE(MINT_RET_VOID
)
2790 if (sp
> frame
->stack
)
2791 g_warning ("ret.void: more values on stack: %d", sp
-frame
->stack
);
2793 MINT_IN_CASE(MINT_RET_VT
)
2794 i32
= READ32(ip
+ 1);
2796 memcpy(frame
->retval
->data
.p
, sp
->data
.p
, i32
);
2797 if (sp
> frame
->stack
)
2798 g_warning ("ret.vt: more values on stack: %d", sp
-frame
->stack
);
2800 MINT_IN_CASE(MINT_BR_S
)
2801 ip
+= (short) *(ip
+ 1);
2803 MINT_IN_CASE(MINT_BR
)
2804 ip
+= (gint32
) READ32(ip
+ 1);
2806 #define ZEROP_S(datamem, op) \
2808 if (sp->data.datamem op 0) \
2809 ip += * (gint16 *)(ip + 1); \
2813 #define ZEROP(datamem, op) \
2815 if (sp->data.datamem op 0) \
2816 ip += READ32(ip + 1); \
2820 MINT_IN_CASE(MINT_BRFALSE_I4_S
)
2823 MINT_IN_CASE(MINT_BRFALSE_I8_S
)
2826 MINT_IN_CASE(MINT_BRFALSE_R8_S
)
2829 MINT_IN_CASE(MINT_BRFALSE_I4
)
2832 MINT_IN_CASE(MINT_BRFALSE_I8
)
2835 MINT_IN_CASE(MINT_BRFALSE_R8
)
2838 MINT_IN_CASE(MINT_BRTRUE_I4_S
)
2841 MINT_IN_CASE(MINT_BRTRUE_I8_S
)
2844 MINT_IN_CASE(MINT_BRTRUE_R8_S
)
2847 MINT_IN_CASE(MINT_BRTRUE_I4
)
2850 MINT_IN_CASE(MINT_BRTRUE_I8
)
2853 MINT_IN_CASE(MINT_BRTRUE_R8
)
2856 #define CONDBR_S(cond) \
2859 ip += * (gint16 *)(ip + 1); \
2862 #define BRELOP_S(datamem, op) \
2863 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2865 #define CONDBR(cond) \
2868 ip += READ32(ip + 1); \
2872 #define BRELOP(datamem, op) \
2873 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2875 MINT_IN_CASE(MINT_BEQ_I4_S
)
2878 MINT_IN_CASE(MINT_BEQ_I8_S
)
2881 MINT_IN_CASE(MINT_BEQ_R8_S
)
2882 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
2884 MINT_IN_CASE(MINT_BEQ_I4
)
2887 MINT_IN_CASE(MINT_BEQ_I8
)
2890 MINT_IN_CASE(MINT_BEQ_R8
)
2891 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
== sp
[1].data
.f
)
2893 MINT_IN_CASE(MINT_BGE_I4_S
)
2896 MINT_IN_CASE(MINT_BGE_I8_S
)
2899 MINT_IN_CASE(MINT_BGE_R8_S
)
2900 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
2902 MINT_IN_CASE(MINT_BGE_I4
)
2905 MINT_IN_CASE(MINT_BGE_I8
)
2908 MINT_IN_CASE(MINT_BGE_R8
)
2909 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
>= sp
[1].data
.f
)
2911 MINT_IN_CASE(MINT_BGT_I4_S
)
2914 MINT_IN_CASE(MINT_BGT_I8_S
)
2917 MINT_IN_CASE(MINT_BGT_R8_S
)
2918 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
2920 MINT_IN_CASE(MINT_BGT_I4
)
2923 MINT_IN_CASE(MINT_BGT_I8
)
2926 MINT_IN_CASE(MINT_BGT_R8
)
2927 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
> sp
[1].data
.f
)
2929 MINT_IN_CASE(MINT_BLT_I4_S
)
2932 MINT_IN_CASE(MINT_BLT_I8_S
)
2935 MINT_IN_CASE(MINT_BLT_R8_S
)
2936 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
2938 MINT_IN_CASE(MINT_BLT_I4
)
2941 MINT_IN_CASE(MINT_BLT_I8
)
2944 MINT_IN_CASE(MINT_BLT_R8
)
2945 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
< sp
[1].data
.f
)
2947 MINT_IN_CASE(MINT_BLE_I4_S
)
2950 MINT_IN_CASE(MINT_BLE_I8_S
)
2953 MINT_IN_CASE(MINT_BLE_R8_S
)
2954 CONDBR_S(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
2956 MINT_IN_CASE(MINT_BLE_I4
)
2959 MINT_IN_CASE(MINT_BLE_I8
)
2962 MINT_IN_CASE(MINT_BLE_R8
)
2963 CONDBR(!isunordered (sp
[0].data
.f
, sp
[1].data
.f
) && sp
[0].data
.f
<= sp
[1].data
.f
)
2965 MINT_IN_CASE(MINT_BNE_UN_I4_S
)
2968 MINT_IN_CASE(MINT_BNE_UN_I8_S
)
2971 MINT_IN_CASE(MINT_BNE_UN_R8_S
)
2972 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
2974 MINT_IN_CASE(MINT_BNE_UN_I4
)
2977 MINT_IN_CASE(MINT_BNE_UN_I8
)
2980 MINT_IN_CASE(MINT_BNE_UN_R8
)
2981 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
!= sp
[1].data
.f
)
2984 #define BRELOP_S_CAST(datamem, op, type) \
2986 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2987 ip += * (gint16 *)(ip + 1); \
2991 #define BRELOP_CAST(datamem, op, type) \
2993 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2994 ip += READ32(ip + 1); \
2998 MINT_IN_CASE(MINT_BGE_UN_I4_S
)
2999 BRELOP_S_CAST(i
, >=, guint32
);
3001 MINT_IN_CASE(MINT_BGE_UN_I8_S
)
3002 BRELOP_S_CAST(l
, >=, guint64
);
3004 MINT_IN_CASE(MINT_BGE_UN_R8_S
)
3005 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3007 MINT_IN_CASE(MINT_BGE_UN_I4
)
3008 BRELOP_CAST(i
, >=, guint32
);
3010 MINT_IN_CASE(MINT_BGE_UN_I8
)
3011 BRELOP_CAST(l
, >=, guint64
);
3013 MINT_IN_CASE(MINT_BGE_UN_R8
)
3014 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
>= sp
[1].data
.f
)
3016 MINT_IN_CASE(MINT_BGT_UN_I4_S
)
3017 BRELOP_S_CAST(i
, >, guint32
);
3019 MINT_IN_CASE(MINT_BGT_UN_I8_S
)
3020 BRELOP_S_CAST(l
, >, guint64
);
3022 MINT_IN_CASE(MINT_BGT_UN_R8_S
)
3023 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3025 MINT_IN_CASE(MINT_BGT_UN_I4
)
3026 BRELOP_CAST(i
, >, guint32
);
3028 MINT_IN_CASE(MINT_BGT_UN_I8
)
3029 BRELOP_CAST(l
, >, guint64
);
3031 MINT_IN_CASE(MINT_BGT_UN_R8
)
3032 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
> sp
[1].data
.f
)
3034 MINT_IN_CASE(MINT_BLE_UN_I4_S
)
3035 BRELOP_S_CAST(i
, <=, guint32
);
3037 MINT_IN_CASE(MINT_BLE_UN_I8_S
)
3038 BRELOP_S_CAST(l
, <=, guint64
);
3040 MINT_IN_CASE(MINT_BLE_UN_R8_S
)
3041 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3043 MINT_IN_CASE(MINT_BLE_UN_I4
)
3044 BRELOP_CAST(i
, <=, guint32
);
3046 MINT_IN_CASE(MINT_BLE_UN_I8
)
3047 BRELOP_CAST(l
, <=, guint64
);
3049 MINT_IN_CASE(MINT_BLE_UN_R8
)
3050 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
<= sp
[1].data
.f
)
3052 MINT_IN_CASE(MINT_BLT_UN_I4_S
)
3053 BRELOP_S_CAST(i
, <, guint32
);
3055 MINT_IN_CASE(MINT_BLT_UN_I8_S
)
3056 BRELOP_S_CAST(l
, <, guint64
);
3058 MINT_IN_CASE(MINT_BLT_UN_R8_S
)
3059 CONDBR_S(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3061 MINT_IN_CASE(MINT_BLT_UN_I4
)
3062 BRELOP_CAST(i
, <, guint32
);
3064 MINT_IN_CASE(MINT_BLT_UN_I8
)
3065 BRELOP_CAST(l
, <, guint64
);
3067 MINT_IN_CASE(MINT_BLT_UN_R8
)
3068 CONDBR(isunordered (sp
[0].data
.f
, sp
[1].data
.f
) || sp
[0].data
.f
< sp
[1].data
.f
)
3070 MINT_IN_CASE(MINT_SWITCH
) {
3072 const unsigned short *st
;
3078 if ((guint32
)sp
->data
.i
< n
) {
3080 ip
+= 2 * (guint32
)sp
->data
.i
;
3081 offset
= READ32 (ip
);
3088 MINT_IN_CASE(MINT_LDIND_I1
)
3090 sp
[-1].data
.i
= *(gint8
*)sp
[-1].data
.p
;
3092 MINT_IN_CASE(MINT_LDIND_U1
)
3094 sp
[-1].data
.i
= *(guint8
*)sp
[-1].data
.p
;
3096 MINT_IN_CASE(MINT_LDIND_I2
)
3098 sp
[-1].data
.i
= *(gint16
*)sp
[-1].data
.p
;
3100 MINT_IN_CASE(MINT_LDIND_U2
)
3102 sp
[-1].data
.i
= *(guint16
*)sp
[-1].data
.p
;
3104 MINT_IN_CASE(MINT_LDIND_I4
) /* Fall through */
3105 MINT_IN_CASE(MINT_LDIND_U4
)
3107 sp
[-1].data
.i
= *(gint32
*)sp
[-1].data
.p
;
3109 MINT_IN_CASE(MINT_LDIND_I8
)
3111 sp
[-1].data
.l
= *(gint64
*)sp
[-1].data
.p
;
3113 MINT_IN_CASE(MINT_LDIND_I
) {
3114 guint16 offset
= * (guint16
*)(ip
+ 1);
3115 sp
[-1 - offset
].data
.p
= *(gpointer
*)sp
[-1 - offset
].data
.p
;
3119 MINT_IN_CASE(MINT_LDIND_R4
)
3121 sp
[-1].data
.f
= *(gfloat
*)sp
[-1].data
.p
;
3123 MINT_IN_CASE(MINT_LDIND_R8
)
3125 sp
[-1].data
.f
= *(gdouble
*)sp
[-1].data
.p
;
3127 MINT_IN_CASE(MINT_LDIND_REF
)
3129 sp
[-1].data
.p
= *(gpointer
*)sp
[-1].data
.p
;
3131 MINT_IN_CASE(MINT_STIND_REF
)
3134 mono_gc_wbarrier_generic_store (sp
->data
.p
, sp
[1].data
.p
);
3136 MINT_IN_CASE(MINT_STIND_I1
)
3139 * (gint8
*) sp
->data
.p
= (gint8
)sp
[1].data
.i
;
3141 MINT_IN_CASE(MINT_STIND_I2
)
3144 * (gint16
*) sp
->data
.p
= (gint16
)sp
[1].data
.i
;
3146 MINT_IN_CASE(MINT_STIND_I4
)
3149 * (gint32
*) sp
->data
.p
= sp
[1].data
.i
;
3151 MINT_IN_CASE(MINT_STIND_I
)
3154 * (mono_i
*) sp
->data
.p
= (mono_i
)sp
[1].data
.p
;
3156 MINT_IN_CASE(MINT_STIND_I8
)
3159 * (gint64
*) sp
->data
.p
= sp
[1].data
.l
;
3161 MINT_IN_CASE(MINT_STIND_R4
)
3164 * (float *) sp
->data
.p
= (gfloat
)sp
[1].data
.f
;
3166 MINT_IN_CASE(MINT_STIND_R8
)
3169 * (double *) sp
->data
.p
= sp
[1].data
.f
;
3171 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4
)
3174 InterlockedWrite ((gint32
*) sp
->data
.p
, sp
[1].data
.i
);
3176 #define BINOP(datamem, op) \
3178 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3180 MINT_IN_CASE(MINT_ADD_I4
)
3183 MINT_IN_CASE(MINT_ADD_I8
)
3186 MINT_IN_CASE(MINT_ADD_R8
)
3189 MINT_IN_CASE(MINT_ADD1_I4
)
3193 MINT_IN_CASE(MINT_SUB_I4
)
3196 MINT_IN_CASE(MINT_SUB_I8
)
3199 MINT_IN_CASE(MINT_SUB_R8
)
3202 MINT_IN_CASE(MINT_SUB1_I4
)
3206 MINT_IN_CASE(MINT_MUL_I4
)
3209 MINT_IN_CASE(MINT_MUL_I8
)
3212 MINT_IN_CASE(MINT_MUL_R8
)
3215 MINT_IN_CASE(MINT_DIV_I4
)
3216 if (sp
[-1].data
.i
== 0)
3217 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3218 if (sp
[-1].data
.i
== (-1))
3219 THROW_EX (mono_get_exception_overflow (), ip
);
3222 MINT_IN_CASE(MINT_DIV_I8
)
3223 if (sp
[-1].data
.l
== 0)
3224 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3225 if (sp
[-1].data
.l
== (-1))
3226 THROW_EX (mono_get_exception_overflow (), ip
);
3229 MINT_IN_CASE(MINT_DIV_R8
)
3233 #define BINOP_CAST(datamem, op, type) \
3235 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3237 MINT_IN_CASE(MINT_DIV_UN_I4
)
3238 if (sp
[-1].data
.i
== 0)
3239 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3240 BINOP_CAST(i
, /, guint32
);
3242 MINT_IN_CASE(MINT_DIV_UN_I8
)
3243 if (sp
[-1].data
.l
== 0)
3244 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3245 BINOP_CAST(l
, /, guint64
);
3247 MINT_IN_CASE(MINT_REM_I4
)
3248 if (sp
[-1].data
.i
== 0)
3249 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3250 if (sp
[-1].data
.i
== (-1))
3251 THROW_EX (mono_get_exception_overflow (), ip
);
3254 MINT_IN_CASE(MINT_REM_I8
)
3255 if (sp
[-1].data
.l
== 0)
3256 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3257 if (sp
[-1].data
.l
== (-1))
3258 THROW_EX (mono_get_exception_overflow (), ip
);
3261 MINT_IN_CASE(MINT_REM_R8
)
3262 /* FIXME: what do we actually do here? */
3264 sp
[-1].data
.f
= fmod (sp
[-1].data
.f
, sp
[0].data
.f
);
3267 MINT_IN_CASE(MINT_REM_UN_I4
)
3268 if (sp
[-1].data
.i
== 0)
3269 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3270 BINOP_CAST(i
, %, guint32
);
3272 MINT_IN_CASE(MINT_REM_UN_I8
)
3273 if (sp
[-1].data
.l
== 0)
3274 THROW_EX (mono_get_exception_divide_by_zero (), ip
);
3275 BINOP_CAST(l
, %, guint64
);
3277 MINT_IN_CASE(MINT_AND_I4
)
3280 MINT_IN_CASE(MINT_AND_I8
)
3283 MINT_IN_CASE(MINT_OR_I4
)
3286 MINT_IN_CASE(MINT_OR_I8
)
3289 MINT_IN_CASE(MINT_XOR_I4
)
3292 MINT_IN_CASE(MINT_XOR_I8
)
3296 #define SHIFTOP(datamem, op) \
3298 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3301 MINT_IN_CASE(MINT_SHL_I4
)
3304 MINT_IN_CASE(MINT_SHL_I8
)
3307 MINT_IN_CASE(MINT_SHR_I4
)
3310 MINT_IN_CASE(MINT_SHR_I8
)
3313 MINT_IN_CASE(MINT_SHR_UN_I4
)
3315 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.i
>> sp
[0].data
.i
;
3318 MINT_IN_CASE(MINT_SHR_UN_I8
)
3320 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.l
>> sp
[0].data
.i
;
3323 MINT_IN_CASE(MINT_NEG_I4
)
3324 sp
[-1].data
.i
= - sp
[-1].data
.i
;
3327 MINT_IN_CASE(MINT_NEG_I8
)
3328 sp
[-1].data
.l
= - sp
[-1].data
.l
;
3331 MINT_IN_CASE(MINT_NEG_R8
)
3332 sp
[-1].data
.f
= - sp
[-1].data
.f
;
3335 MINT_IN_CASE(MINT_NOT_I4
)
3336 sp
[-1].data
.i
= ~ sp
[-1].data
.i
;
3339 MINT_IN_CASE(MINT_NOT_I8
)
3340 sp
[-1].data
.l
= ~ sp
[-1].data
.l
;
3343 MINT_IN_CASE(MINT_CONV_I1_I4
)
3344 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.i
;
3347 MINT_IN_CASE(MINT_CONV_I1_I8
)
3348 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.l
;
3351 MINT_IN_CASE(MINT_CONV_I1_R8
)
3352 sp
[-1].data
.i
= (gint8
)sp
[-1].data
.f
;
3355 MINT_IN_CASE(MINT_CONV_U1_I4
)
3356 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.i
;
3359 MINT_IN_CASE(MINT_CONV_U1_I8
)
3360 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.l
;
3363 MINT_IN_CASE(MINT_CONV_U1_R8
)
3364 sp
[-1].data
.i
= (guint8
)sp
[-1].data
.f
;
3367 MINT_IN_CASE(MINT_CONV_I2_I4
)
3368 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.i
;
3371 MINT_IN_CASE(MINT_CONV_I2_I8
)
3372 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.l
;
3375 MINT_IN_CASE(MINT_CONV_I2_R8
)
3376 sp
[-1].data
.i
= (gint16
)sp
[-1].data
.f
;
3379 MINT_IN_CASE(MINT_CONV_U2_I4
)
3380 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.i
;
3383 MINT_IN_CASE(MINT_CONV_U2_I8
)
3384 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.l
;
3387 MINT_IN_CASE(MINT_CONV_U2_R8
)
3388 sp
[-1].data
.i
= (guint16
)sp
[-1].data
.f
;
3391 MINT_IN_CASE(MINT_CONV_I4_R8
)
3392 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.f
;
3395 MINT_IN_CASE(MINT_CONV_U4_I8
)
3396 MINT_IN_CASE(MINT_CONV_I4_I8
)
3397 sp
[-1].data
.i
= (gint32
)sp
[-1].data
.l
;
3400 MINT_IN_CASE(MINT_CONV_I4_I8_SP
)
3401 sp
[-2].data
.i
= (gint32
)sp
[-2].data
.l
;
3404 MINT_IN_CASE(MINT_CONV_U4_R8
)
3405 /* needed on arm64 */
3406 if (isinf (sp
[-1].data
.f
))
3409 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3412 MINT_IN_CASE(MINT_CONV_I8_I4
)
3413 sp
[-1].data
.l
= sp
[-1].data
.i
;
3416 MINT_IN_CASE(MINT_CONV_I8_I4_SP
)
3417 sp
[-2].data
.l
= sp
[-2].data
.i
;
3420 MINT_IN_CASE(MINT_CONV_I8_U4
)
3421 sp
[-1].data
.l
= (guint32
)sp
[-1].data
.i
;
3424 MINT_IN_CASE(MINT_CONV_I8_R8
)
3425 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
3428 MINT_IN_CASE(MINT_CONV_R4_I4
)
3429 sp
[-1].data
.f
= (float)sp
[-1].data
.i
;
3432 MINT_IN_CASE(MINT_CONV_R4_I8
)
3433 sp
[-1].data
.f
= (float)sp
[-1].data
.l
;
3436 MINT_IN_CASE(MINT_CONV_R4_R8
)
3437 sp
[-1].data
.f
= (float)sp
[-1].data
.f
;
3440 MINT_IN_CASE(MINT_CONV_R8_I4
)
3441 sp
[-1].data
.f
= (double)sp
[-1].data
.i
;
3444 MINT_IN_CASE(MINT_CONV_R8_I8
)
3445 sp
[-1].data
.f
= (double)sp
[-1].data
.l
;
3448 MINT_IN_CASE(MINT_CONV_U8_I4
)
3449 sp
[-1].data
.l
= sp
[-1].data
.i
& 0xffffffff;
3452 MINT_IN_CASE(MINT_CONV_U8_R8
)
3453 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
3456 MINT_IN_CASE(MINT_CPOBJ
) {
3457 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3458 g_assert (c
->byval_arg
.type
== MONO_TYPE_VALUETYPE
);
3459 /* if this assertion fails, we need to add a write barrier */
3460 g_assert (!MONO_TYPE_IS_REFERENCE (&c
->byval_arg
));
3461 stackval_from_data (&c
->byval_arg
, &sp
[-2], sp
[-1].data
.p
, FALSE
);
3466 MINT_IN_CASE(MINT_LDOBJ
) {
3468 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3471 if (c
->byval_arg
.type
== MONO_TYPE_VALUETYPE
&& !c
->enumtype
) {
3472 int size
= mono_class_value_size (c
, NULL
);
3473 sp
[-1].data
.p
= vt_sp
;
3474 vt_sp
+= (size
+ 7) & ~7;
3476 stackval_from_data (&c
->byval_arg
, &sp
[-1], p
, FALSE
);
3479 MINT_IN_CASE(MINT_LDSTR
)
3480 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3484 MINT_IN_CASE(MINT_NEWOBJ
) {
3485 MonoClass
*newobj_class
;
3486 MonoMethodSignature
*csig
;
3487 stackval valuetype_this
;
3493 token
= * (guint16
*)(ip
+ 1);
3496 child_frame
.ip
= NULL
;
3497 child_frame
.ex
= NULL
;
3499 child_frame
.runtime_method
= rtm
->data_items
[token
];
3500 csig
= mono_method_signature (child_frame
.runtime_method
->method
);
3501 newobj_class
= child_frame
.runtime_method
->method
->klass
;
3502 /*if (profiling_classes) {
3503 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3505 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3508 if (newobj_class
->parent
== mono_defaults
.array_class
) {
3509 sp
-= csig
->param_count
;
3510 child_frame
.stack_args
= sp
;
3511 o
= ves_array_create (&child_frame
, context
->domain
, newobj_class
, csig
, sp
);
3513 THROW_EX (child_frame
.ex
, ip
);
3514 goto array_constructed
;
3517 g_assert (csig
->hasthis
);
3518 if (csig
->param_count
) {
3519 sp
-= csig
->param_count
;
3520 memmove (sp
+ 1, sp
, csig
->param_count
* sizeof (stackval
));
3522 child_frame
.stack_args
= sp
;
3525 * First arg is the object.
3527 if (newobj_class
->valuetype
) {
3528 MonoType
*t
= &newobj_class
->byval_arg
;
3529 memset (&valuetype_this
, 0, sizeof (stackval
));
3530 if (!newobj_class
->enumtype
&& (t
->type
== MONO_TYPE_VALUETYPE
|| (t
->type
== MONO_TYPE_GENERICINST
&& mono_type_generic_inst_is_valuetype (t
)))) {
3532 valuetype_this
.data
.p
= vt_sp
;
3534 sp
->data
.p
= &valuetype_this
;
3537 if (newobj_class
!= mono_defaults
.string_class
) {
3538 context
->managed_code
= 0;
3539 o
= mono_object_new_checked (context
->domain
, newobj_class
, &error
);
3540 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3541 context
->managed_code
= 1;
3542 if (*mono_thread_interruption_request_flag ())
3543 mono_thread_interruption_checkpoint ();
3547 child_frame
.retval
= &retval
;
3551 g_assert (csig
->call_convention
== MONO_CALL_DEFAULT
);
3553 ves_exec_method_with_context (&child_frame
, context
, NULL
, NULL
, -1);
3555 context
->current_frame
= frame
;
3557 if (context
->has_resume_state
) {
3558 if (frame
== context
->handler_frame
)
3559 SET_RESUME_STATE (context
);
3564 if (child_frame
.ex
) {
3566 * An exception occurred, need to run finally, fault and catch handlers..
3568 frame
->ex
= child_frame
.ex
;
3569 goto handle_finally
;
3572 * a constructor returns void, but we need to return the object we created
3575 if (newobj_class
->valuetype
&& !newobj_class
->enumtype
) {
3576 *sp
= valuetype_this
;
3577 } else if (newobj_class
== mono_defaults
.string_class
) {
3585 MINT_IN_CASE(MINT_CASTCLASS
)
3586 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3587 if ((o
= sp
[-1].data
.p
)) {
3588 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, &error
);
3589 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3591 THROW_EX (mono_get_exception_invalid_cast (), ip
);
3595 MINT_IN_CASE(MINT_ISINST
)
3596 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3597 if ((o
= sp
[-1].data
.p
)) {
3598 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, &error
);
3599 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3601 sp
[-1].data
.p
= NULL
;
3605 MINT_IN_CASE(MINT_CONV_R_UN_I4
)
3606 sp
[-1].data
.f
= (double)(guint32
)sp
[-1].data
.i
;
3609 MINT_IN_CASE(MINT_CONV_R_UN_I8
)
3610 sp
[-1].data
.f
= (double)(guint64
)sp
[-1].data
.l
;
3613 MINT_IN_CASE(MINT_UNBOX
)
3614 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3618 THROW_EX (mono_get_exception_null_reference (), ip
);
3620 MonoObject
*isinst_obj
= mono_object_isinst_checked (o
, c
, &error
);
3621 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3622 if (!(isinst_obj
|| ((o
->vtable
->klass
->rank
== 0) && (o
->vtable
->klass
->element_class
== c
->element_class
))))
3623 THROW_EX (mono_get_exception_invalid_cast (), ip
);
3625 sp
[-1].data
.p
= mono_object_unbox (o
);
3628 MINT_IN_CASE(MINT_THROW
)
3630 frame
->ex_handler
= NULL
;
3632 sp
->data
.p
= mono_get_exception_null_reference ();
3633 THROW_EX ((MonoException
*)sp
->data
.p
, ip
);
3635 MINT_IN_CASE(MINT_LDFLDA_UNSAFE
)
3637 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
3640 MINT_IN_CASE(MINT_LDFLDA
)
3643 THROW_EX (mono_get_exception_null_reference (), ip
);
3644 sp
[-1].data
.p
= (char *)o
+ * (guint16
*)(ip
+ 1);
3647 MINT_IN_CASE(MINT_CKNULL
)
3650 THROW_EX (mono_get_exception_null_reference (), ip
);
3654 #define LDFLD(datamem, fieldtype) \
3655 o = sp [-1].data.p; \
3657 THROW_EX (mono_get_exception_null_reference (), ip); \
3658 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3661 MINT_IN_CASE(MINT_LDFLD_I1
) LDFLD(i
, gint8
); MINT_IN_BREAK
;
3662 MINT_IN_CASE(MINT_LDFLD_U1
) LDFLD(i
, guint8
); MINT_IN_BREAK
;
3663 MINT_IN_CASE(MINT_LDFLD_I2
) LDFLD(i
, gint16
); MINT_IN_BREAK
;
3664 MINT_IN_CASE(MINT_LDFLD_U2
) LDFLD(i
, guint16
); MINT_IN_BREAK
;
3665 MINT_IN_CASE(MINT_LDFLD_I4
) LDFLD(i
, gint32
); MINT_IN_BREAK
;
3666 MINT_IN_CASE(MINT_LDFLD_I8
) LDFLD(l
, gint64
); MINT_IN_BREAK
;
3667 MINT_IN_CASE(MINT_LDFLD_R4
) LDFLD(f
, float); MINT_IN_BREAK
;
3668 MINT_IN_CASE(MINT_LDFLD_R8
) LDFLD(f
, double); MINT_IN_BREAK
;
3669 MINT_IN_CASE(MINT_LDFLD_O
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
3670 MINT_IN_CASE(MINT_LDFLD_P
) LDFLD(p
, gpointer
); MINT_IN_BREAK
;
3672 MINT_IN_CASE(MINT_LDFLD_VT
)
3675 THROW_EX (mono_get_exception_null_reference (), ip
);
3676 i32
= READ32(ip
+ 2);
3677 sp
[-1].data
.p
= vt_sp
;
3678 memcpy(sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
3679 vt_sp
+= (i32
+ 7) & ~7;
3683 MINT_IN_CASE(MINT_LDRMFLD
) {
3685 MonoClassField
*field
;
3690 THROW_EX (mono_get_exception_null_reference (), ip
);
3691 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3693 if (mono_object_is_transparent_proxy (o
)) {
3694 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3696 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, &error
);
3697 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3699 addr
= (char*)o
+ field
->offset
;
3702 stackval_from_data (field
->type
, &sp
[-1], addr
, FALSE
);
3706 MINT_IN_CASE(MINT_LDRMFLD_VT
) {
3707 MonoClassField
*field
;
3713 THROW_EX (mono_get_exception_null_reference (), ip
);
3714 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3715 i32
= READ32(ip
+ 2);
3717 if (mono_object_is_transparent_proxy (o
)) {
3718 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3719 addr
= mono_load_remote_field_checked (o
, klass
, field
, &tmp
, &error
);
3720 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3722 addr
= (char*)o
+ field
->offset
;
3725 sp
[-1].data
.p
= vt_sp
;
3726 memcpy(sp
[-1].data
.p
, (char *)o
+ * (guint16
*)(ip
+ 1), i32
);
3727 vt_sp
+= (i32
+ 7) & ~7;
3728 memcpy(sp
[-1].data
.p
, addr
, i32
);
3732 #define STFLD(datamem, fieldtype) \
3733 o = sp [-2].data.p; \
3735 THROW_EX (mono_get_exception_null_reference (), ip); \
3737 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3740 MINT_IN_CASE(MINT_STFLD_I1
) STFLD(i
, gint8
); MINT_IN_BREAK
;
3741 MINT_IN_CASE(MINT_STFLD_U1
) STFLD(i
, guint8
); MINT_IN_BREAK
;
3742 MINT_IN_CASE(MINT_STFLD_I2
) STFLD(i
, gint16
); MINT_IN_BREAK
;
3743 MINT_IN_CASE(MINT_STFLD_U2
) STFLD(i
, guint16
); MINT_IN_BREAK
;
3744 MINT_IN_CASE(MINT_STFLD_I4
) STFLD(i
, gint32
); MINT_IN_BREAK
;
3745 MINT_IN_CASE(MINT_STFLD_I8
) STFLD(l
, gint64
); MINT_IN_BREAK
;
3746 MINT_IN_CASE(MINT_STFLD_R4
) STFLD(f
, float); MINT_IN_BREAK
;
3747 MINT_IN_CASE(MINT_STFLD_R8
) STFLD(f
, double); MINT_IN_BREAK
;
3748 MINT_IN_CASE(MINT_STFLD_P
) STFLD(p
, gpointer
); MINT_IN_BREAK
;
3749 MINT_IN_CASE(MINT_STFLD_O
)
3752 THROW_EX (mono_get_exception_null_reference (), ip
);
3754 mono_gc_wbarrier_set_field (o
, (char *) o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.p
);
3758 MINT_IN_CASE(MINT_STFLD_VT
)
3761 THROW_EX (mono_get_exception_null_reference (), ip
);
3762 i32
= READ32(ip
+ 2);
3764 memcpy((char *)o
+ * (guint16
*)(ip
+ 1), sp
[1].data
.p
, i32
);
3765 vt_sp
-= (i32
+ 7) & ~7;
3769 MINT_IN_CASE(MINT_STRMFLD
) {
3770 MonoClassField
*field
;
3774 THROW_EX (mono_get_exception_null_reference (), ip
);
3776 field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3779 if (mono_object_is_transparent_proxy (o
)) {
3780 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3781 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, &error
);
3782 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 i32
= READ32(ip
+ 2);
3799 if (mono_object_is_transparent_proxy (o
)) {
3800 MonoClass
*klass
= ((MonoTransparentProxy
*)o
)->remote_class
->proxy_class
;
3801 mono_store_remote_field_checked (o
, klass
, field
, &sp
[-1].data
, &error
);
3802 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3804 memcpy((char*)o
+ field
->offset
, sp
[-1].data
.p
, i32
);
3807 vt_sp
-= (i32
+ 7) & ~7;
3810 MINT_IN_CASE(MINT_LDSFLDA
) {
3811 MonoClassField
*field
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
3812 sp
->data
.p
= mono_class_static_field_address (context
->domain
, field
);
3817 MINT_IN_CASE(MINT_LDSFLD
) {
3818 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3819 gpointer addr
= mono_class_static_field_address (context
->domain
, field
);
3820 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
3825 MINT_IN_CASE(MINT_LDSFLD_VT
) {
3826 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3827 gpointer addr
= mono_class_static_field_address (context
->domain
, field
);
3828 int size
= READ32 (ip
+ 2);
3832 vt_sp
+= (size
+ 7) & ~7;
3833 stackval_from_data (field
->type
, sp
, addr
, FALSE
);
3837 MINT_IN_CASE(MINT_STSFLD
) {
3838 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3839 gpointer addr
= mono_class_static_field_address (context
->domain
, field
);
3842 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
3845 MINT_IN_CASE(MINT_STSFLD_VT
) {
3846 MonoClassField
*field
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3847 gpointer addr
= mono_class_static_field_address (context
->domain
, field
);
3848 int size
= READ32 (ip
+ 2);
3852 stackval_to_data (field
->type
, sp
, addr
, FALSE
);
3853 vt_sp
-= (size
+ 7) & ~7;
3856 MINT_IN_CASE(MINT_STOBJ_VT
) {
3858 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3860 size
= mono_class_value_size (c
, NULL
);
3861 memcpy(sp
[-2].data
.p
, sp
[-1].data
.p
, size
);
3862 vt_sp
-= (size
+ 7) & ~7;
3866 MINT_IN_CASE(MINT_STOBJ
) {
3867 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3870 g_assert (!c
->byval_arg
.byref
);
3871 if (MONO_TYPE_IS_REFERENCE (&c
->byval_arg
))
3872 mono_gc_wbarrier_generic_store (sp
[-2].data
.p
, sp
[-1].data
.p
);
3874 stackval_from_data (&c
->byval_arg
, sp
[-2].data
.p
, (char *) &sp
[-1].data
.p
, FALSE
);
3878 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8
)
3879 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGUINT32_MAX
)
3880 THROW_EX (mono_get_exception_overflow (), ip
);
3881 sp
[-1].data
.i
= (guint32
)sp
[-1].data
.f
;
3884 MINT_IN_CASE(MINT_CONV_OVF_U8_I4
)
3885 if (sp
[-1].data
.i
< 0)
3886 THROW_EX (mono_get_exception_overflow (), ip
);
3887 sp
[-1].data
.l
= sp
[-1].data
.i
;
3890 MINT_IN_CASE(MINT_CONV_OVF_U8_I8
)
3891 if (sp
[-1].data
.l
< 0)
3892 THROW_EX (mono_get_exception_overflow (), ip
);
3895 MINT_IN_CASE(MINT_CONV_OVF_I8_U8
)
3896 if ((guint64
) sp
[-1].data
.l
> MYGINT64_MAX
)
3897 THROW_EX (mono_get_exception_overflow (), ip
);
3900 MINT_IN_CASE(MINT_CONV_OVF_U8_R8
)
3901 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8
)
3902 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGINT64_MAX
)
3903 THROW_EX (mono_get_exception_overflow (), ip
);
3904 sp
[-1].data
.l
= (guint64
)sp
[-1].data
.f
;
3907 MINT_IN_CASE(MINT_CONV_OVF_I8_R8
)
3908 if (sp
[-1].data
.f
< MYGINT64_MIN
|| sp
[-1].data
.f
> MYGINT64_MAX
)
3909 THROW_EX (mono_get_exception_overflow (), ip
);
3910 sp
[-1].data
.l
= (gint64
)sp
[-1].data
.f
;
3913 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8
)
3914 if ((mono_u
)sp
[-1].data
.l
> MYGUINT32_MAX
)
3915 THROW_EX (mono_get_exception_overflow (), ip
);
3916 sp
[-1].data
.i
= (mono_u
)sp
[-1].data
.l
;
3919 MINT_IN_CASE(MINT_BOX
) {
3920 c
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
3921 guint16 offset
= * (guint16
*)(ip
+ 2);
3923 if (c
->byval_arg
.type
== MONO_TYPE_VALUETYPE
&& !c
->enumtype
) {
3924 int size
= mono_class_value_size (c
, NULL
);
3925 sp
[-1 - offset
].data
.p
= mono_value_box_checked (context
->domain
, c
, sp
[-1 - offset
].data
.p
, &error
);
3926 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3927 size
= (size
+ 7) & ~7;
3930 stackval_to_data (&c
->byval_arg
, &sp
[-1 - offset
], (char *) &sp
[-1 - offset
], FALSE
);
3931 sp
[-1 - offset
].data
.p
= mono_value_box_checked (context
->domain
, c
, &sp
[-1 - offset
], &error
);
3932 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3937 MINT_IN_CASE(MINT_NEWARR
)
3938 sp
[-1].data
.p
= (MonoObject
*) mono_array_new_checked (context
->domain
, rtm
->data_items
[*(guint16
*)(ip
+ 1)], sp
[-1].data
.i
, &error
);
3939 if (!mono_error_ok (&error
)) {
3940 THROW_EX (mono_error_convert_to_exception (&error
), ip
);
3942 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
3944 /*if (profiling_classes) {
3945 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3947 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3951 MINT_IN_CASE(MINT_LDLEN
)
3954 THROW_EX (mono_get_exception_null_reference (), ip
);
3955 sp
[-1].data
.nati
= mono_array_length ((MonoArray
*)o
);
3958 MINT_IN_CASE(MINT_GETCHR
) {
3962 THROW_EX (mono_get_exception_null_reference (), ip
);
3963 i32
= sp
[-1].data
.i
;
3964 if (i32
< 0 || i32
>= mono_string_length (s
))
3965 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
3967 sp
[-1].data
.i
= mono_string_chars(s
)[i32
];
3971 MINT_IN_CASE(MINT_STRLEN
)
3975 THROW_EX (mono_get_exception_null_reference (), ip
);
3976 sp
[-1].data
.i
= mono_string_length ((MonoString
*) o
);
3978 MINT_IN_CASE(MINT_ARRAY_RANK
)
3981 THROW_EX (mono_get_exception_null_reference (), ip
);
3982 sp
[-1].data
.i
= mono_object_class (sp
[-1].data
.p
)->rank
;
3985 MINT_IN_CASE(MINT_LDELEMA
)
3986 MINT_IN_CASE(MINT_LDELEMA_TC
) {
3987 gboolean needs_typecheck
= *ip
== MINT_LDELEMA_TC
;
3989 MonoClass
*klass
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
3990 guint16 numargs
= *(guint16
*) (ip
+ 2);
3995 sp
->data
.p
= ves_array_element_address (frame
, klass
, (MonoArray
*) o
, &sp
[1], needs_typecheck
);
3997 THROW_EX (frame
->ex
, ip
);
4002 MINT_IN_CASE(MINT_LDELEM_I1
) /* fall through */
4003 MINT_IN_CASE(MINT_LDELEM_U1
) /* fall through */
4004 MINT_IN_CASE(MINT_LDELEM_I2
) /* fall through */
4005 MINT_IN_CASE(MINT_LDELEM_U2
) /* fall through */
4006 MINT_IN_CASE(MINT_LDELEM_I4
) /* fall through */
4007 MINT_IN_CASE(MINT_LDELEM_U4
) /* fall through */
4008 MINT_IN_CASE(MINT_LDELEM_I8
) /* fall through */
4009 MINT_IN_CASE(MINT_LDELEM_I
) /* fall through */
4010 MINT_IN_CASE(MINT_LDELEM_R4
) /* fall through */
4011 MINT_IN_CASE(MINT_LDELEM_R8
) /* fall through */
4012 MINT_IN_CASE(MINT_LDELEM_REF
) /* fall through */
4013 MINT_IN_CASE(MINT_LDELEM_VT
) {
4021 THROW_EX (mono_get_exception_null_reference (), ip
);
4023 aindex
= sp
[1].data
.i
;
4024 if (aindex
>= mono_array_length (o
))
4025 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4028 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4031 case MINT_LDELEM_I1
:
4032 sp
[0].data
.i
= mono_array_get (o
, gint8
, aindex
);
4034 case MINT_LDELEM_U1
:
4035 sp
[0].data
.i
= mono_array_get (o
, guint8
, aindex
);
4037 case MINT_LDELEM_I2
:
4038 sp
[0].data
.i
= mono_array_get (o
, gint16
, aindex
);
4040 case MINT_LDELEM_U2
:
4041 sp
[0].data
.i
= mono_array_get (o
, guint16
, aindex
);
4044 sp
[0].data
.nati
= mono_array_get (o
, mono_i
, aindex
);
4046 case MINT_LDELEM_I4
:
4047 sp
[0].data
.i
= mono_array_get (o
, gint32
, aindex
);
4049 case MINT_LDELEM_U4
:
4050 sp
[0].data
.i
= mono_array_get (o
, guint32
, aindex
);
4052 case MINT_LDELEM_I8
:
4053 sp
[0].data
.l
= mono_array_get (o
, guint64
, aindex
);
4055 case MINT_LDELEM_R4
:
4056 sp
[0].data
.f
= mono_array_get (o
, float, aindex
);
4058 case MINT_LDELEM_R8
:
4059 sp
[0].data
.f
= mono_array_get (o
, double, aindex
);
4061 case MINT_LDELEM_REF
:
4062 sp
[0].data
.p
= mono_array_get (o
, gpointer
, aindex
);
4064 case MINT_LDELEM_VT
: {
4065 MonoClass
*klass_vt
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4066 i32
= READ32 (ip
+ 2);
4067 char *src_addr
= mono_array_addr_with_size ((MonoArray
*) o
, i32
, aindex
);
4068 sp
[0].data
.vt
= vt_sp
;
4069 stackval_from_data (&klass_vt
->byval_arg
, sp
, src_addr
, FALSE
);
4070 vt_sp
+= (i32
+ 7) & ~7;
4082 MINT_IN_CASE(MINT_STELEM_I
) /* fall through */
4083 MINT_IN_CASE(MINT_STELEM_I1
) /* fall through */
4084 MINT_IN_CASE(MINT_STELEM_U1
) /* fall through */
4085 MINT_IN_CASE(MINT_STELEM_I2
) /* fall through */
4086 MINT_IN_CASE(MINT_STELEM_U2
) /* fall through */
4087 MINT_IN_CASE(MINT_STELEM_I4
) /* fall through */
4088 MINT_IN_CASE(MINT_STELEM_I8
) /* fall through */
4089 MINT_IN_CASE(MINT_STELEM_R4
) /* fall through */
4090 MINT_IN_CASE(MINT_STELEM_R8
) /* fall through */
4091 MINT_IN_CASE(MINT_STELEM_REF
) /* fall through */
4092 MINT_IN_CASE(MINT_STELEM_VT
) {
4099 THROW_EX (mono_get_exception_null_reference (), ip
);
4101 aindex
= sp
[1].data
.i
;
4102 if (aindex
>= mono_array_length ((MonoArray
*)o
))
4103 THROW_EX (mono_get_exception_index_out_of_range (), ip
);
4107 mono_array_set ((MonoArray
*)o
, mono_i
, aindex
, sp
[2].data
.nati
);
4109 case MINT_STELEM_I1
:
4110 mono_array_set ((MonoArray
*)o
, gint8
, aindex
, sp
[2].data
.i
);
4112 case MINT_STELEM_U1
:
4113 mono_array_set ((MonoArray
*) o
, guint8
, aindex
, sp
[2].data
.i
);
4115 case MINT_STELEM_I2
:
4116 mono_array_set ((MonoArray
*)o
, gint16
, aindex
, sp
[2].data
.i
);
4118 case MINT_STELEM_U2
:
4119 mono_array_set ((MonoArray
*)o
, guint16
, aindex
, sp
[2].data
.i
);
4121 case MINT_STELEM_I4
:
4122 mono_array_set ((MonoArray
*)o
, gint32
, aindex
, sp
[2].data
.i
);
4124 case MINT_STELEM_I8
:
4125 mono_array_set ((MonoArray
*)o
, gint64
, aindex
, sp
[2].data
.l
);
4127 case MINT_STELEM_R4
:
4128 mono_array_set ((MonoArray
*)o
, float, aindex
, sp
[2].data
.f
);
4130 case MINT_STELEM_R8
:
4131 mono_array_set ((MonoArray
*)o
, double, aindex
, sp
[2].data
.f
);
4133 case MINT_STELEM_REF
: {
4134 MonoObject
*isinst_obj
= mono_object_isinst_checked (sp
[2].data
.p
, mono_object_class (o
)->element_class
, &error
);
4135 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4136 if (sp
[2].data
.p
&& !isinst_obj
)
4137 THROW_EX (mono_get_exception_array_type_mismatch (), ip
);
4138 mono_array_setref ((MonoArray
*) o
, aindex
, sp
[2].data
.p
);
4141 case MINT_STELEM_VT
: {
4142 MonoClass
*klass_vt
= rtm
->data_items
[*(guint16
*) (ip
+ 1)];
4143 i32
= READ32 (ip
+ 2);
4144 char *dst_addr
= mono_array_addr_with_size ((MonoArray
*) o
, i32
, aindex
);
4146 stackval_to_data (&klass_vt
->byval_arg
, &sp
[2], dst_addr
, FALSE
);
4147 vt_sp
-= (i32
+ 7) & ~7;
4158 MINT_IN_CASE(MINT_CONV_OVF_I4_U4
)
4159 if (sp
[-1].data
.i
< 0)
4160 THROW_EX (mono_get_exception_overflow (), ip
);
4163 MINT_IN_CASE(MINT_CONV_OVF_I4_I8
)
4164 if (sp
[-1].data
.l
< MYGINT32_MIN
|| sp
[-1].data
.l
> MYGINT32_MAX
)
4165 THROW_EX (mono_get_exception_overflow (), ip
);
4166 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4169 MINT_IN_CASE(MINT_CONV_OVF_I4_U8
)
4170 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> MYGINT32_MAX
)
4171 THROW_EX (mono_get_exception_overflow (), ip
);
4172 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.l
;
4175 MINT_IN_CASE(MINT_CONV_OVF_I4_R8
)
4176 if (sp
[-1].data
.f
< MYGINT32_MIN
|| sp
[-1].data
.f
> MYGINT32_MAX
)
4177 THROW_EX (mono_get_exception_overflow (), ip
);
4178 sp
[-1].data
.i
= (gint32
) sp
[-1].data
.f
;
4181 MINT_IN_CASE(MINT_CONV_OVF_U4_I4
)
4182 if (sp
[-1].data
.i
< 0)
4183 THROW_EX (mono_get_exception_overflow (), ip
);
4186 MINT_IN_CASE(MINT_CONV_OVF_U4_I8
)
4187 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> MYGUINT32_MAX
)
4188 THROW_EX (mono_get_exception_overflow (), ip
);
4189 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.l
;
4192 MINT_IN_CASE(MINT_CONV_OVF_U4_R8
)
4193 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> MYGUINT32_MAX
)
4194 THROW_EX (mono_get_exception_overflow (), ip
);
4195 sp
[-1].data
.i
= (guint32
) sp
[-1].data
.f
;
4198 MINT_IN_CASE(MINT_CONV_OVF_I2_I4
)
4199 if (sp
[-1].data
.i
< -32768 || sp
[-1].data
.i
> 32767)
4200 THROW_EX (mono_get_exception_overflow (), ip
);
4203 MINT_IN_CASE(MINT_CONV_OVF_I2_I8
)
4204 if (sp
[-1].data
.l
< -32768 || sp
[-1].data
.l
> 32767)
4205 THROW_EX (mono_get_exception_overflow (), ip
);
4206 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.l
;
4209 MINT_IN_CASE(MINT_CONV_OVF_I2_R8
)
4210 if (sp
[-1].data
.f
< -32768 || sp
[-1].data
.f
> 32767)
4211 THROW_EX (mono_get_exception_overflow (), ip
);
4212 sp
[-1].data
.i
= (gint16
) sp
[-1].data
.f
;
4215 MINT_IN_CASE(MINT_CONV_OVF_U2_I4
)
4216 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> 65535)
4217 THROW_EX (mono_get_exception_overflow (), ip
);
4220 MINT_IN_CASE(MINT_CONV_OVF_U2_I8
)
4221 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> 65535)
4222 THROW_EX (mono_get_exception_overflow (), ip
);
4223 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.l
;
4226 MINT_IN_CASE(MINT_CONV_OVF_U2_R8
)
4227 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> 65535)
4228 THROW_EX (mono_get_exception_overflow (), ip
);
4229 sp
[-1].data
.i
= (guint16
) sp
[-1].data
.f
;
4232 MINT_IN_CASE(MINT_CONV_OVF_I1_I4
)
4233 if (sp
[-1].data
.i
< -128 || sp
[-1].data
.i
> 127)
4234 THROW_EX (mono_get_exception_overflow (), ip
);
4237 MINT_IN_CASE(MINT_CONV_OVF_I1_I8
)
4238 if (sp
[-1].data
.l
< -128 || sp
[-1].data
.l
> 127)
4239 THROW_EX (mono_get_exception_overflow (), ip
);
4240 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.l
;
4243 MINT_IN_CASE(MINT_CONV_OVF_I1_R8
)
4244 if (sp
[-1].data
.f
< -128 || sp
[-1].data
.f
> 127)
4245 THROW_EX (mono_get_exception_overflow (), ip
);
4246 sp
[-1].data
.i
= (gint8
) sp
[-1].data
.f
;
4249 MINT_IN_CASE(MINT_CONV_OVF_U1_I4
)
4250 if (sp
[-1].data
.i
< 0 || sp
[-1].data
.i
> 255)
4251 THROW_EX (mono_get_exception_overflow (), ip
);
4254 MINT_IN_CASE(MINT_CONV_OVF_U1_I8
)
4255 if (sp
[-1].data
.l
< 0 || sp
[-1].data
.l
> 255)
4256 THROW_EX (mono_get_exception_overflow (), ip
);
4257 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.l
;
4260 MINT_IN_CASE(MINT_CONV_OVF_U1_R8
)
4261 if (sp
[-1].data
.f
< 0 || sp
[-1].data
.f
> 255)
4262 THROW_EX (mono_get_exception_overflow (), ip
);
4263 sp
[-1].data
.i
= (guint8
) sp
[-1].data
.f
;
4267 MINT_IN_CASE(MINT_LDELEM
)
4268 MINT_IN_CASE(MINT_STELEM
)
4269 MINT_IN_CASE(MINT_UNBOX_ANY
)
4271 MINT_IN_CASE(MINT_CKFINITE
)
4272 if (!isfinite(sp
[-1].data
.f
))
4273 THROW_EX (mono_get_exception_arithmetic (), ip
);
4276 MINT_IN_CASE(MINT_MKREFANY
) {
4277 c
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4279 /* The value address is on the stack */
4280 gpointer addr
= sp
[-1].data
.p
;
4281 /* Push the typedref value on the stack */
4282 sp
[-1].data
.p
= vt_sp
;
4283 vt_sp
+= sizeof (MonoTypedRef
);
4285 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4287 tref
->type
= &c
->byval_arg
;
4293 MINT_IN_CASE(MINT_REFANYTYPE
) {
4294 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4295 MonoType
*type
= tref
->type
;
4297 vt_sp
-= sizeof (MonoTypedRef
);
4298 sp
[-1].data
.p
= vt_sp
;
4300 *(gpointer
*)sp
[-1].data
.p
= type
;
4304 MINT_IN_CASE(MINT_REFANYVAL
) {
4305 MonoTypedRef
*tref
= sp
[-1].data
.p
;
4306 gpointer addr
= tref
->value
;
4308 vt_sp
-= sizeof (MonoTypedRef
);
4310 sp
[-1].data
.p
= addr
;
4314 MINT_IN_CASE(MINT_LDTOKEN
)
4317 * (gpointer
*)sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4321 MINT_IN_CASE(MINT_ADD_OVF_I4
)
4322 if (CHECK_ADD_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4323 THROW_EX (mono_get_exception_overflow (), ip
);
4326 MINT_IN_CASE(MINT_ADD_OVF_I8
)
4327 if (CHECK_ADD_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4328 THROW_EX (mono_get_exception_overflow (), ip
);
4331 MINT_IN_CASE(MINT_ADD_OVF_UN_I4
)
4332 if (CHECK_ADD_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4333 THROW_EX (mono_get_exception_overflow (), ip
);
4334 BINOP_CAST(i
, +, guint32
);
4336 MINT_IN_CASE(MINT_ADD_OVF_UN_I8
)
4337 if (CHECK_ADD_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4338 THROW_EX (mono_get_exception_overflow (), ip
);
4339 BINOP_CAST(l
, +, guint64
);
4341 MINT_IN_CASE(MINT_MUL_OVF_I4
)
4342 if (CHECK_MUL_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4343 THROW_EX (mono_get_exception_overflow (), ip
);
4346 MINT_IN_CASE(MINT_MUL_OVF_I8
)
4347 if (CHECK_MUL_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4348 THROW_EX (mono_get_exception_overflow (), ip
);
4351 MINT_IN_CASE(MINT_MUL_OVF_UN_I4
)
4352 if (CHECK_MUL_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4353 THROW_EX (mono_get_exception_overflow (), ip
);
4354 BINOP_CAST(i
, *, guint32
);
4356 MINT_IN_CASE(MINT_MUL_OVF_UN_I8
)
4357 if (CHECK_MUL_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4358 THROW_EX (mono_get_exception_overflow (), ip
);
4359 BINOP_CAST(l
, *, guint64
);
4361 MINT_IN_CASE(MINT_SUB_OVF_I4
)
4362 if (CHECK_SUB_OVERFLOW (sp
[-2].data
.i
, sp
[-1].data
.i
))
4363 THROW_EX (mono_get_exception_overflow (), ip
);
4366 MINT_IN_CASE(MINT_SUB_OVF_I8
)
4367 if (CHECK_SUB_OVERFLOW64 (sp
[-2].data
.l
, sp
[-1].data
.l
))
4368 THROW_EX (mono_get_exception_overflow (), ip
);
4371 MINT_IN_CASE(MINT_SUB_OVF_UN_I4
)
4372 if (CHECK_SUB_OVERFLOW_UN (sp
[-2].data
.i
, sp
[-1].data
.i
))
4373 THROW_EX (mono_get_exception_overflow (), ip
);
4374 BINOP_CAST(i
, -, guint32
);
4376 MINT_IN_CASE(MINT_SUB_OVF_UN_I8
)
4377 if (CHECK_SUB_OVERFLOW64_UN (sp
[-2].data
.l
, sp
[-1].data
.l
))
4378 THROW_EX (mono_get_exception_overflow (), ip
);
4379 BINOP_CAST(l
, -, guint64
);
4381 MINT_IN_CASE(MINT_ENDFINALLY
)
4383 int clause_index
= *ip
;
4384 if (clause_index
== exit_at_finally
)
4386 while (sp
> frame
->stack
) {
4390 ip
= finally_ips
->data
;
4391 finally_ips
= g_slist_remove (finally_ips
, ip
);
4398 MINT_IN_CASE(MINT_LEAVE
) /* Fall through */
4399 MINT_IN_CASE(MINT_LEAVE_S
)
4400 while (sp
> frame
->stack
) {
4404 if (*ip
== MINT_LEAVE_S
) {
4405 ip
+= (short) *(ip
+ 1);
4407 ip
+= (gint32
) READ32 (ip
+ 1);
4410 if (frame
->ex_handler
!= NULL
&& MONO_OFFSET_IN_HANDLER(frame
->ex_handler
, frame
->ip
- rtm
->code
)) {
4411 frame
->ex_handler
= NULL
;
4414 goto handle_finally
;
4416 MINT_IN_CASE(MINT_ICALL_V_V
)
4417 MINT_IN_CASE(MINT_ICALL_V_P
)
4418 MINT_IN_CASE(MINT_ICALL_P_V
)
4419 MINT_IN_CASE(MINT_ICALL_P_P
)
4420 MINT_IN_CASE(MINT_ICALL_PP_V
)
4421 MINT_IN_CASE(MINT_ICALL_PI_V
)
4422 MINT_IN_CASE(MINT_ICALL_PP_P
)
4423 MINT_IN_CASE(MINT_ICALL_PI_P
)
4424 MINT_IN_CASE(MINT_ICALL_PPP_V
)
4425 MINT_IN_CASE(MINT_ICALL_PPI_V
)
4426 sp
= do_icall (context
, *ip
, sp
, rtm
->data_items
[*(guint16
*)(ip
+ 1)]);
4427 if (*mono_thread_interruption_request_flag ()) {
4428 MonoException
*exc
= mono_thread_interruption_checkpoint ();
4431 context
->search_for_handler
= 1;
4434 if (frame
->ex
!= NULL
)
4435 goto handle_exception
;
4438 MINT_IN_CASE(MINT_MONO_LDPTR
)
4439 sp
->data
.p
= rtm
->data_items
[*(guint16
*)(ip
+ 1)];
4443 MINT_IN_CASE(MINT_MONO_NEWOBJ
)
4444 sp
->data
.p
= mono_object_new_checked (context
->domain
, rtm
->data_items
[*(guint16
*)(ip
+ 1)], &error
);
4445 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4449 MINT_IN_CASE(MINT_MONO_FREE
)
4452 g_error ("that doesn't seem right");
4453 g_free (sp
->data
.p
);
4455 MINT_IN_CASE(MINT_MONO_RETOBJ
)
4458 stackval_from_data (mono_method_signature (frame
->runtime_method
->method
)->ret
, frame
->retval
, sp
->data
.p
,
4459 mono_method_signature (frame
->runtime_method
->method
)->pinvoke
);
4460 if (sp
> frame
->stack
)
4461 g_warning ("retobj: more values on stack: %d", sp
-frame
->stack
);
4463 MINT_IN_CASE(MINT_MONO_TLS
) {
4464 MonoTlsKey key
= *(gint32
*)(ip
+ 1);
4465 sp
->data
.p
= ((gpointer (*)()) mono_tls_get_tls_getter (key
, FALSE
)) ();
4470 MINT_IN_CASE(MINT_MONO_JIT_ATTACH
) {
4473 context
->original_domain
= NULL
;
4474 MonoDomain
*tls_domain
= (MonoDomain
*) ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN
, FALSE
)) ();
4475 gpointer tls_jit
= ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN
, FALSE
)) ();
4477 if (tls_domain
!= context
->domain
|| !tls_jit
)
4478 context
->original_domain
= mono_jit_thread_attach (context
->domain
);
4481 MINT_IN_CASE(MINT_MONO_JIT_DETACH
)
4483 mono_jit_set_domain (context
->original_domain
);
4486 #define RELOP(datamem, op) \
4488 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4490 MINT_IN_CASE(MINT_CEQ_I4
)
4493 MINT_IN_CASE(MINT_CEQ0_I4
)
4494 sp
[-1].data
.i
= (sp
[-1].data
.i
== 0);
4497 MINT_IN_CASE(MINT_CEQ_I8
)
4500 MINT_IN_CASE(MINT_CEQ_R8
)
4502 if (isunordered (sp
[-1].data
.f
, sp
[0].data
.f
))
4505 sp
[-1].data
.i
= sp
[-1].data
.f
== sp
[0].data
.f
;
4508 MINT_IN_CASE(MINT_CGT_I4
)
4511 MINT_IN_CASE(MINT_CGT_I8
)
4514 MINT_IN_CASE(MINT_CGT_R8
)
4516 if (isunordered (sp
[-1].data
.f
, sp
[0].data
.f
))
4519 sp
[-1].data
.i
= sp
[-1].data
.f
> sp
[0].data
.f
;
4523 #define RELOP_CAST(datamem, op, type) \
4525 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4528 MINT_IN_CASE(MINT_CGT_UN_I4
)
4529 RELOP_CAST(i
, >, guint32
);
4531 MINT_IN_CASE(MINT_CGT_UN_I8
)
4532 RELOP_CAST(l
, >, guint64
);
4534 MINT_IN_CASE(MINT_CGT_UN_R8
)
4536 if (isunordered (sp
[-1].data
.f
, sp
[0].data
.f
))
4539 sp
[-1].data
.i
= sp
[-1].data
.f
> sp
[0].data
.f
;
4542 MINT_IN_CASE(MINT_CLT_I4
)
4545 MINT_IN_CASE(MINT_CLT_I8
)
4548 MINT_IN_CASE(MINT_CLT_R8
)
4550 if (isunordered (sp
[-1].data
.f
, sp
[0].data
.f
))
4553 sp
[-1].data
.i
= sp
[-1].data
.f
< sp
[0].data
.f
;
4556 MINT_IN_CASE(MINT_CLT_UN_I4
)
4557 RELOP_CAST(i
, <, guint32
);
4559 MINT_IN_CASE(MINT_CLT_UN_I8
)
4560 RELOP_CAST(l
, <, guint64
);
4562 MINT_IN_CASE(MINT_CLT_UN_R8
)
4564 if (isunordered (sp
[-1].data
.f
, sp
[0].data
.f
))
4567 sp
[-1].data
.i
= sp
[-1].data
.f
< sp
[0].data
.f
;
4570 MINT_IN_CASE(MINT_LDFTN
) {
4571 sp
->data
.p
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4576 MINT_IN_CASE(MINT_LDVIRTFTN
) {
4577 RuntimeMethod
*m
= rtm
->data_items
[* (guint16
*)(ip
+ 1)];
4581 THROW_EX (mono_get_exception_null_reference (), ip
- 2);
4583 sp
->data
.p
= get_virtual_method (context
->domain
, m
, sp
->data
.p
);
4588 #define LDARG(datamem, argtype) \
4589 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4593 MINT_IN_CASE(MINT_LDARG_I1
) LDARG(i
, gint8
); MINT_IN_BREAK
;
4594 MINT_IN_CASE(MINT_LDARG_U1
) LDARG(i
, guint8
); MINT_IN_BREAK
;
4595 MINT_IN_CASE(MINT_LDARG_I2
) LDARG(i
, gint16
); MINT_IN_BREAK
;
4596 MINT_IN_CASE(MINT_LDARG_U2
) LDARG(i
, guint16
); MINT_IN_BREAK
;
4597 MINT_IN_CASE(MINT_LDARG_I4
) LDARG(i
, gint32
); MINT_IN_BREAK
;
4598 MINT_IN_CASE(MINT_LDARG_I8
) LDARG(l
, gint64
); MINT_IN_BREAK
;
4599 MINT_IN_CASE(MINT_LDARG_R4
) LDARG(f
, float); MINT_IN_BREAK
;
4600 MINT_IN_CASE(MINT_LDARG_R8
) LDARG(f
, double); MINT_IN_BREAK
;
4601 MINT_IN_CASE(MINT_LDARG_O
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
4602 MINT_IN_CASE(MINT_LDARG_P
) LDARG(p
, gpointer
); MINT_IN_BREAK
;
4604 MINT_IN_CASE(MINT_LDARG_VT
)
4606 i32
= READ32(ip
+ 2);
4607 memcpy(sp
->data
.p
, frame
->args
+ * (guint16
*)(ip
+ 1), i32
);
4608 vt_sp
+= (i32
+ 7) & ~7;
4613 #define STARG(datamem, argtype) \
4615 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4618 MINT_IN_CASE(MINT_STARG_I1
) STARG(i
, gint8
); MINT_IN_BREAK
;
4619 MINT_IN_CASE(MINT_STARG_U1
) STARG(i
, guint8
); MINT_IN_BREAK
;
4620 MINT_IN_CASE(MINT_STARG_I2
) STARG(i
, gint16
); MINT_IN_BREAK
;
4621 MINT_IN_CASE(MINT_STARG_U2
) STARG(i
, guint16
); MINT_IN_BREAK
;
4622 MINT_IN_CASE(MINT_STARG_I4
) STARG(i
, gint32
); MINT_IN_BREAK
;
4623 MINT_IN_CASE(MINT_STARG_I8
) STARG(l
, gint64
); MINT_IN_BREAK
;
4624 MINT_IN_CASE(MINT_STARG_R4
) STARG(f
, float); MINT_IN_BREAK
;
4625 MINT_IN_CASE(MINT_STARG_R8
) STARG(f
, double); MINT_IN_BREAK
;
4626 MINT_IN_CASE(MINT_STARG_O
) STARG(p
, gpointer
); MINT_IN_BREAK
;
4627 MINT_IN_CASE(MINT_STARG_P
) STARG(p
, gpointer
); MINT_IN_BREAK
;
4629 MINT_IN_CASE(MINT_STARG_VT
)
4630 i32
= READ32(ip
+ 2);
4632 memcpy(frame
->args
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
4633 vt_sp
-= (i32
+ 7) & ~7;
4637 #define STINARG(datamem, argtype) \
4639 int n = * (guint16 *)(ip + 1); \
4640 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4644 MINT_IN_CASE(MINT_STINARG_I1
) STINARG(i
, gint8
); MINT_IN_BREAK
;
4645 MINT_IN_CASE(MINT_STINARG_U1
) STINARG(i
, guint8
); MINT_IN_BREAK
;
4646 MINT_IN_CASE(MINT_STINARG_I2
) STINARG(i
, gint16
); MINT_IN_BREAK
;
4647 MINT_IN_CASE(MINT_STINARG_U2
) STINARG(i
, guint16
); MINT_IN_BREAK
;
4648 MINT_IN_CASE(MINT_STINARG_I4
) STINARG(i
, gint32
); MINT_IN_BREAK
;
4649 MINT_IN_CASE(MINT_STINARG_I8
) STINARG(l
, gint64
); MINT_IN_BREAK
;
4650 MINT_IN_CASE(MINT_STINARG_R4
) STINARG(f
, float); MINT_IN_BREAK
;
4651 MINT_IN_CASE(MINT_STINARG_R8
) STINARG(f
, double); MINT_IN_BREAK
;
4652 MINT_IN_CASE(MINT_STINARG_O
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
4653 MINT_IN_CASE(MINT_STINARG_P
) STINARG(p
, gpointer
); MINT_IN_BREAK
;
4655 MINT_IN_CASE(MINT_STINARG_VT
) {
4656 int n
= * (guint16
*)(ip
+ 1);
4657 i32
= READ32(ip
+ 2);
4658 memcpy (frame
->args
+ rtm
->arg_offsets
[n
], frame
->stack_args
[n
].data
.p
, i32
);
4663 MINT_IN_CASE(MINT_LDARGA
)
4664 sp
->data
.p
= frame
->args
+ * (guint16
*)(ip
+ 1);
4669 #define LDLOC(datamem, argtype) \
4670 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4674 MINT_IN_CASE(MINT_LDLOC_I1
) LDLOC(i
, gint8
); MINT_IN_BREAK
;
4675 MINT_IN_CASE(MINT_LDLOC_U1
) LDLOC(i
, guint8
); MINT_IN_BREAK
;
4676 MINT_IN_CASE(MINT_LDLOC_I2
) LDLOC(i
, gint16
); MINT_IN_BREAK
;
4677 MINT_IN_CASE(MINT_LDLOC_U2
) LDLOC(i
, guint16
); MINT_IN_BREAK
;
4678 MINT_IN_CASE(MINT_LDLOC_I4
) LDLOC(i
, gint32
); MINT_IN_BREAK
;
4679 MINT_IN_CASE(MINT_LDLOC_I8
) LDLOC(l
, gint64
); MINT_IN_BREAK
;
4680 MINT_IN_CASE(MINT_LDLOC_R4
) LDLOC(f
, float); MINT_IN_BREAK
;
4681 MINT_IN_CASE(MINT_LDLOC_R8
) LDLOC(f
, double); MINT_IN_BREAK
;
4682 MINT_IN_CASE(MINT_LDLOC_O
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
4683 MINT_IN_CASE(MINT_LDLOC_P
) LDLOC(p
, gpointer
); MINT_IN_BREAK
;
4685 MINT_IN_CASE(MINT_LDLOC_VT
)
4687 i32
= READ32(ip
+ 2);
4688 memcpy(sp
->data
.p
, locals
+ * (guint16
*)(ip
+ 1), i32
);
4689 vt_sp
+= (i32
+ 7) & ~7;
4694 MINT_IN_CASE(MINT_LDLOCA_S
)
4695 sp
->data
.p
= locals
+ * (guint16
*)(ip
+ 1);
4700 #define STLOC(datamem, argtype) \
4702 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4705 MINT_IN_CASE(MINT_STLOC_I1
) STLOC(i
, gint8
); MINT_IN_BREAK
;
4706 MINT_IN_CASE(MINT_STLOC_U1
) STLOC(i
, guint8
); MINT_IN_BREAK
;
4707 MINT_IN_CASE(MINT_STLOC_I2
) STLOC(i
, gint16
); MINT_IN_BREAK
;
4708 MINT_IN_CASE(MINT_STLOC_U2
) STLOC(i
, guint16
); MINT_IN_BREAK
;
4709 MINT_IN_CASE(MINT_STLOC_I4
) STLOC(i
, gint32
); MINT_IN_BREAK
;
4710 MINT_IN_CASE(MINT_STLOC_I8
) STLOC(l
, gint64
); MINT_IN_BREAK
;
4711 MINT_IN_CASE(MINT_STLOC_R4
) STLOC(f
, float); MINT_IN_BREAK
;
4712 MINT_IN_CASE(MINT_STLOC_R8
) STLOC(f
, double); MINT_IN_BREAK
;
4713 MINT_IN_CASE(MINT_STLOC_O
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
4714 MINT_IN_CASE(MINT_STLOC_P
) STLOC(p
, gpointer
); MINT_IN_BREAK
;
4716 #define STLOC_NP(datamem, argtype) \
4717 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4720 MINT_IN_CASE(MINT_STLOC_NP_I4
) STLOC_NP(i
, gint32
); MINT_IN_BREAK
;
4721 MINT_IN_CASE(MINT_STLOC_NP_O
) STLOC_NP(p
, gpointer
); MINT_IN_BREAK
;
4723 MINT_IN_CASE(MINT_STLOC_VT
)
4724 i32
= READ32(ip
+ 2);
4726 memcpy(locals
+ * (guint16
*)(ip
+ 1), sp
->data
.p
, i32
);
4727 vt_sp
-= (i32
+ 7) & ~7;
4731 MINT_IN_CASE(MINT_LOCALLOC
) {
4732 if (sp
!= frame
->stack
+ 1) /*FIX?*/
4733 THROW_EX (mono_get_exception_execution_engine (NULL
), ip
);
4735 int len
= sp
[-1].data
.i
;
4736 sp
[-1].data
.p
= alloca (len
);
4737 MonoMethodHeader
*header
= mono_method_get_header_checked (frame
->runtime_method
->method
, &error
);
4738 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4739 if (header
&& header
->init_locals
)
4740 memset (sp
[-1].data
.p
, 0, len
);
4744 MINT_IN_CASE(MINT_ENDFILTER
)
4745 /* top of stack is result of filter */
4746 frame
->retval
= &sp
[-1];
4748 MINT_IN_CASE(MINT_INITOBJ
)
4750 memset (sp
->data
.vt
, 0, READ32(ip
+ 1));
4753 MINT_IN_CASE(MINT_CPBLK
)
4755 if (!sp
[0].data
.p
|| !sp
[1].data
.p
)
4756 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
4758 /* FIXME: value and size may be int64... */
4759 memcpy (sp
[0].data
.p
, sp
[1].data
.p
, sp
[2].data
.i
);
4762 MINT_IN_CASE(MINT_CONSTRAINED_
) {
4764 /* FIXME: implement */
4766 token
= READ32 (ip
);
4771 MINT_IN_CASE(MINT_INITBLK
)
4774 THROW_EX (mono_get_exception_null_reference(), ip
- 1);
4776 /* FIXME: value and size may be int64... */
4777 memset (sp
[0].data
.p
, sp
[1].data
.i
, sp
[2].data
.i
);
4780 MINT_IN_CASE(MINT_NO_
)
4781 /* FIXME: implement */
4785 MINT_IN_CASE(MINT_RETHROW
)
4787 * need to clarify what this should actually do:
4788 * start the search from the last found handler in
4789 * this method or continue in the caller or what.
4790 * Also, do we need to run finally/fault handlers after a retrow?
4791 * Well, this implementation will follow the usual search
4792 * for an handler, considering the current ip as throw spot.
4793 * We need to NULL frame->ex_handler for the later code to
4794 * actually run the new found handler.
4796 frame
->ex_handler
= NULL
;
4797 THROW_EX (frame
->ex
, ip
- 1);
4800 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip
, mono_interp_opname
[*ip
], ip
-rtm
->code
);
4801 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip
);
4805 g_assert_not_reached ();
4807 * Exception handling code.
4808 * The exception object is stored in frame->ex.
4815 MonoInvocation
*inv
;
4816 MonoExceptionClause
*clause
;
4822 g_print ("* Handling exception '%s' at IL_%04x\n",
4823 frame
->ex
== NULL
? "** Unknown **" : mono_object_class (frame
->ex
)->name
,
4824 rtm
== NULL
? 0 : frame
->ip
- rtm
->code
);
4826 if (die_on_exception
)
4829 for (inv
= frame
; inv
; inv
= inv
->parent
) {
4831 if (inv
->runtime_method
== NULL
)
4833 method
= inv
->runtime_method
->method
;
4834 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
4836 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))
4838 if (inv
->ip
== NULL
)
4840 ip_offset
= inv
->ip
- inv
->runtime_method
->code
;
4841 inv
->ex_handler
= NULL
; /* clear this in case we are trhowing an exception while handling one - this one wins */
4842 for (i
= 0; i
< inv
->runtime_method
->num_clauses
; ++i
) {
4843 clause
= &inv
->runtime_method
->clauses
[i
];
4845 g_print ("* clause [%d]: %p\n", i
, clause
);
4847 if (!MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
)) {
4850 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4853 g_print ("* Filter found at '%s'\n", method
->name
);
4855 MonoInvocation dup_frame
;
4857 memcpy (&dup_frame
, inv
, sizeof (MonoInvocation
));
4858 dup_frame
.retval
= &retval
;
4859 ves_exec_method_with_context (&dup_frame
, context
, inv
->runtime_method
->code
+ clause
->data
.filter_offset
, frame
->ex
, -1);
4860 if (dup_frame
.retval
->data
.i
) {
4863 g_print ("* Matched Filter at '%s'\n", method
->name
);
4865 inv
->ex_handler
= clause
;
4866 goto handle_finally
;
4868 } else if (clause
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) {
4869 MonoObject
*isinst_obj
= mono_object_isinst_checked ((MonoObject
*)frame
->ex
, clause
->data
.catch_class
, &error
);
4870 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4873 * OK, we found an handler, now we need to execute the finally
4874 * and fault blocks before branching to the handler code.
4878 g_print ("* Found handler at '%s'\n", method
->name
);
4880 inv
->ex_handler
= clause
;
4881 goto handle_finally
;
4887 * If we get here, no handler was found: print a stack trace.
4889 for (inv
= frame
; inv
; inv
= inv
->parent
) {
4890 if (inv
->invoke_trap
)
4891 goto handle_finally
;
4894 ex_obj
= (MonoObject
*) frame
->ex
;
4895 mono_unhandled_exception (ex_obj
);
4896 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*) mono_tls_get_jit_tls ();
4897 jit_tls
->abort_func (ex_obj
);
4898 g_assert_not_reached ();
4904 MonoExceptionClause
*clause
;
4905 GSList
*old_list
= finally_ips
;
4906 MonoMethod
*method
= frame
->runtime_method
->method
;
4907 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, &error
);
4908 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4912 g_print ("* Handle finally IL_%04x\n", endfinally_ip
== NULL
? 0 : endfinally_ip
- rtm
->code
);
4914 if (rtm
== NULL
|| (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
4915 || (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
))) {
4918 ip_offset
= frame
->ip
- rtm
->code
;
4920 if (endfinally_ip
!= NULL
)
4921 finally_ips
= g_slist_prepend(finally_ips
, (void *)endfinally_ip
);
4922 for (i
= 0; i
< header
->num_clauses
; ++i
)
4923 if (frame
->ex_handler
== &rtm
->clauses
[i
])
4927 clause
= &rtm
->clauses
[i
];
4928 if (MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
) && (endfinally_ip
== NULL
|| !(MONO_OFFSET_IN_CLAUSE (clause
, endfinally_ip
- rtm
->code
)))) {
4929 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
4930 ip
= rtm
->code
+ clause
->handler_offset
;
4931 finally_ips
= g_slist_prepend (finally_ips
, (gpointer
) ip
);
4934 g_print ("* Found finally at IL_%04x with exception: %s\n", clause
->handler_offset
, frame
->ex
? "yes": "no");
4940 endfinally_ip
= NULL
;
4942 if (old_list
!= finally_ips
&& finally_ips
) {
4943 ip
= finally_ips
->data
;
4944 finally_ips
= g_slist_remove (finally_ips
, ip
);
4945 sp
= frame
->stack
; /* spec says stack should be empty at endfinally so it should be at the start too */
4950 * If an exception is set, we need to execute the fault handler, too,
4951 * otherwise, we continue normally.
4961 MonoExceptionClause
*clause
;
4962 MonoMethod
*method
= frame
->runtime_method
->method
;
4963 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, &error
);
4964 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
4968 g_print ("* Handle fault\n");
4970 ip_offset
= frame
->ip
- rtm
->code
;
4971 for (i
= 0; i
< header
->num_clauses
; ++i
) {
4972 clause
= &rtm
->clauses
[i
];
4973 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
&& MONO_OFFSET_IN_CLAUSE (clause
, ip_offset
)) {
4974 ip
= rtm
->code
+ clause
->handler_offset
;
4977 g_print ("* Executing handler at IL_%04x\n", clause
->handler_offset
);
4983 * If the handler for the exception was found in this method, we jump
4984 * to it right away, otherwise we return and let the caller run
4985 * the finally, fault and catch blocks.
4986 * This same code should be present in the endfault opcode, but it
4987 * is corrently not assigned in the ECMA specs: LAMESPEC.
4989 if (frame
->ex_handler
) {
4992 g_print ("* Executing handler at IL_%04x\n", frame
->ex_handler
->handler_offset
);
4994 ip
= rtm
->code
+ frame
->ex_handler
->handler_offset
;
4996 vt_sp
= (unsigned char *) sp
+ rtm
->stack_size
;
4997 sp
->data
.p
= frame
->ex
;
5008 ves_exec_method (MonoInvocation
*frame
)
5010 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
5011 ThreadContext context_struct
;
5018 mono_unhandled_exception ((MonoObject
*)frame
->ex
);
5021 if (context
== NULL
) {
5022 context
= &context_struct
;
5023 context_struct
.domain
= mono_domain_get ();
5024 context_struct
.base_frame
= frame
;
5025 context_struct
.current_frame
= NULL
;
5026 context_struct
.env_frame
= frame
;
5027 context_struct
.current_env
= &env
;
5028 context_struct
.search_for_handler
= 0;
5029 context_struct
.managed_code
= 0;
5030 mono_native_tls_set_value (thread_context_id
, context
);
5033 frame
->parent
= context
->current_frame
;
5034 frame
->runtime_method
= mono_interp_get_runtime_method (context
->domain
, frame
->method
, &error
);
5035 mono_error_cleanup (&error
); /* FIXME: don't swallow the error */
5036 context
->managed_code
= 1;
5037 ves_exec_method_with_context (frame
, context
, NULL
, NULL
, -1);
5038 context
->managed_code
= 0;
5040 if (context
!= &context_struct
&& context
->current_env
) {
5041 context
->env_frame
->ex
= frame
->ex
;
5042 longjmp (*context
->current_env
, 1);
5045 mono_unhandled_exception ((MonoObject
*)frame
->ex
);
5047 if (context
->base_frame
== frame
)
5048 mono_native_tls_set_value (thread_context_id
, NULL
);
5050 context
->current_frame
= frame
->parent
;
5054 mono_interp_parse_options (const char *options
)
5058 args
= g_strsplit (options
, ",", -1);
5059 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
5062 if (strncmp (arg
, "jit=", 4) == 0)
5063 jit_classes
= g_slist_prepend (jit_classes
, arg
+ 4);
5070 mono_native_tls_alloc (&thread_context_id
, NULL
);
5071 mono_native_tls_set_value (thread_context_id
, NULL
);
5073 mono_interp_transform_init ();
5076 typedef int (*TestMethod
) (void);
5079 interp_regression_step (MonoImage
*image
, int verbose
, int *total_run
, int *total
, GTimer
*timer
, MonoDomain
*domain
)
5081 int result
, expected
, failed
, cfailed
, run
;
5082 double elapsed
, transform_time
;
5084 MonoObject
*result_obj
;
5085 static gboolean filter_method_init
= FALSE
;
5086 static const char *filter_method
= NULL
;
5088 g_print ("Test run: image=%s\n", mono_image_get_filename (image
));
5089 cfailed
= failed
= run
= 0;
5090 transform_time
= elapsed
= 0.0;
5092 g_timer_start (timer
);
5093 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
5094 MonoObject
*exc
= NULL
;
5096 MonoMethod
*method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
5098 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
5102 if (!filter_method_init
) {
5103 filter_method
= g_getenv ("INTERP_FILTER_METHOD");
5104 filter_method_init
= TRUE
;
5106 gboolean filter
= FALSE
;
5107 if (filter_method
) {
5108 const char *name
= filter_method
;
5110 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
5111 MonoMethodDesc
*desc
= mono_method_desc_new (name
, TRUE
);
5112 filter
= mono_method_desc_full_match (desc
, method
);
5113 mono_method_desc_free (desc
);
5115 filter
= strcmp (method
->name
, name
) == 0;
5117 } else { /* no filter, check for `Category' attribute on method */
5119 MonoCustomAttrInfo
* ainfo
= mono_custom_attrs_from_method_checked (method
, &error
);
5120 mono_error_cleanup (&error
);
5124 for (j
= 0; j
< ainfo
->num_attrs
&& filter
; ++j
) {
5125 MonoCustomAttrEntry
*centry
= &ainfo
->attrs
[j
];
5126 if (centry
->ctor
== NULL
)
5129 MonoClass
*klass
= centry
->ctor
->klass
;
5130 if (strcmp (klass
->name
, "CategoryAttribute"))
5133 MonoObject
*obj
= mono_custom_attrs_get_attr_checked (ainfo
, klass
, &error
);
5134 /* FIXME: there is an ordering problem if there're multiple attributes, do this instead:
5135 * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */
5136 mono_error_cleanup (&error
);
5137 MonoMethod
*getter
= mono_class_get_method_from_name (klass
, "get_Category", -1);
5138 MonoObject
*str
= mono_interp_runtime_invoke (getter
, obj
, NULL
, &exc
, &error
);
5139 mono_error_cleanup (&error
);
5140 char *utf8_str
= mono_string_to_utf8_checked ((MonoString
*) str
, &error
);
5141 mono_error_cleanup (&error
);
5142 if (!strcmp (utf8_str
, "!INTERPRETER")) {
5143 g_print ("skip %s...\n", method
->name
);
5149 if (strncmp (method
->name
, "test_", 5) == 0 && filter
) {
5150 MonoError interp_error
;
5151 MonoObject
*exc
= NULL
;
5153 result_obj
= mono_interp_runtime_invoke (method
, NULL
, NULL
, &exc
, &interp_error
);
5154 if (!mono_error_ok (&interp_error
)) {
5156 g_print ("Test '%s' execution failed.\n", method
->name
);
5157 } else if (exc
!= NULL
) {
5158 g_print ("Exception in Test '%s' occured:\n", method
->name
);
5159 mono_object_describe (exc
);
5163 result
= *(gint32
*) mono_object_unbox (result_obj
);
5164 expected
= atoi (method
->name
+ 5); // FIXME: oh no.
5167 if (result
!= expected
) {
5169 g_print ("Test '%s' failed result (got %d, expected %d).\n", method
->name
, result
, expected
);
5174 g_timer_stop (timer
);
5175 elapsed
= g_timer_elapsed (timer
, NULL
);
5176 if (failed
> 0 || cfailed
> 0){
5177 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
5178 run
, failed
, cfailed
, 100.0*(run
-failed
-cfailed
)/run
);
5180 g_print ("Results: total tests: %d, all pass \n", run
);
5183 g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed
,
5184 elapsed
- transform_time
, transform_time
);
5185 *total
+= failed
+ cfailed
;
5190 interp_regression (MonoImage
*image
, int verbose
, int *total_run
)
5193 GTimer
*timer
= g_timer_new ();
5194 MonoDomain
*domain
= mono_domain_get ();
5198 /* load the metadata */
5199 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
5201 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
5203 mono_error_cleanup (&error
);
5206 mono_class_init (method
->klass
);
5211 interp_regression_step (image
, verbose
, total_run
, &total
, timer
, domain
);
5213 g_timer_destroy (timer
);
5218 mono_interp_regression_list (int verbose
, int count
, char *images
[])
5220 int i
, total
, total_run
, run
;
5222 total_run
= total
= 0;
5223 for (i
= 0; i
< count
; ++i
) {
5224 MonoAssembly
*ass
= mono_assembly_open_predicate (images
[i
], FALSE
, FALSE
, NULL
, NULL
, NULL
);
5226 g_warning ("failed to load assembly: %s", images
[i
]);
5229 total
+= interp_regression (mono_assembly_get_image (ass
), verbose
, &run
);
5233 g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run
, total
, 100.0*(total_run
-total
)/total_run
);
5235 g_print ("Overall results: tests: %d, 100%% pass\n", total_run
);
5242 * mono_interp_set_resume_state:
5244 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5247 mono_interp_set_resume_state (MonoException
*ex
, StackFrameInfo
*frame
, gpointer handler_ip
)
5249 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
5251 context
->has_resume_state
= TRUE
;
5252 context
->handler_frame
= frame
->interp_frame
;
5253 /* This is on the stack, so it doesn't need a wbarrier */
5254 context
->handler_frame
->ex
= ex
;
5255 context
->handler_ip
= handler_ip
;
5259 * mono_interp_run_finally:
5261 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5262 * frame->interp_frame.
5265 mono_interp_run_finally (StackFrameInfo
*frame
, int clause_index
, gpointer handler_ip
)
5267 MonoInvocation
*iframe
= frame
->interp_frame
;
5268 ThreadContext
*context
= mono_native_tls_get_value (thread_context_id
);
5270 ves_exec_method_with_context (iframe
, context
, handler_ip
, NULL
, clause_index
);
5274 MonoInvocation
*current
;
5278 * mono_interp_frame_iter_init:
5280 * Initialize an iterator for iterating through interpreted frames.
5283 mono_interp_frame_iter_init (MonoInterpStackIter
*iter
, gpointer interp_exit_data
)
5285 StackIter
*stack_iter
= (StackIter
*)iter
;
5287 stack_iter
->current
= (MonoInvocation
*)interp_exit_data
;
5291 mono_interp_frame_iter_next (MonoInterpStackIter
*iter
, StackFrameInfo
*frame
)
5293 StackIter
*stack_iter
= (StackIter
*)iter
;
5294 MonoInvocation
*iframe
= stack_iter
->current
;
5296 memset (frame
, 0, sizeof (StackFrameInfo
));
5297 /* pinvoke frames doesn't have runtime_method set */
5298 while (iframe
&& !iframe
->runtime_method
)
5299 iframe
= iframe
->parent
;
5303 frame
->type
= FRAME_TYPE_INTERP
;
5304 frame
->interp_frame
= iframe
;
5305 frame
->method
= iframe
->runtime_method
->method
;
5306 frame
->actual_method
= frame
->method
;
5307 /* This is the offset in the interpreter IR */
5308 frame
->native_offset
= iframe
->ip
- iframe
->runtime_method
->code
;
5309 frame
->ji
= iframe
->runtime_method
->jinfo
;
5311 stack_iter
->current
= iframe
->parent
;