[interp] Restore frame ip after running finally handler
[mono-project.git] / mono / mini / interp / interp.c
blob23193ec86289732a5f955ffd166ddf9fc08dd8b7
1 /**
2 * \file
3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
8 * Authors:
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.
15 #ifndef __USE_ISOC99
16 #define __USE_ISOC99
17 #endif
18 #include "config.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <math.h>
25 #include <locale.h>
27 #include <mono/utils/gc_wrapper.h>
29 #ifdef HAVE_ALLOCA_H
30 # include <alloca.h>
31 #else
32 # ifdef __CYGWIN__
33 # define alloca __builtin_alloca
34 # endif
35 #endif
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
61 #include "interp.h"
62 #include "interp-internals.h"
63 #include "mintops.h"
64 #include "hacks.h"
66 #include <mono/mini/mini.h>
67 #include <mono/mini/mini-runtime.h>
68 #include <mono/mini/aot-runtime.h>
69 #include <mono/mini/jit-icalls.h>
70 #include <mono/mini/debugger-agent.h>
71 #include <mono/mini/ee.h>
73 #ifdef TARGET_ARM
74 #include <mono/mini/mini-arm.h>
75 #endif
77 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
78 #ifdef _WIN32
79 #define isnan _isnan
80 #define finite _finite
81 #endif
82 #ifndef HAVE_FINITE
83 #ifdef HAVE_ISFINITE
84 #define finite isfinite
85 #endif
86 #endif
88 static inline void
89 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
91 frame->parent = parent_frame;
92 frame->stack_args = method_args;
93 frame->retval = method_retval;
94 frame->imethod = rmethod;
95 frame->ex = NULL;
96 frame->ip = NULL;
97 frame->invoke_trap = 0;
100 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
101 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
102 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
103 } while (0)
105 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL, NULL, -1, NULL)
108 * List of classes whose methods will be executed by transitioning to JITted code.
109 * Used for testing.
111 GSList *mono_interp_jit_classes;
112 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
113 static gboolean ss_enabled;
115 static gboolean interp_init_done = FALSE;
117 static char* dump_frame (InterpFrame *inv);
118 static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top);
119 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame);
120 static InterpMethod* lookup_method_pointer (gpointer addr);
122 typedef void (*ICallMethod) (InterpFrame *frame);
124 static MonoNativeTlsKey thread_context_id;
126 static char* dump_args (InterpFrame *inv);
128 #define DEBUG_INTERP 0
129 #define COUNT_OPS 0
130 #if DEBUG_INTERP
131 int mono_interp_traceopt = 2;
132 /* If true, then we output the opcodes as we interpret them */
133 static int global_tracing = 2;
135 static int debug_indent_level = 0;
137 static int break_on_method = 0;
138 static int nested_trace = 0;
139 static GList *db_methods = NULL;
141 static void
142 output_indent (void)
144 int h;
146 for (h = 0; h < debug_indent_level; h++)
147 g_print (" ");
150 static void
151 db_match_method (gpointer data, gpointer user_data)
153 MonoMethod *m = (MonoMethod*)user_data;
154 MonoMethodDesc *desc = data;
156 if (mono_method_desc_full_match (desc, m))
157 break_on_method = 1;
160 static void
161 debug_enter (InterpFrame *frame, int *tracing)
163 if (db_methods) {
164 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
165 if (break_on_method)
166 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
167 break_on_method = 0;
169 if (*tracing) {
170 MonoMethod *method = frame->imethod->method;
171 char *mn, *args = dump_args (frame);
172 debug_indent_level++;
173 output_indent ();
174 mn = mono_method_full_name (method, FALSE);
175 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
176 g_free (mn);
177 g_print ("%s)\n", args);
178 g_free (args);
183 #define DEBUG_LEAVE() \
184 if (tracing) { \
185 char *mn, *args; \
186 args = dump_retval (frame); \
187 output_indent (); \
188 mn = mono_method_full_name (frame->imethod->method, FALSE); \
189 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
190 g_free (mn); \
191 g_print (" => %s\n", args); \
192 g_free (args); \
193 debug_indent_level--; \
194 if (tracing == 3) global_tracing = 0; \
197 #else
199 int mono_interp_traceopt = 0;
200 static void debug_enter (InterpFrame *frame, int *tracing)
203 #define DEBUG_LEAVE()
205 #endif
207 static void
208 set_resume_state (ThreadContext *context, InterpFrame *frame)
210 frame->ex = NULL;
211 context->has_resume_state = 0;
212 context->handler_frame = NULL;
213 context->handler_ei = NULL;
216 /* Set the current execution state to the resume state in context */
217 #define SET_RESUME_STATE(context) do { \
218 ip = (const guint16*)(context)->handler_ip; \
219 /* spec says stack should be empty at endfinally so it should be at the start too */ \
220 sp = frame->stack; \
221 vt_sp = (unsigned char *) sp + rtm->stack_size; \
222 if (frame->ex) { \
223 sp->data.p = frame->ex; \
224 ++sp; \
226 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
227 while (finally_ips && \
228 finally_ips->data >= (context)->handler_ei->try_start && \
229 finally_ips->data < (context)->handler_ei->try_end) \
230 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
231 set_resume_state ((context), (frame)); \
232 goto main_loop; \
233 } while (0)
235 static void
236 set_context (ThreadContext *context)
238 MonoJitTlsData *jit_tls;
240 mono_native_tls_set_value (thread_context_id, context);
241 jit_tls = mono_tls_get_jit_tls ();
242 if (jit_tls)
243 /* jit_tls assumes ownership of 'context' */
244 jit_tls->interp_context = context;
247 static void
248 ves_real_abort (int line, MonoMethod *mh,
249 const unsigned short *ip, stackval *stack, stackval *sp)
251 ERROR_DECL (error);
252 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
253 mono_error_cleanup (error); /* FIXME: don't swallow the error */
254 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
255 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
256 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
257 mono_metadata_free_mh (header);
260 #define ves_abort() \
261 do {\
262 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
263 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
264 } while (0);
266 static InterpMethod*
267 lookup_imethod (MonoDomain *domain, MonoMethod *method)
269 InterpMethod *rtm;
270 MonoJitDomainInfo *info;
272 info = domain_jit_info (domain);
273 mono_domain_jit_code_hash_lock (domain);
274 rtm = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
275 mono_domain_jit_code_hash_unlock (domain);
276 return rtm;
279 static gpointer
280 interp_get_remoting_invoke (gpointer addr, MonoError *error)
282 #ifndef DISABLE_REMOTING
283 InterpMethod *imethod = lookup_method_pointer (addr);
285 g_assert (imethod);
286 g_assert (mono_use_interpreter);
288 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
289 return_val_if_nok (error, NULL);
290 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
291 #else
292 g_assert_not_reached ();
293 return NULL;
294 #endif
297 InterpMethod*
298 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
300 InterpMethod *rtm;
301 MonoJitDomainInfo *info;
302 MonoMethodSignature *sig;
303 int i;
305 error_init (error);
307 info = domain_jit_info (domain);
308 mono_domain_jit_code_hash_lock (domain);
309 rtm = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
310 mono_domain_jit_code_hash_unlock (domain);
311 if (rtm)
312 return rtm;
314 sig = mono_method_signature (method);
316 rtm = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
317 rtm->method = method;
318 rtm->domain = domain;
319 rtm->param_count = sig->param_count;
320 rtm->hasthis = sig->hasthis;
321 rtm->vararg = sig->call_convention == MONO_CALL_VARARG;
322 rtm->rtype = mini_get_underlying_type (sig->ret);
323 rtm->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
324 for (i = 0; i < sig->param_count; ++i)
325 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
327 mono_domain_jit_code_hash_lock (domain);
328 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
329 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
330 mono_domain_jit_code_hash_unlock (domain);
332 rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method);
334 return rtm;
338 * interp_push_lmf:
340 * Push an LMF frame on the LMF stack
341 * to mark the transition to native code.
342 * This is needed for the native code to
343 * be able to do stack walks.
345 static void
346 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
348 memset (ext, 0, sizeof (MonoLMFExt));
349 ext->interp_exit = TRUE;
350 ext->interp_exit_data = frame;
352 mono_push_lmf (ext);
355 static void
356 interp_pop_lmf (MonoLMFExt *ext)
358 mono_pop_lmf (&ext->lmf);
361 static InterpMethod*
362 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
364 MonoMethod *m = imethod->method;
365 MonoDomain *domain = imethod->domain;
366 InterpMethod *ret = NULL;
367 ERROR_DECL (error);
369 #ifndef DISABLE_REMOTING
370 if (mono_object_is_transparent_proxy (obj)) {
371 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
372 mono_error_assert_ok (error);
373 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
374 mono_error_assert_ok (error);
375 return ret;
377 #endif
379 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
380 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
381 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
382 mono_error_cleanup (error); /* FIXME: don't swallow the error */
383 } else {
384 ret = imethod;
386 return ret;
389 mono_class_setup_vtable (obj->vtable->klass);
391 int slot = mono_method_get_vtable_slot (m);
392 if (mono_class_is_interface (m->klass)) {
393 g_assert (obj->vtable->klass != m->klass);
394 /* TODO: interface offset lookup is slow, go through IMT instead */
395 gboolean non_exact_match;
396 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
399 MonoMethod *virtual_method = m_class_get_vtable (mono_object_class (obj)) [slot];
400 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
401 MonoGenericContext context = { NULL, NULL };
403 if (mono_class_is_ginst (virtual_method->klass))
404 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
405 else if (mono_class_is_gtd (virtual_method->klass))
406 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
407 context.method_inst = mono_method_get_context (m)->method_inst;
409 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
410 mono_error_cleanup (error); /* FIXME: don't swallow the error */
413 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
414 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
417 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
418 mono_error_cleanup (error); /* FIXME: don't swallow the error */
419 return virtual_imethod;
422 static void inline
423 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
425 MonoType *type = mini_native_type_replace_type (type_);
426 if (type->byref) {
427 switch (type->type) {
428 case MONO_TYPE_OBJECT:
429 case MONO_TYPE_CLASS:
430 case MONO_TYPE_STRING:
431 case MONO_TYPE_ARRAY:
432 case MONO_TYPE_SZARRAY:
433 break;
434 default:
435 break;
437 result->data.p = *(gpointer*)data;
438 return;
440 switch (type->type) {
441 case MONO_TYPE_VOID:
442 return;
443 case MONO_TYPE_I1:
444 result->data.i = *(gint8*)data;
445 return;
446 case MONO_TYPE_U1:
447 case MONO_TYPE_BOOLEAN:
448 result->data.i = *(guint8*)data;
449 return;
450 case MONO_TYPE_I2:
451 result->data.i = *(gint16*)data;
452 return;
453 case MONO_TYPE_U2:
454 case MONO_TYPE_CHAR:
455 result->data.i = *(guint16*)data;
456 return;
457 case MONO_TYPE_I4:
458 result->data.i = *(gint32*)data;
459 return;
460 case MONO_TYPE_U:
461 case MONO_TYPE_I:
462 result->data.nati = *(mono_i*)data;
463 return;
464 case MONO_TYPE_PTR:
465 result->data.p = *(gpointer*)data;
466 return;
467 case MONO_TYPE_U4:
468 result->data.i = *(guint32*)data;
469 return;
470 case MONO_TYPE_R4: {
471 float tmp;
472 /* memmove handles unaligned case */
473 memmove (&tmp, data, sizeof (float));
474 result->data.f = tmp;
475 return;
477 case MONO_TYPE_I8:
478 case MONO_TYPE_U8:
479 memmove (&result->data.l, data, sizeof (gint64));
480 return;
481 case MONO_TYPE_R8:
482 memmove (&result->data.f, data, sizeof (double));
483 return;
484 case MONO_TYPE_STRING:
485 case MONO_TYPE_SZARRAY:
486 case MONO_TYPE_CLASS:
487 case MONO_TYPE_OBJECT:
488 case MONO_TYPE_ARRAY:
489 result->data.p = *(gpointer*)data;
490 return;
491 case MONO_TYPE_VALUETYPE:
492 if (m_class_is_enumtype (type->data.klass)) {
493 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
494 return;
495 } else if (pinvoke) {
496 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
497 } else {
498 mono_value_copy (result->data.vt, data, type->data.klass);
500 return;
501 case MONO_TYPE_GENERICINST: {
502 if (mono_type_generic_inst_is_valuetype (type)) {
503 mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
504 return;
506 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
507 return;
509 default:
510 g_error ("got type 0x%02x", type->type);
514 static void inline
515 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
517 MonoType *type = mini_native_type_replace_type (type_);
518 if (type->byref) {
519 gpointer *p = (gpointer*)data;
520 *p = val->data.p;
521 return;
523 /* printf ("TODAT0 %p\n", data); */
524 switch (type->type) {
525 case MONO_TYPE_I1:
526 case MONO_TYPE_U1: {
527 guint8 *p = (guint8*)data;
528 *p = val->data.i;
529 return;
531 case MONO_TYPE_BOOLEAN: {
532 guint8 *p = (guint8*)data;
533 *p = (val->data.i != 0);
534 return;
536 case MONO_TYPE_I2:
537 case MONO_TYPE_U2:
538 case MONO_TYPE_CHAR: {
539 guint16 *p = (guint16*)data;
540 *p = val->data.i;
541 return;
543 case MONO_TYPE_I: {
544 mono_i *p = (mono_i*)data;
545 /* In theory the value used by stloc should match the local var type
546 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
547 a native int - both by csc and mcs). Not sure what to do about sign extension
548 as it is outside the spec... doing the obvious */
549 *p = (mono_i)val->data.nati;
550 return;
552 case MONO_TYPE_U: {
553 mono_u *p = (mono_u*)data;
554 /* see above. */
555 *p = (mono_u)val->data.nati;
556 return;
558 case MONO_TYPE_I4:
559 case MONO_TYPE_U4: {
560 gint32 *p = (gint32*)data;
561 *p = val->data.i;
562 return;
564 case MONO_TYPE_I8:
565 case MONO_TYPE_U8: {
566 memmove (data, &val->data.l, sizeof (gint64));
567 return;
569 case MONO_TYPE_R4: {
570 float tmp = (float)val->data.f;
571 /* memmove handles unaligned case */
572 memmove (data, &tmp, sizeof (float));
573 return;
575 case MONO_TYPE_R8: {
576 memmove (data, &val->data.f, sizeof (double));
577 return;
579 case MONO_TYPE_STRING:
580 case MONO_TYPE_SZARRAY:
581 case MONO_TYPE_CLASS:
582 case MONO_TYPE_OBJECT:
583 case MONO_TYPE_ARRAY: {
584 gpointer *p = (gpointer *) data;
585 mono_gc_wbarrier_generic_store (p, val->data.o);
586 return;
588 case MONO_TYPE_PTR: {
589 gpointer *p = (gpointer *) data;
590 *p = val->data.p;
591 return;
593 case MONO_TYPE_VALUETYPE:
594 if (m_class_is_enumtype (type->data.klass)) {
595 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
596 return;
597 } else if (pinvoke) {
598 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
599 } else {
600 mono_value_copy (data, val->data.vt, type->data.klass);
602 return;
603 case MONO_TYPE_GENERICINST: {
604 MonoClass *container_class = type->data.generic_class->container_class;
606 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
607 mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
608 return;
610 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
611 return;
613 default:
614 g_error ("got type %x", type->type);
619 * Same as stackval_to_data but return address of storage instead
620 * of copying the value.
622 static gpointer
623 stackval_to_data_addr (MonoType *type_, stackval *val)
625 MonoType *type = mini_native_type_replace_type (type_);
626 if (type->byref)
627 return &val->data.p;
629 switch (type->type) {
630 case MONO_TYPE_I1:
631 case MONO_TYPE_U1:
632 case MONO_TYPE_BOOLEAN:
633 case MONO_TYPE_I2:
634 case MONO_TYPE_U2:
635 case MONO_TYPE_CHAR:
636 case MONO_TYPE_I4:
637 case MONO_TYPE_U4:
638 return &val->data.i;
639 case MONO_TYPE_I:
640 case MONO_TYPE_U:
641 return &val->data.nati;
642 case MONO_TYPE_I8:
643 case MONO_TYPE_U8:
644 return &val->data.l;
645 case MONO_TYPE_R4:
646 case MONO_TYPE_R8:
647 return &val->data.f;
648 case MONO_TYPE_STRING:
649 case MONO_TYPE_SZARRAY:
650 case MONO_TYPE_CLASS:
651 case MONO_TYPE_OBJECT:
652 case MONO_TYPE_ARRAY:
653 case MONO_TYPE_PTR:
654 return &val->data.p;
655 case MONO_TYPE_VALUETYPE:
656 if (m_class_is_enumtype (type->data.klass))
657 return stackval_to_data_addr (mono_class_enum_basetype (type->data.klass), val);
658 else
659 return val->data.vt;
660 case MONO_TYPE_TYPEDBYREF:
661 return val->data.vt;
662 case MONO_TYPE_GENERICINST: {
663 MonoClass *container_class = type->data.generic_class->container_class;
665 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
666 return val->data.vt;
667 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
669 default:
670 g_error ("got type %x", type->type);
675 * interp_throw:
676 * Throw an exception from the interpreter.
678 static MONO_NEVER_INLINE void
679 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
681 ERROR_DECL (error);
682 MonoLMFExt ext;
684 interp_push_lmf (&ext, frame);
685 frame->ip = (const guint16*)ip;
686 frame->ex = ex;
688 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
689 MonoException *mono_ex = (MonoException *) ex;
690 if (!rethrow) {
691 mono_ex->stack_trace = NULL;
692 mono_ex->trace_ips = NULL;
695 mono_error_assert_ok (error);
697 MonoContext ctx;
698 memset (&ctx, 0, sizeof (MonoContext));
699 MONO_CONTEXT_SET_SP (&ctx, frame);
702 * Call the JIT EH code. The EH code will call back to us using:
703 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
704 * Since ctx.ip is 0, this will start unwinding from the LMF frame
705 * pushed above, which points to our frames.
707 mono_handle_exception (&ctx, (MonoObject*)ex);
708 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
709 /* We need to unwind into non-interpreter code */
710 mono_restore_context (&ctx);
711 g_assert_not_reached ();
714 interp_pop_lmf (&ext);
716 g_assert (context->has_resume_state);
719 static void
720 fill_in_trace (MonoException *exception, InterpFrame *frame)
722 ERROR_DECL (error);
723 char *stack_trace = dump_frame (frame);
724 MonoDomain *domain = frame->imethod->domain;
725 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, error);
726 mono_error_cleanup (error); /* FIXME: don't swallow the error */
727 (exception)->trace_ips = get_trace_ips (domain, frame);
728 g_free (stack_trace);
731 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
733 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
734 do { \
735 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
736 if (frame == context->handler_frame) \
737 SET_RESUME_STATE (context); \
738 else \
739 goto exit_frame; \
740 } while (0)
742 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
745 * Its possible for child_frame.ex to contain an unthrown exception, if the transform phase
746 * produced one.
748 #define CHECK_CHILD_EX(child_frame, ip) do { \
749 if ((child_frame).ex) \
750 THROW_EX ((child_frame).ex, (ip)); \
751 } while (0)
753 #define EXCEPTION_CHECKPOINT \
754 do { \
755 if (*mono_thread_interruption_request_flag ()) { \
756 MonoException *exc = mono_thread_interruption_checkpoint (); \
757 if (exc) \
758 THROW_EX (exc, ip); \
760 } while (0)
763 static MonoObject*
764 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
766 uintptr_t *lengths;
767 intptr_t *lower_bounds;
768 MonoObject *obj;
769 int i;
771 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
772 for (i = 0; i < param_count; ++i) {
773 lengths [i] = values->data.i;
774 values ++;
776 if (m_class_get_rank (klass) == param_count) {
777 /* Only lengths provided. */
778 lower_bounds = NULL;
779 } else {
780 /* lower bounds are first. */
781 lower_bounds = (intptr_t *) lengths;
782 lengths += m_class_get_rank (klass);
784 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
785 return obj;
788 static gint32
789 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
791 g_assert (!frame->ex);
792 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
794 guint32 pos = 0;
795 if (ao->bounds) {
796 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
797 guint32 idx = sp [i].data.i;
798 guint32 lower = ao->bounds [i].lower_bound;
799 guint32 len = ao->bounds [i].length;
800 if (safe && (idx < lower || (idx - lower) >= len)) {
801 frame->ex = mono_get_exception_index_out_of_range ();
802 FILL_IN_TRACE (frame->ex, frame);
803 return -1;
805 pos = (pos * len) + idx - lower;
807 } else {
808 pos = sp [0].data.i;
809 if (safe && pos >= ao->max_length) {
810 frame->ex = mono_get_exception_index_out_of_range ();
811 FILL_IN_TRACE (frame->ex, frame);
812 return -1;
815 return pos;
818 static void
819 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
821 MonoObject *o = sp->data.o;
822 MonoArray *ao = (MonoArray *) o;
823 MonoClass *ac = o->vtable->klass;
825 g_assert (m_class_get_rank (ac) >= 1);
827 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
828 if (frame->ex)
829 return;
831 int val_index = 1 + m_class_get_rank (ac);
832 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
833 ERROR_DECL (error);
834 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
835 mono_error_cleanup (error);
836 if (!isinst) {
837 frame->ex = mono_get_exception_array_type_mismatch ();
838 FILL_IN_TRACE (frame->ex, frame);
839 return;
843 gint32 esize = mono_array_element_size (ac);
844 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
846 MonoType *mt = sig->params [m_class_get_rank (ac)];
847 stackval_to_data (mt, &sp [val_index], ea, FALSE);
850 static void
851 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
853 MonoObject *o = sp->data.o;
854 MonoArray *ao = (MonoArray *) o;
855 MonoClass *ac = o->vtable->klass;
857 g_assert (m_class_get_rank (ac) >= 1);
859 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
860 if (frame->ex)
861 return;
863 gint32 esize = mono_array_element_size (ac);
864 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
866 MonoType *mt = sig->ret;
867 stackval_from_data (mt, retval, ea, FALSE);
870 static gpointer
871 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
873 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
875 g_assert (m_class_get_rank (ac) >= 1);
877 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
878 if (frame->ex)
879 return NULL;
881 if (needs_typecheck && !mono_class_is_assignable_from (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), m_class_get_element_class (required_type))) {
882 frame->ex = mono_get_exception_array_type_mismatch ();
883 FILL_IN_TRACE (frame->ex, frame);
884 return NULL;
886 gint32 esize = mono_array_element_size (ac);
887 return mono_array_addr_with_size_fast (ao, esize, pos);
890 static MonoPIFunc mono_interp_to_native_trampoline = NULL;
892 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
893 static MonoFuncV mono_native_to_interp_trampoline = NULL;
894 #endif
896 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
897 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
899 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
901 #ifdef TARGET_ARM
902 g_assert (mono_arm_eabi_supported ());
903 int i8_align = mono_arm_i8_align ();
904 #endif
906 #ifdef TARGET_WASM
907 margs->sig = sig;
908 #endif
910 if (sig->hasthis)
911 margs->ilen++;
913 for (int i = 0; i < sig->param_count; i++) {
914 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
915 switch (ptype) {
916 case MONO_TYPE_BOOLEAN:
917 case MONO_TYPE_CHAR:
918 case MONO_TYPE_I1:
919 case MONO_TYPE_U1:
920 case MONO_TYPE_I2:
921 case MONO_TYPE_U2:
922 case MONO_TYPE_I4:
923 case MONO_TYPE_U4:
924 case MONO_TYPE_I:
925 case MONO_TYPE_U:
926 case MONO_TYPE_PTR:
927 case MONO_TYPE_SZARRAY:
928 case MONO_TYPE_CLASS:
929 case MONO_TYPE_OBJECT:
930 case MONO_TYPE_STRING:
931 case MONO_TYPE_VALUETYPE:
932 case MONO_TYPE_GENERICINST:
933 #if SIZEOF_VOID_P == 8
934 case MONO_TYPE_I8:
935 case MONO_TYPE_U8:
936 #endif
937 margs->ilen++;
938 break;
939 #if SIZEOF_VOID_P == 4
940 case MONO_TYPE_I8:
941 case MONO_TYPE_U8:
942 #ifdef TARGET_ARM
943 /* pairs begin at even registers */
944 if (i8_align == 8 && margs->ilen & 1)
945 margs->ilen++;
946 #endif
947 margs->ilen += 2;
948 break;
949 #endif
950 case MONO_TYPE_R4:
951 #if SIZEOF_VOID_P == 8
952 case MONO_TYPE_R8:
953 #endif
954 margs->flen++;
955 break;
956 #if SIZEOF_VOID_P == 4
957 case MONO_TYPE_R8:
958 margs->flen += 2;
959 break;
960 #endif
961 default:
962 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
966 if (margs->ilen > 0)
967 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
969 if (margs->flen > 0)
970 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
972 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
973 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
975 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
976 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
979 size_t int_i = 0;
980 size_t int_f = 0;
982 if (sig->hasthis) {
983 margs->iargs [0] = frame->stack_args->data.p;
984 int_i++;
987 for (int i = 0; i < sig->param_count; i++) {
988 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
989 switch (ptype) {
990 case MONO_TYPE_BOOLEAN:
991 case MONO_TYPE_CHAR:
992 case MONO_TYPE_I1:
993 case MONO_TYPE_U1:
994 case MONO_TYPE_I2:
995 case MONO_TYPE_U2:
996 case MONO_TYPE_I4:
997 case MONO_TYPE_U4:
998 case MONO_TYPE_I:
999 case MONO_TYPE_U:
1000 case MONO_TYPE_PTR:
1001 case MONO_TYPE_SZARRAY:
1002 case MONO_TYPE_CLASS:
1003 case MONO_TYPE_OBJECT:
1004 case MONO_TYPE_STRING:
1005 case MONO_TYPE_VALUETYPE:
1006 case MONO_TYPE_GENERICINST:
1007 #if SIZEOF_VOID_P == 8
1008 case MONO_TYPE_I8:
1009 case MONO_TYPE_U8:
1010 #endif
1011 margs->iargs [int_i] = frame->stack_args [i].data.p;
1012 #if DEBUG_INTERP
1013 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1014 #endif
1015 int_i++;
1016 break;
1017 #if SIZEOF_VOID_P == 4
1018 case MONO_TYPE_I8:
1019 case MONO_TYPE_U8: {
1020 stackval *sarg = &frame->stack_args [i];
1021 #ifdef TARGET_ARM
1022 /* pairs begin at even registers */
1023 if (i8_align == 8 && int_i & 1)
1024 int_i++;
1025 #endif
1026 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1027 int_i++;
1028 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1029 #if DEBUG_INTERP
1030 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
1031 #endif
1032 int_i++;
1033 break;
1035 #endif
1036 case MONO_TYPE_R4:
1037 case MONO_TYPE_R8:
1038 if (ptype == MONO_TYPE_R4)
1039 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
1040 else
1041 margs->fargs [int_f] = frame->stack_args [i].data.f;
1042 #if DEBUG_INTERP
1043 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);
1044 #endif
1045 #if SIZEOF_VOID_P == 4
1046 int_f += 2;
1047 #else
1048 int_f++;
1049 #endif
1050 break;
1051 default:
1052 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1056 switch (sig->ret->type) {
1057 case MONO_TYPE_BOOLEAN:
1058 case MONO_TYPE_CHAR:
1059 case MONO_TYPE_I1:
1060 case MONO_TYPE_U1:
1061 case MONO_TYPE_I2:
1062 case MONO_TYPE_U2:
1063 case MONO_TYPE_I4:
1064 case MONO_TYPE_U4:
1065 case MONO_TYPE_I:
1066 case MONO_TYPE_U:
1067 case MONO_TYPE_PTR:
1068 case MONO_TYPE_SZARRAY:
1069 case MONO_TYPE_CLASS:
1070 case MONO_TYPE_OBJECT:
1071 case MONO_TYPE_STRING:
1072 case MONO_TYPE_I8:
1073 case MONO_TYPE_U8:
1074 case MONO_TYPE_VALUETYPE:
1075 case MONO_TYPE_GENERICINST:
1076 margs->retval = &(frame->retval->data.p);
1077 margs->is_float_ret = 0;
1078 break;
1079 case MONO_TYPE_R4:
1080 case MONO_TYPE_R8:
1081 margs->retval = &(frame->retval->data.p);
1082 margs->is_float_ret = 1;
1083 break;
1084 case MONO_TYPE_VOID:
1085 margs->retval = NULL;
1086 break;
1087 default:
1088 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1091 return margs;
1093 #endif
1095 static void
1096 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1098 InterpFrame *iframe = (InterpFrame*)frame;
1100 if (index == -1)
1101 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1102 else
1103 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1106 static void
1107 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1109 InterpFrame *iframe = (InterpFrame*)frame;
1111 if (index == -1)
1112 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1113 else if (sig->hasthis && index == 0)
1114 iframe->stack_args [index].data.p = *(gpointer*)data;
1115 else
1116 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1119 static gpointer
1120 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1122 InterpFrame *iframe = (InterpFrame*)frame;
1124 if (index == -1)
1125 return stackval_to_data_addr (sig->ret, iframe->retval);
1126 else
1127 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1130 static void
1131 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1133 InterpFrame *iframe = (InterpFrame*)frame;
1134 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1135 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1137 switch (type->type) {
1138 case MONO_TYPE_GENERICINST:
1139 if (!MONO_TYPE_IS_REFERENCE (type))
1140 val->data.vt = storage;
1141 break;
1142 case MONO_TYPE_VALUETYPE:
1143 val->data.vt = storage;
1144 break;
1145 default:
1146 g_assert_not_reached ();
1150 static MONO_NEVER_INLINE void
1151 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1153 MonoLMFExt ext;
1155 frame->ex = NULL;
1157 g_assert (!frame->imethod);
1158 if (!mono_interp_to_native_trampoline) {
1159 if (mono_ee_features.use_aot_trampolines) {
1160 mono_interp_to_native_trampoline = (MonoPIFunc)mono_aot_get_trampoline ("interp_to_native_trampoline");
1161 } else {
1162 MonoTrampInfo *info;
1163 mono_interp_to_native_trampoline = (MonoPIFunc)mono_arch_get_interp_to_native_trampoline (&info);
1164 // TODO:
1165 // mono_tramp_info_register (info, NULL);
1168 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1169 CallContext ccontext;
1170 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1171 #else
1172 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1173 #endif
1175 #if DEBUG_INTERP
1176 g_print ("ICALL: mono_interp_to_native_trampoline = %p, addr = %p\n", mono_interp_to_native_trampoline, addr);
1177 #endif
1179 context->current_frame = frame;
1181 interp_push_lmf (&ext, frame);
1182 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1183 mono_interp_to_native_trampoline (addr, &ccontext);
1184 #else
1185 mono_interp_to_native_trampoline (addr, margs);
1186 #endif
1187 interp_pop_lmf (&ext);
1189 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1190 if (!frame->ex)
1191 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1192 #else
1193 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1194 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1196 g_free (margs->iargs);
1197 g_free (margs->fargs);
1198 g_free (margs);
1199 #endif
1203 * interp_init_delegate:
1205 * Initialize del->interp_method.
1207 static void
1208 interp_init_delegate (MonoDelegate *del)
1210 MonoMethod *method;
1211 ERROR_DECL (error);
1213 if (del->interp_method) {
1214 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1215 del->method = ((InterpMethod *)del->interp_method)->method;
1216 } else if (del->method) {
1217 /* Delegate created dynamically */
1218 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1219 } else {
1220 /* Created from JITted code */
1221 g_assert (del->method_ptr);
1222 del->interp_method = lookup_method_pointer (del->method_ptr);
1223 g_assert (del->interp_method);
1226 method = ((InterpMethod*)del->interp_method)->method;
1227 if (del->target &&
1228 method &&
1229 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1230 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1231 mono_class_is_abstract (method->klass))
1232 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target);
1234 method = ((InterpMethod*)del->interp_method)->method;
1235 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1236 const char *name = method->name;
1237 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1239 * When invoking the delegate interp_method is executed directly. If it's an
1240 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1242 * FIXME We should do this later, when we also know the delegate on which the
1243 * target method is called.
1245 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1246 mono_error_assert_ok (error);
1251 static void
1252 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1255 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1257 InterpMethod *imethod = (InterpMethod*)addr;
1259 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1260 MonoMethod *invoke = mono_get_delegate_invoke (mono_handle_class (this_obj));
1261 /* virtual invoke delegates must not have null check */
1262 if (mono_method_signature (imethod->method)->param_count == mono_method_signature (invoke)->param_count
1263 && MONO_HANDLE_IS_NULL (target)) {
1264 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1265 return;
1269 g_assert (imethod->method);
1270 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1271 return_if_nok (error);
1273 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1275 mono_delegate_ctor (this_obj, target, entry, error);
1279 * From the spec:
1280 * runtime specifies that the implementation of the method is automatically
1281 * provided by the runtime and is primarily used for the methods of delegates.
1283 static MONO_NEVER_INLINE void
1284 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1286 const char *name = method->name;
1287 mono_class_init (method->klass);
1289 if (method->klass == mono_defaults.array_class) {
1290 if (!strcmp (name, "UnsafeMov")) {
1291 /* TODO: layout checks */
1292 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1293 return;
1295 if (!strcmp (name, "UnsafeLoad")) {
1296 ves_array_get (frame, sp, retval, sig, FALSE);
1297 return;
1299 } else if (mini_class_is_system_array (method->klass)) {
1300 MonoObject *obj = (MonoObject*) sp->data.p;
1301 if (!obj) {
1302 frame->ex = mono_get_exception_null_reference ();
1303 FILL_IN_TRACE (frame->ex, frame);
1304 return;
1306 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1307 ves_array_set (frame, sp, sig);
1308 return;
1310 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1311 ves_array_get (frame, sp, retval, sig, TRUE);
1312 return;
1316 g_error ("Don't know how to exec runtime method %s.%s::%s",
1317 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1318 method->name);
1321 #if DEBUG_INTERP
1322 static char*
1323 dump_stack (stackval *stack, stackval *sp)
1325 stackval *s = stack;
1326 GString *str = g_string_new ("");
1328 if (sp == stack)
1329 return g_string_free (str, FALSE);
1331 while (s < sp) {
1332 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1333 ++s;
1335 return g_string_free (str, FALSE);
1337 #endif
1339 static void
1340 dump_stackval (GString *str, stackval *s, MonoType *type)
1342 switch (type->type) {
1343 case MONO_TYPE_I1:
1344 case MONO_TYPE_U1:
1345 case MONO_TYPE_I2:
1346 case MONO_TYPE_U2:
1347 case MONO_TYPE_I4:
1348 case MONO_TYPE_U4:
1349 case MONO_TYPE_CHAR:
1350 case MONO_TYPE_BOOLEAN:
1351 g_string_append_printf (str, "[%d] ", s->data.i);
1352 break;
1353 case MONO_TYPE_STRING:
1354 case MONO_TYPE_SZARRAY:
1355 case MONO_TYPE_CLASS:
1356 case MONO_TYPE_OBJECT:
1357 case MONO_TYPE_ARRAY:
1358 case MONO_TYPE_PTR:
1359 case MONO_TYPE_I:
1360 case MONO_TYPE_U:
1361 g_string_append_printf (str, "[%p] ", s->data.p);
1362 break;
1363 case MONO_TYPE_VALUETYPE:
1364 if (m_class_is_enumtype (type->data.klass))
1365 g_string_append_printf (str, "[%d] ", s->data.i);
1366 else
1367 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1368 break;
1369 case MONO_TYPE_R4:
1370 case MONO_TYPE_R8:
1371 g_string_append_printf (str, "[%g] ", s->data.f);
1372 break;
1373 case MONO_TYPE_I8:
1374 case MONO_TYPE_U8:
1375 default: {
1376 GString *res = g_string_new ("");
1377 mono_type_get_desc (res, type, TRUE);
1378 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1379 g_string_free (res, TRUE);
1380 break;
1385 #if DEBUG_INTERP
1386 static char*
1387 dump_retval (InterpFrame *inv)
1389 GString *str = g_string_new ("");
1390 MonoType *ret = mono_method_signature (inv->imethod->method)->ret;
1392 if (ret->type != MONO_TYPE_VOID)
1393 dump_stackval (str, inv->retval, ret);
1395 return g_string_free (str, FALSE);
1397 #endif
1399 static char*
1400 dump_args (InterpFrame *inv)
1402 GString *str = g_string_new ("");
1403 int i;
1404 MonoMethodSignature *signature = mono_method_signature (inv->imethod->method);
1406 if (signature->param_count == 0 && !signature->hasthis)
1407 return g_string_free (str, FALSE);
1409 if (signature->hasthis) {
1410 MonoMethod *method = inv->imethod->method;
1411 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1414 for (i = 0; i < signature->param_count; ++i)
1415 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1417 return g_string_free (str, FALSE);
1420 static char*
1421 dump_frame (InterpFrame *inv)
1423 GString *str = g_string_new ("");
1424 int i;
1425 char *args;
1426 ERROR_DECL (error);
1428 for (i = 0; inv; inv = inv->parent) {
1429 if (inv->imethod != NULL) {
1430 MonoMethod *method = inv->imethod->method;
1431 MonoClass *k;
1433 int codep = 0;
1434 const char * opname = "";
1435 char *name;
1436 gchar *source = NULL;
1438 k = method->klass;
1440 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1441 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1442 MonoMethodHeader *hd = mono_method_get_header_checked (method, error);
1443 mono_error_cleanup (error); /* FIXME: don't swallow the error */
1445 if (hd != NULL) {
1446 if (inv->ip) {
1447 opname = mono_interp_opname [*inv->ip];
1448 codep = inv->ip - inv->imethod->code;
1449 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1450 } else
1451 opname = "";
1453 #if 0
1454 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1455 source = mono_debug_method_lookup_location (minfo, codep);
1456 #endif
1457 mono_metadata_free_mh (hd);
1460 args = dump_args (inv);
1461 name = mono_method_full_name (method, TRUE);
1462 if (source)
1463 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1464 else
1465 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1466 g_free (name);
1467 g_free (args);
1468 g_free (source);
1469 ++i;
1472 return g_string_free (str, FALSE);
1475 static MonoArray *
1476 get_trace_ips (MonoDomain *domain, InterpFrame *top)
1478 int i;
1479 MonoArray *res;
1480 InterpFrame *inv;
1481 ERROR_DECL (error);
1483 for (i = 0, inv = top; inv; inv = inv->parent)
1484 if (inv->imethod != NULL)
1485 ++i;
1487 res = mono_array_new_checked (domain, mono_defaults.int_class, 3 * i, error);
1488 mono_error_cleanup (error); /* FIXME: don't swallow the error */
1490 for (i = 0, inv = top; inv; inv = inv->parent)
1491 if (inv->imethod != NULL) {
1492 mono_array_set_fast (res, gpointer, i, inv->imethod);
1493 ++i;
1494 mono_array_set_fast (res, gpointer, i, (gpointer)inv->ip);
1495 ++i;
1496 mono_array_set_fast (res, gpointer, i, NULL);
1497 ++i;
1500 return res;
1503 #define CHECK_ADD_OVERFLOW(a,b) \
1504 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1505 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1507 #define CHECK_SUB_OVERFLOW(a,b) \
1508 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1509 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1511 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1512 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1514 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1515 (guint32)(a) < (guint32)(b) ? -1 : 0
1517 #define CHECK_ADD_OVERFLOW64(a,b) \
1518 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1519 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1521 #define CHECK_SUB_OVERFLOW64(a,b) \
1522 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1523 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1525 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1526 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1528 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1529 (guint64)(a) < (guint64)(b) ? -1 : 0
1531 #if SIZEOF_VOID_P == 4
1532 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1533 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1534 #else
1535 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1536 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1537 #endif
1539 /* Resolves to TRUE if the operands would overflow */
1540 #define CHECK_MUL_OVERFLOW(a,b) \
1541 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1542 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1543 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1544 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1545 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1546 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1547 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1549 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1550 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1551 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1553 #define CHECK_MUL_OVERFLOW64(a,b) \
1554 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1555 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1556 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1557 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1558 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1559 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1560 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1562 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1563 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1564 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1566 #if SIZEOF_VOID_P == 4
1567 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1568 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1569 #else
1570 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1571 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1572 #endif
1574 static MonoObject*
1575 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1577 InterpFrame frame, *old_frame;
1578 ThreadContext *context = (ThreadContext*)mono_native_tls_get_value (thread_context_id);
1579 MonoMethodSignature *sig = mono_method_signature (method);
1580 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1581 stackval result;
1582 MonoMethod *target_method = method;
1584 error_init (error);
1585 if (exc)
1586 *exc = NULL;
1588 frame.ex = NULL;
1590 if (context == NULL) {
1591 context = g_new0 (ThreadContext, 1);
1592 set_context (context);
1594 old_frame = context->current_frame;
1596 MonoDomain *domain = mono_domain_get ();
1598 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1599 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1600 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1602 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1604 result.data.vt = alloca (mono_class_instance_size (klass));
1605 stackval args [4];
1607 if (sig->hasthis)
1608 args [0].data.p = obj;
1609 else
1610 args [0].data.p = NULL;
1611 args [1].data.p = params;
1612 args [2].data.p = exc;
1613 args [3].data.p = target_method;
1615 INIT_FRAME (&frame, NULL, args, &result, domain, invoke_wrapper, error);
1617 if (exc)
1618 frame.invoke_trap = 1;
1620 interp_exec_method (&frame, context);
1622 context->current_frame = old_frame;
1624 if (frame.ex) {
1625 if (exc) {
1626 *exc = (MonoObject*) frame.ex;
1627 return NULL;
1629 mono_error_set_exception_instance (error, frame.ex);
1630 return NULL;
1632 return (MonoObject*)result.data.p;
1635 typedef struct {
1636 InterpMethod *rmethod;
1637 gpointer this_arg;
1638 gpointer res;
1639 gpointer args [16];
1640 gpointer *many_args;
1641 } InterpEntryData;
1643 /* Main function for entering the interpreter from compiled code */
1644 static void
1645 interp_entry (InterpEntryData *data)
1647 InterpFrame frame;
1648 InterpMethod *rmethod = data->rmethod;
1649 ThreadContext *context = (ThreadContext*)mono_native_tls_get_value (thread_context_id);
1650 InterpFrame *old_frame;
1651 stackval result;
1652 stackval *args;
1653 MonoMethod *method;
1654 MonoMethodSignature *sig;
1655 MonoType *type;
1656 int i;
1658 method = rmethod->method;
1659 sig = mono_method_signature (method);
1661 // FIXME: Optimize this
1663 //printf ("%s\n", mono_method_full_name (method, 1));
1665 frame.ex = NULL;
1666 if (context == NULL) {
1667 context = g_new0 (ThreadContext, 1);
1668 set_context (context);
1670 old_frame = context->current_frame;
1672 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1673 if (sig->hasthis)
1674 args [0].data.p = data->this_arg;
1676 gpointer *params;
1677 if (data->many_args)
1678 params = data->many_args;
1679 else
1680 params = data->args;
1681 for (i = 0; i < sig->param_count; ++i) {
1682 int a_index = i + (sig->hasthis ? 1 : 0);
1683 if (sig->params [i]->byref) {
1684 args [a_index].data.p = params [i];
1685 continue;
1687 type = rmethod->param_types [i];
1688 switch (type->type) {
1689 case MONO_TYPE_VALUETYPE:
1690 args [a_index].data.p = params [i];
1691 break;
1692 case MONO_TYPE_GENERICINST:
1693 if (MONO_TYPE_IS_REFERENCE (type))
1694 args [a_index].data.p = *(gpointer*)params [i];
1695 else
1696 args [a_index].data.vt = params [i];
1697 break;
1698 default:
1699 stackval_from_data (type, &args [a_index], params [i], FALSE);
1700 break;
1704 memset (&result, 0, sizeof (result));
1705 init_frame (&frame, NULL, data->rmethod, args, &result);
1707 type = rmethod->rtype;
1708 switch (type->type) {
1709 case MONO_TYPE_GENERICINST:
1710 if (!MONO_TYPE_IS_REFERENCE (type))
1711 frame.retval->data.vt = data->res;
1712 break;
1713 case MONO_TYPE_VALUETYPE:
1714 frame.retval->data.vt = data->res;
1715 break;
1716 default:
1717 break;
1720 interp_exec_method (&frame, context);
1721 context->current_frame = old_frame;
1723 // FIXME:
1724 g_assert (frame.ex == NULL);
1726 type = rmethod->rtype;
1727 switch (type->type) {
1728 case MONO_TYPE_VOID:
1729 break;
1730 case MONO_TYPE_OBJECT:
1731 /* No need for a write barrier */
1732 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1733 break;
1734 case MONO_TYPE_GENERICINST:
1735 if (MONO_TYPE_IS_REFERENCE (type)) {
1736 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1737 } else {
1738 /* Already set before the call */
1740 break;
1741 case MONO_TYPE_VALUETYPE:
1742 /* Already set before the call */
1743 break;
1744 default:
1745 stackval_to_data (type, frame.retval, data->res, FALSE);
1746 break;
1750 static MONO_NEVER_INLINE stackval *
1751 do_icall (ThreadContext *context, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr)
1753 MonoLMFExt ext;
1754 interp_push_lmf (&ext, context->current_frame);
1756 switch (op) {
1757 case MINT_ICALL_V_V: {
1758 typedef void (*T)(void);
1759 T func = (T)ptr;
1760 func ();
1761 break;
1763 case MINT_ICALL_V_P: {
1764 typedef gpointer (*T)(void);
1765 T func = (T)ptr;
1766 sp++;
1767 sp [-1].data.p = func ();
1768 break;
1770 case MINT_ICALL_P_V: {
1771 typedef void (*T)(gpointer);
1772 T func = (T)ptr;
1773 func (sp [-1].data.p);
1774 sp --;
1775 break;
1777 case MINT_ICALL_P_P: {
1778 typedef gpointer (*T)(gpointer);
1779 T func = (T)ptr;
1780 sp [-1].data.p = func (sp [-1].data.p);
1781 break;
1783 case MINT_ICALL_PP_V: {
1784 typedef void (*T)(gpointer,gpointer);
1785 T func = (T)ptr;
1786 sp -= 2;
1787 func (sp [0].data.p, sp [1].data.p);
1788 break;
1790 case MINT_ICALL_PP_P: {
1791 typedef gpointer (*T)(gpointer,gpointer);
1792 T func = (T)ptr;
1793 --sp;
1794 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1795 break;
1797 case MINT_ICALL_PPP_V: {
1798 typedef void (*T)(gpointer,gpointer,gpointer);
1799 T func = (T)ptr;
1800 sp -= 3;
1801 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1802 break;
1804 case MINT_ICALL_PPP_P: {
1805 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1806 T func = (T)ptr;
1807 sp -= 2;
1808 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1809 break;
1811 case MINT_ICALL_PPPP_V: {
1812 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1813 T func = (T)ptr;
1814 sp -= 4;
1815 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1816 break;
1818 case MINT_ICALL_PPPP_P: {
1819 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1820 T func = (T)ptr;
1821 sp -= 3;
1822 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1823 break;
1825 case MINT_ICALL_PPPPP_V: {
1826 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1827 T func = (T)ptr;
1828 sp -= 5;
1829 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1830 break;
1832 case MINT_ICALL_PPPPP_P: {
1833 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1834 T func = (T)ptr;
1835 sp -= 4;
1836 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1837 break;
1839 case MINT_ICALL_PPPPPP_V: {
1840 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1841 T func = (T)ptr;
1842 sp -= 6;
1843 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p, sp [5].data.p);
1844 break;
1846 case MINT_ICALL_PPPPPP_P: {
1847 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1848 T func = (T)ptr;
1849 sp -= 5;
1850 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1851 break;
1853 default:
1854 g_assert_not_reached ();
1857 /* convert the native representation to the stackval representation */
1858 if (sig)
1859 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
1861 interp_pop_lmf (&ext);
1862 return sp;
1865 static MONO_NEVER_INLINE stackval *
1866 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
1868 MonoMethodSignature *sig;
1869 MonoFtnDesc ftndesc;
1870 guint8 res_buf [256];
1871 MonoType *type;
1872 MonoLMFExt ext;
1874 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
1877 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1878 * by ref and return a return value using an explicit return value argument.
1880 if (!rmethod->jit_wrapper) {
1881 MonoMethod *method = rmethod->method;
1883 sig = mono_method_signature (method);
1884 g_assert (sig);
1886 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
1887 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1889 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
1890 mono_error_assert_ok (error);
1892 gpointer addr = mono_jit_compile_method_jit_only (method, error);
1893 return_val_if_nok (error, NULL);
1894 g_assert (addr);
1896 rmethod->jit_addr = addr;
1897 rmethod->jit_sig = sig;
1898 mono_memory_barrier ();
1899 rmethod->jit_wrapper = jit_wrapper;
1901 } else {
1902 sig = rmethod->jit_sig;
1905 sp -= sig->param_count;
1906 if (sig->hasthis)
1907 --sp;
1909 ftndesc.addr = rmethod->jit_addr;
1910 ftndesc.arg = NULL;
1912 // FIXME: Optimize this
1914 gpointer args [32];
1915 int pindex = 0;
1916 int stack_index = 0;
1917 if (rmethod->hasthis) {
1918 args [pindex ++] = sp [0].data.p;
1919 stack_index ++;
1921 type = rmethod->rtype;
1922 if (type->type != MONO_TYPE_VOID) {
1923 if (MONO_TYPE_ISSTRUCT (type))
1924 args [pindex ++] = vt_sp;
1925 else
1926 args [pindex ++] = res_buf;
1928 for (int i = 0; i < rmethod->param_count; ++i) {
1929 MonoType *t = rmethod->param_types [i];
1930 stackval *sval = &sp [stack_index + i];
1931 if (sig->params [i]->byref) {
1932 args [pindex ++] = sval->data.p;
1933 } else if (MONO_TYPE_ISSTRUCT (t)) {
1934 args [pindex ++] = sval->data.p;
1935 } else if (MONO_TYPE_IS_REFERENCE (t)) {
1936 args [pindex ++] = &sval->data.p;
1937 } else {
1938 switch (t->type) {
1939 case MONO_TYPE_I1:
1940 case MONO_TYPE_U1:
1941 case MONO_TYPE_I2:
1942 case MONO_TYPE_U2:
1943 case MONO_TYPE_I4:
1944 case MONO_TYPE_U4:
1945 case MONO_TYPE_VALUETYPE:
1946 args [pindex ++] = &sval->data.i;
1947 break;
1948 case MONO_TYPE_PTR:
1949 case MONO_TYPE_FNPTR:
1950 case MONO_TYPE_I:
1951 case MONO_TYPE_U:
1952 case MONO_TYPE_OBJECT:
1953 args [pindex ++] = &sval->data.p;
1954 break;
1955 case MONO_TYPE_I8:
1956 case MONO_TYPE_U8:
1957 args [pindex ++] = &sval->data.l;
1958 break;
1959 case MONO_TYPE_R4: {
1960 float tmp = (float)sval->data.f;
1961 sval->data.i = *(int*)&tmp;
1962 args [pindex ++] = &sval->data.i;
1963 break;
1965 case MONO_TYPE_R8:
1966 args [pindex ++] = &sval->data.f;
1967 break;
1968 default:
1969 printf ("%s\n", mono_type_full_name (t));
1970 g_assert_not_reached ();
1975 interp_push_lmf (&ext, frame);
1977 switch (pindex) {
1978 case 0: {
1979 typedef void (*T)(gpointer);
1980 T func = (T)rmethod->jit_wrapper;
1982 func (&ftndesc);
1983 break;
1985 case 1: {
1986 typedef void (*T)(gpointer, gpointer);
1987 T func = (T)rmethod->jit_wrapper;
1989 func (args [0], &ftndesc);
1990 break;
1992 case 2: {
1993 typedef void (*T)(gpointer, gpointer, gpointer);
1994 T func = (T)rmethod->jit_wrapper;
1996 func (args [0], args [1], &ftndesc);
1997 break;
1999 case 3: {
2000 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2001 T func = (T)rmethod->jit_wrapper;
2003 func (args [0], args [1], args [2], &ftndesc);
2004 break;
2006 case 4: {
2007 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2008 T func = (T)rmethod->jit_wrapper;
2010 func (args [0], args [1], args [2], args [3], &ftndesc);
2011 break;
2013 case 5: {
2014 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2015 T func = (T)rmethod->jit_wrapper;
2017 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2018 break;
2020 case 6: {
2021 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2022 T func = (T)rmethod->jit_wrapper;
2024 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2025 break;
2027 case 7: {
2028 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2029 T func = (T)rmethod->jit_wrapper;
2031 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2032 break;
2034 case 8: {
2035 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2036 T func = (T)rmethod->jit_wrapper;
2038 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2039 break;
2041 default:
2042 g_assert_not_reached ();
2043 break;
2046 interp_pop_lmf (&ext);
2048 MonoType *rtype = rmethod->rtype;
2049 switch (rtype->type) {
2050 case MONO_TYPE_VOID:
2051 case MONO_TYPE_OBJECT:
2052 case MONO_TYPE_STRING:
2053 case MONO_TYPE_CLASS:
2054 case MONO_TYPE_ARRAY:
2055 case MONO_TYPE_SZARRAY:
2056 case MONO_TYPE_I:
2057 case MONO_TYPE_U:
2058 case MONO_TYPE_PTR:
2059 sp->data.p = *(gpointer*)res_buf;
2060 break;
2061 case MONO_TYPE_I1:
2062 sp->data.i = *(gint8*)res_buf;
2063 break;
2064 case MONO_TYPE_U1:
2065 sp->data.i = *(guint8*)res_buf;
2066 break;
2067 case MONO_TYPE_I2:
2068 sp->data.i = *(gint16*)res_buf;
2069 break;
2070 case MONO_TYPE_U2:
2071 sp->data.i = *(guint16*)res_buf;
2072 break;
2073 case MONO_TYPE_I4:
2074 sp->data.i = *(gint32*)res_buf;
2075 break;
2076 case MONO_TYPE_U4:
2077 sp->data.i = *(guint32*)res_buf;
2078 break;
2079 case MONO_TYPE_I8:
2080 sp->data.l = *(gint64*)res_buf;
2081 break;
2082 case MONO_TYPE_U8:
2083 sp->data.l = *(guint64*)res_buf;
2084 break;
2085 case MONO_TYPE_R4:
2086 sp->data.f = *(float*)res_buf;
2087 break;
2088 case MONO_TYPE_R8:
2089 sp->data.f = *(double*)res_buf;
2090 break;
2091 case MONO_TYPE_VALUETYPE:
2092 /* The result was written to vt_sp */
2093 sp->data.p = vt_sp;
2094 break;
2095 case MONO_TYPE_GENERICINST:
2096 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2097 sp->data.p = *(gpointer*)res_buf;
2098 } else {
2099 /* The result was written to vt_sp */
2100 sp->data.p = vt_sp;
2102 break;
2103 default:
2104 g_print ("%s\n", mono_type_full_name (rtype));
2105 g_assert_not_reached ();
2106 break;
2109 return sp;
2112 static MONO_NEVER_INLINE void
2113 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2115 MonoLMFExt ext;
2116 interp_push_lmf (&ext, frame);
2117 tramp ();
2118 interp_pop_lmf (&ext);
2121 static MONO_NEVER_INLINE void
2122 do_transform_method (InterpFrame *frame, ThreadContext *context)
2124 MonoLMFExt ext;
2125 /* Don't push lmf if we have no interp data */
2126 gboolean push_lmf = frame->parent != NULL;
2127 ERROR_DECL (error);
2129 /* Use the parent frame as the current frame is not complete yet */
2130 if (push_lmf)
2131 interp_push_lmf (&ext, frame->parent);
2133 mono_interp_transform_method (frame->imethod, context, error);
2134 frame->ex = mono_error_convert_to_exception (error);
2136 if (push_lmf)
2137 interp_pop_lmf (&ext);
2140 static void
2141 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, unsigned char **vt_sp)
2143 char *vt = *(char**)vt_sp;
2144 stackval *first_arg = sp - csig->param_count;
2147 * We need to have the varargs linearly on the stack so the ArgIterator
2148 * can iterate over them. We pass the signature first and then copy them
2149 * one by one on the vtstack.
2151 *(gpointer*)vt = csig;
2152 vt += sizeof (gpointer);
2154 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2155 int align, arg_size;
2156 arg_size = mono_type_stack_size (csig->params [i], &align);
2157 vt = (char*)ALIGN_PTR_TO (vt, align);
2159 stackval_to_data (csig->params [i], &first_arg [i], vt, FALSE);
2160 vt += arg_size;
2163 vt = (char*)ALIGN_PTR_TO (vt, MINT_VT_ALIGNMENT);
2165 *(char**)vt_sp = vt;
2169 * These functions are the entry points into the interpreter from compiled code.
2170 * They are called by the interp_in wrappers. They have the following signature:
2171 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2172 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2173 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2174 * more wrappers then these functions.
2175 * this/static * ret/void * 16 arguments -> 64 functions.
2178 #define MAX_INTERP_ENTRY_ARGS 8
2180 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2181 InterpEntryData data; \
2182 (data).rmethod = (_method); \
2183 (data).res = (_res); \
2184 (data).this_arg = (_this_arg); \
2185 (data).many_args = NULL;
2187 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2188 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2189 interp_entry (&data); \
2191 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2192 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2193 (data).args [0] = arg1; \
2194 interp_entry (&data); \
2196 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2197 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2198 (data).args [0] = arg1; \
2199 (data).args [1] = arg2; \
2200 interp_entry (&data); \
2202 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2203 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2204 (data).args [0] = arg1; \
2205 (data).args [1] = arg2; \
2206 (data).args [2] = arg3; \
2207 interp_entry (&data); \
2209 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2210 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2211 (data).args [0] = arg1; \
2212 (data).args [1] = arg2; \
2213 (data).args [2] = arg3; \
2214 (data).args [3] = arg4; \
2215 interp_entry (&data); \
2217 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2218 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2219 (data).args [0] = arg1; \
2220 (data).args [1] = arg2; \
2221 (data).args [2] = arg3; \
2222 (data).args [3] = arg4; \
2223 (data).args [4] = arg5; \
2224 interp_entry (&data); \
2226 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2227 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2228 (data).args [0] = arg1; \
2229 (data).args [1] = arg2; \
2230 (data).args [2] = arg3; \
2231 (data).args [3] = arg4; \
2232 (data).args [4] = arg5; \
2233 (data).args [5] = arg6; \
2234 interp_entry (&data); \
2236 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2237 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2238 (data).args [0] = arg1; \
2239 (data).args [1] = arg2; \
2240 (data).args [2] = arg3; \
2241 (data).args [3] = arg4; \
2242 (data).args [4] = arg5; \
2243 (data).args [5] = arg6; \
2244 (data).args [6] = arg7; \
2245 interp_entry (&data); \
2247 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2248 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2249 (data).args [0] = arg1; \
2250 (data).args [1] = arg2; \
2251 (data).args [2] = arg3; \
2252 (data).args [3] = arg4; \
2253 (data).args [4] = arg5; \
2254 (data).args [5] = arg6; \
2255 (data).args [6] = arg7; \
2256 (data).args [7] = arg8; \
2257 interp_entry (&data); \
2260 #define ARGLIST0 InterpMethod *rmethod
2261 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2262 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2263 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2264 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2265 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2266 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2267 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2268 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2270 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2271 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2272 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2273 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2274 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2275 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2276 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2277 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2278 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2279 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2280 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2281 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2282 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2283 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2284 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2285 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2286 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2287 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2288 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2289 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2290 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2291 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2292 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2293 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2294 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2295 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2296 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2297 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2298 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2299 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2300 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2301 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2302 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2303 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2304 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2305 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2307 #define INTERP_ENTRY_FUNCLIST(type) (gpointer)interp_entry_ ## type ## _0, (gpointer)interp_entry_ ## type ## _1, (gpointer)interp_entry_ ## type ## _2, (gpointer)interp_entry_ ## type ## _3, (gpointer)interp_entry_ ## type ## _4, (gpointer)interp_entry_ ## type ## _5, (gpointer)interp_entry_ ## type ## _6, (gpointer)interp_entry_ ## type ## _7, (gpointer)interp_entry_ ## type ## _8
2309 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2310 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2311 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2312 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2314 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2315 static void
2316 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2318 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2319 data.many_args = args;
2320 interp_entry (&data);
2323 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2325 // inline so we can alloc on stack
2326 #define alloc_storage_for_stackval(s, t, p) do { \
2327 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2328 (s)->data.vt = alloca (mono_class_value_size ((t)->data.generic_class->container_class, NULL)); \
2329 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2330 if (p) \
2331 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2332 else \
2333 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2335 } while (0)
2337 static void
2338 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2340 InterpFrame frame;
2341 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
2342 InterpFrame *old_frame;
2343 stackval result;
2344 stackval *args;
2345 MonoMethod *method;
2346 MonoMethodSignature *sig;
2347 CallContext *ccontext = (CallContext*) ccontext_untyped;
2348 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2349 int i;
2351 method = rmethod->method;
2352 sig = mono_method_signature (method);
2354 frame.ex = NULL;
2355 if (context == NULL) {
2356 context = g_new0 (ThreadContext, 1);
2357 set_context (context);
2359 old_frame = context->current_frame;
2361 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2363 init_frame (&frame, NULL, rmethod, args, &result);
2365 /* Allocate storage for value types */
2366 for (i = 0; i < sig->param_count; i++) {
2367 MonoType *type = sig->params [i];
2368 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2371 if (sig->ret->type != MONO_TYPE_VOID)
2372 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2374 /* Copy the args saved in the trampoline to the frame stack */
2375 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2377 interp_exec_method (&frame, context);
2378 context->current_frame = old_frame;
2380 // FIXME:
2381 g_assert (frame.ex == NULL);
2383 /* Write back the return value */
2384 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2386 #endif
2388 static InterpMethod*
2389 lookup_method_pointer (gpointer addr)
2391 MonoDomain *domain = mono_domain_get ();
2392 MonoJitDomainInfo *info = domain_jit_info (domain);
2393 InterpMethod *res = NULL;
2395 mono_domain_lock (domain);
2396 if (info->interp_method_pointer_hash)
2397 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2398 mono_domain_unlock (domain);
2400 return res;
2403 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2404 static void
2405 interp_no_native_to_managed (void)
2407 g_error ("interpreter: native-to-managed transition not available on this platform");
2409 #endif
2412 * interp_create_method_pointer:
2414 * Return a function pointer which can be used to call METHOD using the
2415 * interpreter. Return NULL for methods which are not supported.
2417 static gpointer
2418 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2420 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2421 return interp_no_native_to_managed;
2422 #else
2423 gpointer addr, entry_func, entry_wrapper;
2424 MonoDomain *domain = mono_domain_get ();
2425 MonoJitDomainInfo *info;
2426 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2428 if (compile) {
2429 /* Return any errors from method compilation */
2430 mono_interp_transform_method (imethod, (ThreadContext*)mono_native_tls_get_value (thread_context_id), error);
2431 return_val_if_nok (error, NULL);
2434 /* HACK: method_ptr of delegate should point to a runtime method*/
2435 if (method->wrapper_type && (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
2436 (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)))
2437 return imethod;
2439 if (imethod->jit_entry)
2440 return imethod->jit_entry;
2442 MonoMethodSignature *sig = mono_method_signature (method);
2443 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2444 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2446 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2447 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2448 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2449 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2451 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2452 entry_func = (gpointer)interp_entry_general;
2453 } else if (sig->hasthis) {
2454 if (sig->ret->type == MONO_TYPE_VOID)
2455 entry_func = entry_funcs_instance [sig->param_count];
2456 else
2457 entry_func = entry_funcs_instance_ret [sig->param_count];
2458 } else {
2459 if (sig->ret->type == MONO_TYPE_VOID)
2460 entry_func = entry_funcs_static [sig->param_count];
2461 else
2462 entry_func = entry_funcs_static_ret [sig->param_count];
2464 g_assert (entry_func);
2465 #else
2466 if (!mono_native_to_interp_trampoline) {
2467 if (mono_aot_only) {
2468 mono_native_to_interp_trampoline = mono_aot_get_trampoline ("native_to_interp_trampoline");
2469 } else {
2470 MonoTrampInfo *info;
2471 mono_native_to_interp_trampoline = mono_arch_get_native_to_interp_trampoline (&info);
2472 mono_tramp_info_register (info, NULL);
2475 entry_wrapper = mono_native_to_interp_trampoline;
2476 /* We need the lmf wrapper only when being called from mixed mode */
2477 if (sig->pinvoke)
2478 entry_func = interp_entry_from_trampoline;
2479 else
2480 entry_func = mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper (), error);
2481 #endif
2482 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2483 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2484 ftndesc->addr = entry_func;
2485 ftndesc->arg = imethod;
2486 mono_error_assert_ok (error);
2489 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2490 * rgctx register using a trampoline.
2493 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2495 info = domain_jit_info (domain);
2496 mono_domain_lock (domain);
2497 if (!info->interp_method_pointer_hash)
2498 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2499 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2500 mono_domain_unlock (domain);
2502 mono_memory_barrier ();
2503 imethod->jit_entry = addr;
2505 return addr;
2506 #endif
2509 #if COUNT_OPS
2510 static int opcode_counts[512];
2512 #define COUNT_OP(op) opcode_counts[op]++
2513 #else
2514 #define COUNT_OP(op)
2515 #endif
2517 #if DEBUG_INTERP
2518 #define DUMP_INSTR() \
2519 if (tracing > 1) { \
2520 char *ins; \
2521 if (sp > frame->stack) { \
2522 ins = dump_stack (frame->stack, sp); \
2523 } else { \
2524 ins = g_strdup (""); \
2526 sp->data.l = 0; \
2527 output_indent (); \
2528 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2529 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2530 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2531 g_free (mn); \
2532 g_free (ins); \
2533 g_free (disasm); \
2535 #else
2536 #define DUMP_INSTR()
2537 #endif
2539 #ifdef __GNUC__
2540 #define USE_COMPUTED_GOTO 1
2541 #endif
2542 #if USE_COMPUTED_GOTO
2543 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2544 #define MINT_IN_CASE(x) LAB_ ## x:
2545 #if DEBUG_INTERP
2546 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2547 #else
2548 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2549 #endif
2550 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2551 #else
2552 #define MINT_IN_SWITCH(op) switch (op)
2553 #define MINT_IN_CASE(x) case x:
2554 #define MINT_IN_BREAK break
2555 #define MINT_IN_DEFAULT default:
2556 #endif
2559 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2560 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2562 static void
2563 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame)
2565 InterpFrame child_frame;
2566 GSList *finally_ips = NULL;
2567 const unsigned short *endfinally_ip = NULL;
2568 const unsigned short *ip = NULL;
2569 register stackval *sp;
2570 InterpMethod *rtm = NULL;
2571 #if DEBUG_INTERP
2572 gint tracing = global_tracing;
2573 unsigned char *vtalloc;
2574 #else
2575 gint tracing = 0;
2576 #endif
2577 int i32;
2578 unsigned char *vt_sp;
2579 unsigned char *locals;
2580 ERROR_DECL (error);
2581 MonoObject *o = NULL;
2582 MonoClass *c;
2583 #if USE_COMPUTED_GOTO
2584 static void *in_labels[] = {
2585 #define OPDEF(a,b,c,d) \
2586 &&LAB_ ## a,
2587 #include "mintops.def"
2588 0 };
2589 #endif
2592 frame->ex = NULL;
2593 frame->ex_handler = NULL;
2594 frame->ip = NULL;
2595 frame->domain = mono_domain_get ();
2596 context->current_frame = frame;
2598 debug_enter (frame, &tracing);
2600 rtm = frame->imethod;
2601 if (!frame->imethod->transformed) {
2602 #if DEBUG_INTERP
2603 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
2604 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2605 g_free (mn);
2606 #endif
2608 do_transform_method (frame, context);
2609 if (frame->ex)
2610 THROW_EX (frame->ex, NULL);
2611 if (*mono_thread_interruption_request_flag ()) {
2612 MonoException *exc = mono_thread_interruption_checkpoint ();
2613 if (exc)
2614 THROW_EX (exc, NULL);
2619 if (!start_with_ip) {
2620 frame->args = g_newa (char, rtm->alloca_size);
2621 memset (frame->args, 0, rtm->alloca_size);
2623 ip = rtm->code;
2624 } else {
2625 ip = start_with_ip;
2626 if (base_frame) {
2627 frame->args = g_newa (char, rtm->alloca_size);
2628 memcpy (frame->args, base_frame->args, rtm->alloca_size);
2631 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2632 vt_sp = (unsigned char *) sp + rtm->stack_size;
2633 #if DEBUG_INTERP
2634 vtalloc = vt_sp;
2635 #endif
2636 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2637 frame->locals = locals;
2638 child_frame.parent = frame;
2640 if (filter_exception) {
2641 sp->data.p = filter_exception;
2642 sp++;
2646 * using while (ip < end) may result in a 15% performance drop,
2647 * but it may be useful for debug
2649 while (1) {
2650 main_loop:
2651 /* g_assert (sp >= frame->stack); */
2652 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2653 DUMP_INSTR();
2654 MINT_IN_SWITCH (*ip) {
2655 MINT_IN_CASE(MINT_INITLOCALS)
2656 memset (locals, 0, rtm->locals_size);
2657 ++ip;
2658 MINT_IN_BREAK;
2659 MINT_IN_CASE(MINT_NOP)
2660 ++ip;
2661 MINT_IN_BREAK;
2662 MINT_IN_CASE(MINT_NIY)
2663 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2664 MINT_IN_BREAK;
2665 MINT_IN_CASE(MINT_BREAK)
2666 ++ip;
2667 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
2668 MINT_IN_BREAK;
2669 MINT_IN_CASE(MINT_LDNULL)
2670 sp->data.p = NULL;
2671 ++ip;
2672 ++sp;
2673 MINT_IN_BREAK;
2674 MINT_IN_CASE(MINT_ARGLIST)
2675 g_assert (frame->varargs);
2676 sp->data.p = vt_sp;
2677 *(gpointer*)sp->data.p = frame->varargs;
2678 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
2679 ++ip;
2680 ++sp;
2681 MINT_IN_BREAK;
2682 MINT_IN_CASE(MINT_VTRESULT) {
2683 int ret_size = * (guint16 *)(ip + 1);
2684 unsigned char *ret_vt_sp = vt_sp;
2685 vt_sp -= READ32(ip + 2);
2686 if (ret_size > 0) {
2687 memmove (vt_sp, ret_vt_sp, ret_size);
2688 sp [-1].data.p = vt_sp;
2689 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
2691 ip += 4;
2692 MINT_IN_BREAK;
2694 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2695 MINT_IN_CASE(MINT_LDC_I4_M1)
2696 LDC(-1);
2697 MINT_IN_BREAK;
2698 MINT_IN_CASE(MINT_LDC_I4_0)
2699 LDC(0);
2700 MINT_IN_BREAK;
2701 MINT_IN_CASE(MINT_LDC_I4_1)
2702 LDC(1);
2703 MINT_IN_BREAK;
2704 MINT_IN_CASE(MINT_LDC_I4_2)
2705 LDC(2);
2706 MINT_IN_BREAK;
2707 MINT_IN_CASE(MINT_LDC_I4_3)
2708 LDC(3);
2709 MINT_IN_BREAK;
2710 MINT_IN_CASE(MINT_LDC_I4_4)
2711 LDC(4);
2712 MINT_IN_BREAK;
2713 MINT_IN_CASE(MINT_LDC_I4_5)
2714 LDC(5);
2715 MINT_IN_BREAK;
2716 MINT_IN_CASE(MINT_LDC_I4_6)
2717 LDC(6);
2718 MINT_IN_BREAK;
2719 MINT_IN_CASE(MINT_LDC_I4_7)
2720 LDC(7);
2721 MINT_IN_BREAK;
2722 MINT_IN_CASE(MINT_LDC_I4_8)
2723 LDC(8);
2724 MINT_IN_BREAK;
2725 MINT_IN_CASE(MINT_LDC_I4_S)
2726 sp->data.i = *(const short *)(ip + 1);
2727 ip += 2;
2728 ++sp;
2729 MINT_IN_BREAK;
2730 MINT_IN_CASE(MINT_LDC_I4)
2731 ++ip;
2732 sp->data.i = READ32 (ip);
2733 ip += 2;
2734 ++sp;
2735 MINT_IN_BREAK;
2736 MINT_IN_CASE(MINT_LDC_I8)
2737 ++ip;
2738 sp->data.l = READ64 (ip);
2739 ip += 4;
2740 ++sp;
2741 MINT_IN_BREAK;
2742 MINT_IN_CASE(MINT_LDC_R4) {
2743 guint32 val;
2744 ++ip;
2745 val = READ32(ip);
2746 sp->data.f = * (float *)&val;
2747 ip += 2;
2748 ++sp;
2749 MINT_IN_BREAK;
2751 MINT_IN_CASE(MINT_LDC_R8)
2752 sp->data.l = READ64 (ip + 1); /* note union usage */
2753 ip += 5;
2754 ++sp;
2755 MINT_IN_BREAK;
2756 MINT_IN_CASE(MINT_DUP)
2757 sp [0] = sp[-1];
2758 ++sp;
2759 ++ip;
2760 MINT_IN_BREAK;
2761 MINT_IN_CASE(MINT_DUP_VT)
2762 i32 = READ32 (ip + 1);
2763 sp->data.p = vt_sp;
2764 memcpy(sp->data.p, sp [-1].data.p, i32);
2765 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
2766 ++sp;
2767 ip += 3;
2768 MINT_IN_BREAK;
2769 MINT_IN_CASE(MINT_POP) {
2770 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2771 if (u16 > 1)
2772 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2773 sp--;
2774 ip += 2;
2775 MINT_IN_BREAK;
2777 MINT_IN_CASE(MINT_JMP) {
2778 InterpMethod *new_method = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
2779 gboolean realloc_frame = new_method->alloca_size > rtm->alloca_size;
2781 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
2782 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
2784 if (!new_method->transformed) {
2785 ERROR_DECL (error);
2787 frame->ip = ip;
2788 mono_interp_transform_method (new_method, context, error);
2789 frame->ex = mono_error_convert_to_exception (error);
2790 if (frame->ex)
2791 goto exit_frame;
2793 ip += 2;
2794 rtm = frame->imethod = new_method;
2796 * We allocate the stack frame from scratch and store the arguments in the
2797 * locals again since it's possible for the caller stack frame to be smaller
2798 * than the callee stack frame (at the interp level)
2800 if (realloc_frame) {
2801 frame->args = g_newa (char, rtm->alloca_size);
2802 memset (frame->args, 0, rtm->alloca_size);
2803 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2805 vt_sp = (unsigned char *) sp + rtm->stack_size;
2806 #if DEBUG_INTERP
2807 vtalloc = vt_sp;
2808 #endif
2809 locals = vt_sp + rtm->vt_stack_size;
2810 frame->locals = locals;
2811 if (realloc_frame)
2812 ip = rtm->code;
2813 else
2814 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2815 MINT_IN_BREAK;
2817 MINT_IN_CASE(MINT_CALLI) {
2818 MonoMethodSignature *csignature;
2819 stackval *endsp = sp;
2821 frame->ip = ip;
2823 csignature = (MonoMethodSignature*)rtm->data_items [* (guint16 *)(ip + 1)];
2824 ip += 2;
2825 --sp;
2826 --endsp;
2827 child_frame.imethod = (InterpMethod*)sp->data.p;
2829 sp->data.p = vt_sp;
2830 child_frame.retval = sp;
2831 /* decrement by the actual number of args */
2832 sp -= csignature->param_count;
2833 if (csignature->hasthis)
2834 --sp;
2835 child_frame.stack_args = sp;
2837 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2838 child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
2839 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2842 if (csignature->hasthis) {
2843 MonoObject *this_arg = (MonoObject*)sp->data.p;
2845 if (m_class_is_valuetype (this_arg->vtable->klass)) {
2846 gpointer unboxed = mono_object_unbox (this_arg);
2847 sp [0].data.p = unboxed;
2851 interp_exec_method (&child_frame, context);
2853 context->current_frame = frame;
2855 if (context->has_resume_state) {
2856 if (frame == context->handler_frame)
2857 SET_RESUME_STATE (context);
2858 else
2859 goto exit_frame;
2862 CHECK_CHILD_EX (child_frame, ip - 2);
2864 /* need to handle typedbyref ... */
2865 if (csignature->ret->type != MONO_TYPE_VOID) {
2866 *sp = *endsp;
2867 sp++;
2869 MINT_IN_BREAK;
2871 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
2872 gpointer target_ip = sp [-1].data.p;
2873 MonoMethodSignature *csignature = (MonoMethodSignature*)rtm->data_items [* (guint16 *)(ip + 1)];
2874 int opcode = *(guint16 *)(ip + 2);
2876 sp--;
2877 frame->ip = ip;
2879 sp = do_icall (context, csignature, opcode, sp, target_ip);
2880 EXCEPTION_CHECKPOINT;
2881 if (context->has_resume_state) {
2882 if (frame == context->handler_frame)
2883 SET_RESUME_STATE (context);
2884 else
2885 goto exit_frame;
2887 ip += 3;
2888 MINT_IN_BREAK;
2890 MINT_IN_CASE(MINT_CALLI_NAT) {
2891 MonoMethodSignature *csignature;
2892 stackval *endsp = sp;
2893 unsigned char *code = NULL;
2895 frame->ip = ip;
2897 csignature = (MonoMethodSignature*)rtm->data_items [* (guint16 *)(ip + 1)];
2898 ip += 2;
2899 --sp;
2900 --endsp;
2901 code = (guchar*)sp->data.p;
2902 child_frame.imethod = NULL;
2904 sp->data.p = vt_sp;
2905 child_frame.retval = sp;
2906 /* decrement by the actual number of args */
2907 sp -= csignature->param_count;
2908 if (csignature->hasthis)
2909 --sp;
2910 child_frame.stack_args = sp;
2911 if (frame->imethod->method->dynamic && csignature->pinvoke) {
2912 MonoMarshalSpec **mspecs;
2913 MonoMethodPInvoke piinfo;
2914 MonoMethod *m;
2916 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
2917 mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
2918 memset (&piinfo, 0, sizeof (piinfo));
2920 m = mono_marshal_get_native_func_wrapper (m_class_get_image (frame->imethod->method->klass), csignature, &piinfo, mspecs, code);
2921 child_frame.imethod = mono_interp_get_imethod (rtm->domain, m, error);
2922 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2924 interp_exec_method (&child_frame, context);
2925 } else {
2926 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2928 context->current_frame = frame;
2930 if (context->has_resume_state) {
2931 if (frame == context->handler_frame)
2932 SET_RESUME_STATE (context);
2933 else
2934 goto exit_frame;
2937 CHECK_CHILD_EX (child_frame, ip - 2);
2939 /* need to handle typedbyref ... */
2940 if (csignature->ret->type != MONO_TYPE_VOID) {
2941 *sp = *endsp;
2942 sp++;
2944 MINT_IN_BREAK;
2946 MINT_IN_CASE(MINT_CALL)
2947 MINT_IN_CASE(MINT_VCALL)
2948 MINT_IN_CASE(MINT_CALLVIRT)
2949 MINT_IN_CASE(MINT_VCALLVIRT) {
2950 gboolean is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
2951 gboolean is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
2952 stackval *endsp = sp;
2953 int num_varargs = 0;;
2955 frame->ip = ip;
2957 child_frame.imethod = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
2958 if (child_frame.imethod->vararg) {
2959 /* The real signature for vararg calls */
2960 MonoMethodSignature *csig = (MonoMethodSignature*) rtm->data_items [* (guint16*) (ip + 2)];
2961 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
2962 num_varargs = csig->param_count - csig->sentinelpos;
2963 child_frame.varargs = (char*) vt_sp;
2964 copy_varargs_vtstack (csig, sp, &vt_sp);
2966 ip += 2 + child_frame.imethod->vararg;
2967 sp->data.p = vt_sp;
2968 child_frame.retval = sp;
2970 /* decrement by the actual number of args */
2971 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
2972 child_frame.stack_args = sp;
2974 if (is_virtual) {
2975 MonoObject *this_arg = (MonoObject*)sp->data.p;
2976 MonoClass *this_class = this_arg->vtable->klass;
2978 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2979 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
2980 /* unbox */
2981 gpointer unboxed = mono_object_unbox (this_arg);
2982 sp [0].data.p = unboxed;
2986 interp_exec_method (&child_frame, context);
2988 context->current_frame = frame;
2990 if (context->has_resume_state) {
2991 if (frame == context->handler_frame)
2992 SET_RESUME_STATE (context);
2993 else
2994 goto exit_frame;
2996 CHECK_CHILD_EX (child_frame, ip - 2);
2998 if (!is_void) {
2999 /* need to handle typedbyref ... */
3000 *sp = *endsp;
3001 sp++;
3003 MINT_IN_BREAK;
3005 MINT_IN_CASE(MINT_JIT_CALL) {
3006 InterpMethod *rmethod = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
3007 ERROR_DECL (error);
3008 frame->ip = ip;
3009 ip += 2;
3010 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3011 if (!is_ok (error)) {
3012 MonoException *ex = mono_error_convert_to_exception (error);
3013 THROW_EX (ex, ip);
3016 if (context->has_resume_state) {
3018 * If this bit is set, it means the call has thrown the exception, and we
3019 * reached this point because the EH code in mono_handle_exception ()
3020 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
3021 * has set the fields in context to indicate where we have to resume execution.
3023 if (frame == context->handler_frame)
3024 SET_RESUME_STATE (context);
3025 else
3026 goto exit_frame;
3028 if (rmethod->rtype->type != MONO_TYPE_VOID)
3029 sp++;
3031 MINT_IN_BREAK;
3033 MINT_IN_CASE(MINT_CALLRUN) {
3034 MonoMethod *target_method = (MonoMethod*) rtm->data_items [* (guint16 *)(ip + 1)];
3035 MonoMethodSignature *sig = (MonoMethodSignature*) rtm->data_items [* (guint16 *)(ip + 2)];
3036 stackval *retval;
3038 sp->data.p = vt_sp;
3039 retval = sp;
3041 sp -= sig->param_count;
3042 if (sig->hasthis)
3043 sp--;
3045 ves_imethod (frame, target_method, sig, sp, retval);
3046 if (frame->ex)
3047 THROW_EX (frame->ex, ip);
3049 if (sig->ret->type != MONO_TYPE_VOID) {
3050 *sp = *retval;
3051 sp++;
3053 ip += 3;
3054 MINT_IN_BREAK;
3056 MINT_IN_CASE(MINT_RET)
3057 --sp;
3058 *frame->retval = *sp;
3059 if (sp > frame->stack)
3060 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3061 goto exit_frame;
3062 MINT_IN_CASE(MINT_RET_VOID)
3063 if (sp > frame->stack)
3064 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3065 goto exit_frame;
3066 MINT_IN_CASE(MINT_RET_VT)
3067 i32 = READ32(ip + 1);
3068 --sp;
3069 memcpy(frame->retval->data.p, sp->data.p, i32);
3070 if (sp > frame->stack)
3071 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3072 goto exit_frame;
3073 MINT_IN_CASE(MINT_BR_S)
3074 ip += (short) *(ip + 1);
3075 MINT_IN_BREAK;
3076 MINT_IN_CASE(MINT_BR)
3077 ip += (gint32) READ32(ip + 1);
3078 MINT_IN_BREAK;
3079 #define ZEROP_S(datamem, op) \
3080 --sp; \
3081 if (sp->data.datamem op 0) \
3082 ip += * (gint16 *)(ip + 1); \
3083 else \
3084 ip += 2;
3086 #define ZEROP(datamem, op) \
3087 --sp; \
3088 if (sp->data.datamem op 0) \
3089 ip += READ32(ip + 1); \
3090 else \
3091 ip += 3;
3093 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3094 ZEROP_S(i, ==);
3095 MINT_IN_BREAK;
3096 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3097 ZEROP_S(l, ==);
3098 MINT_IN_BREAK;
3099 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3100 ZEROP_S(f, ==);
3101 MINT_IN_BREAK;
3102 MINT_IN_CASE(MINT_BRFALSE_I4)
3103 ZEROP(i, ==);
3104 MINT_IN_BREAK;
3105 MINT_IN_CASE(MINT_BRFALSE_I8)
3106 ZEROP(l, ==);
3107 MINT_IN_BREAK;
3108 MINT_IN_CASE(MINT_BRFALSE_R8)
3109 ZEROP_S(f, ==);
3110 MINT_IN_BREAK;
3111 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3112 ZEROP_S(i, !=);
3113 MINT_IN_BREAK;
3114 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3115 ZEROP_S(l, !=);
3116 MINT_IN_BREAK;
3117 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3118 ZEROP_S(f, !=);
3119 MINT_IN_BREAK;
3120 MINT_IN_CASE(MINT_BRTRUE_I4)
3121 ZEROP(i, !=);
3122 MINT_IN_BREAK;
3123 MINT_IN_CASE(MINT_BRTRUE_I8)
3124 ZEROP(l, !=);
3125 MINT_IN_BREAK;
3126 MINT_IN_CASE(MINT_BRTRUE_R8)
3127 ZEROP(f, !=);
3128 MINT_IN_BREAK;
3129 #define CONDBR_S(cond) \
3130 sp -= 2; \
3131 if (cond) \
3132 ip += * (gint16 *)(ip + 1); \
3133 else \
3134 ip += 2;
3135 #define BRELOP_S(datamem, op) \
3136 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3138 #define CONDBR(cond) \
3139 sp -= 2; \
3140 if (cond) \
3141 ip += READ32(ip + 1); \
3142 else \
3143 ip += 3;
3145 #define BRELOP(datamem, op) \
3146 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3148 MINT_IN_CASE(MINT_BEQ_I4_S)
3149 BRELOP_S(i, ==)
3150 MINT_IN_BREAK;
3151 MINT_IN_CASE(MINT_BEQ_I8_S)
3152 BRELOP_S(l, ==)
3153 MINT_IN_BREAK;
3154 MINT_IN_CASE(MINT_BEQ_R8_S)
3155 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3156 MINT_IN_BREAK;
3157 MINT_IN_CASE(MINT_BEQ_I4)
3158 BRELOP(i, ==)
3159 MINT_IN_BREAK;
3160 MINT_IN_CASE(MINT_BEQ_I8)
3161 BRELOP(l, ==)
3162 MINT_IN_BREAK;
3163 MINT_IN_CASE(MINT_BEQ_R8)
3164 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3165 MINT_IN_BREAK;
3166 MINT_IN_CASE(MINT_BGE_I4_S)
3167 BRELOP_S(i, >=)
3168 MINT_IN_BREAK;
3169 MINT_IN_CASE(MINT_BGE_I8_S)
3170 BRELOP_S(l, >=)
3171 MINT_IN_BREAK;
3172 MINT_IN_CASE(MINT_BGE_R8_S)
3173 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3174 MINT_IN_BREAK;
3175 MINT_IN_CASE(MINT_BGE_I4)
3176 BRELOP(i, >=)
3177 MINT_IN_BREAK;
3178 MINT_IN_CASE(MINT_BGE_I8)
3179 BRELOP(l, >=)
3180 MINT_IN_BREAK;
3181 MINT_IN_CASE(MINT_BGE_R8)
3182 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3183 MINT_IN_BREAK;
3184 MINT_IN_CASE(MINT_BGT_I4_S)
3185 BRELOP_S(i, >)
3186 MINT_IN_BREAK;
3187 MINT_IN_CASE(MINT_BGT_I8_S)
3188 BRELOP_S(l, >)
3189 MINT_IN_BREAK;
3190 MINT_IN_CASE(MINT_BGT_R8_S)
3191 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3192 MINT_IN_BREAK;
3193 MINT_IN_CASE(MINT_BGT_I4)
3194 BRELOP(i, >)
3195 MINT_IN_BREAK;
3196 MINT_IN_CASE(MINT_BGT_I8)
3197 BRELOP(l, >)
3198 MINT_IN_BREAK;
3199 MINT_IN_CASE(MINT_BGT_R8)
3200 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3201 MINT_IN_BREAK;
3202 MINT_IN_CASE(MINT_BLT_I4_S)
3203 BRELOP_S(i, <)
3204 MINT_IN_BREAK;
3205 MINT_IN_CASE(MINT_BLT_I8_S)
3206 BRELOP_S(l, <)
3207 MINT_IN_BREAK;
3208 MINT_IN_CASE(MINT_BLT_R8_S)
3209 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3210 MINT_IN_BREAK;
3211 MINT_IN_CASE(MINT_BLT_I4)
3212 BRELOP(i, <)
3213 MINT_IN_BREAK;
3214 MINT_IN_CASE(MINT_BLT_I8)
3215 BRELOP(l, <)
3216 MINT_IN_BREAK;
3217 MINT_IN_CASE(MINT_BLT_R8)
3218 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3219 MINT_IN_BREAK;
3220 MINT_IN_CASE(MINT_BLE_I4_S)
3221 BRELOP_S(i, <=)
3222 MINT_IN_BREAK;
3223 MINT_IN_CASE(MINT_BLE_I8_S)
3224 BRELOP_S(l, <=)
3225 MINT_IN_BREAK;
3226 MINT_IN_CASE(MINT_BLE_R8_S)
3227 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3228 MINT_IN_BREAK;
3229 MINT_IN_CASE(MINT_BLE_I4)
3230 BRELOP(i, <=)
3231 MINT_IN_BREAK;
3232 MINT_IN_CASE(MINT_BLE_I8)
3233 BRELOP(l, <=)
3234 MINT_IN_BREAK;
3235 MINT_IN_CASE(MINT_BLE_R8)
3236 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3237 MINT_IN_BREAK;
3238 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3239 BRELOP_S(i, !=)
3240 MINT_IN_BREAK;
3241 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3242 BRELOP_S(l, !=)
3243 MINT_IN_BREAK;
3244 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3245 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3246 MINT_IN_BREAK;
3247 MINT_IN_CASE(MINT_BNE_UN_I4)
3248 BRELOP(i, !=)
3249 MINT_IN_BREAK;
3250 MINT_IN_CASE(MINT_BNE_UN_I8)
3251 BRELOP(l, !=)
3252 MINT_IN_BREAK;
3253 MINT_IN_CASE(MINT_BNE_UN_R8)
3254 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3255 MINT_IN_BREAK;
3257 #define BRELOP_S_CAST(datamem, op, type) \
3258 sp -= 2; \
3259 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3260 ip += * (gint16 *)(ip + 1); \
3261 else \
3262 ip += 2;
3264 #define BRELOP_CAST(datamem, op, type) \
3265 sp -= 2; \
3266 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3267 ip += READ32(ip + 1); \
3268 else \
3269 ip += 3;
3271 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3272 BRELOP_S_CAST(i, >=, guint32);
3273 MINT_IN_BREAK;
3274 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3275 BRELOP_S_CAST(l, >=, guint64);
3276 MINT_IN_BREAK;
3277 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3278 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3279 MINT_IN_BREAK;
3280 MINT_IN_CASE(MINT_BGE_UN_I4)
3281 BRELOP_CAST(i, >=, guint32);
3282 MINT_IN_BREAK;
3283 MINT_IN_CASE(MINT_BGE_UN_I8)
3284 BRELOP_CAST(l, >=, guint64);
3285 MINT_IN_BREAK;
3286 MINT_IN_CASE(MINT_BGE_UN_R8)
3287 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3288 MINT_IN_BREAK;
3289 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3290 BRELOP_S_CAST(i, >, guint32);
3291 MINT_IN_BREAK;
3292 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3293 BRELOP_S_CAST(l, >, guint64);
3294 MINT_IN_BREAK;
3295 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3296 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3297 MINT_IN_BREAK;
3298 MINT_IN_CASE(MINT_BGT_UN_I4)
3299 BRELOP_CAST(i, >, guint32);
3300 MINT_IN_BREAK;
3301 MINT_IN_CASE(MINT_BGT_UN_I8)
3302 BRELOP_CAST(l, >, guint64);
3303 MINT_IN_BREAK;
3304 MINT_IN_CASE(MINT_BGT_UN_R8)
3305 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3306 MINT_IN_BREAK;
3307 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3308 BRELOP_S_CAST(i, <=, guint32);
3309 MINT_IN_BREAK;
3310 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3311 BRELOP_S_CAST(l, <=, guint64);
3312 MINT_IN_BREAK;
3313 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3314 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3315 MINT_IN_BREAK;
3316 MINT_IN_CASE(MINT_BLE_UN_I4)
3317 BRELOP_CAST(i, <=, guint32);
3318 MINT_IN_BREAK;
3319 MINT_IN_CASE(MINT_BLE_UN_I8)
3320 BRELOP_CAST(l, <=, guint64);
3321 MINT_IN_BREAK;
3322 MINT_IN_CASE(MINT_BLE_UN_R8)
3323 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3324 MINT_IN_BREAK;
3325 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3326 BRELOP_S_CAST(i, <, guint32);
3327 MINT_IN_BREAK;
3328 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3329 BRELOP_S_CAST(l, <, guint64);
3330 MINT_IN_BREAK;
3331 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3332 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3333 MINT_IN_BREAK;
3334 MINT_IN_CASE(MINT_BLT_UN_I4)
3335 BRELOP_CAST(i, <, guint32);
3336 MINT_IN_BREAK;
3337 MINT_IN_CASE(MINT_BLT_UN_I8)
3338 BRELOP_CAST(l, <, guint64);
3339 MINT_IN_BREAK;
3340 MINT_IN_CASE(MINT_BLT_UN_R8)
3341 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3342 MINT_IN_BREAK;
3343 MINT_IN_CASE(MINT_SWITCH) {
3344 guint32 n;
3345 const unsigned short *st;
3346 ++ip;
3347 n = READ32 (ip);
3348 ip += 2;
3349 st = ip + 2 * n;
3350 --sp;
3351 if ((guint32)sp->data.i < n) {
3352 gint offset;
3353 ip += 2 * (guint32)sp->data.i;
3354 offset = READ32 (ip);
3355 ip = ip + offset;
3356 } else {
3357 ip = st;
3359 MINT_IN_BREAK;
3361 MINT_IN_CASE(MINT_LDIND_I1)
3362 ++ip;
3363 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3364 MINT_IN_BREAK;
3365 MINT_IN_CASE(MINT_LDIND_U1)
3366 ++ip;
3367 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3368 MINT_IN_BREAK;
3369 MINT_IN_CASE(MINT_LDIND_I2)
3370 ++ip;
3371 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3372 MINT_IN_BREAK;
3373 MINT_IN_CASE(MINT_LDIND_U2)
3374 ++ip;
3375 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3376 MINT_IN_BREAK;
3377 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3378 MINT_IN_CASE(MINT_LDIND_U4)
3379 ++ip;
3380 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3381 MINT_IN_BREAK;
3382 MINT_IN_CASE(MINT_LDIND_I8)
3383 ++ip;
3384 /* memmove handles unaligned case */
3385 memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3386 MINT_IN_BREAK;
3387 MINT_IN_CASE(MINT_LDIND_I) {
3388 guint16 offset = * (guint16 *)(ip + 1);
3389 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3390 ip += 2;
3391 MINT_IN_BREAK;
3393 MINT_IN_CASE(MINT_LDIND_R4)
3394 ++ip;
3395 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3396 MINT_IN_BREAK;
3397 MINT_IN_CASE(MINT_LDIND_R8)
3398 ++ip;
3399 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3400 MINT_IN_BREAK;
3401 MINT_IN_CASE(MINT_LDIND_REF)
3402 ++ip;
3403 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3404 MINT_IN_BREAK;
3405 MINT_IN_CASE(MINT_STIND_REF)
3406 ++ip;
3407 sp -= 2;
3408 mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.o);
3409 MINT_IN_BREAK;
3410 MINT_IN_CASE(MINT_STIND_I1)
3411 ++ip;
3412 sp -= 2;
3413 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3414 MINT_IN_BREAK;
3415 MINT_IN_CASE(MINT_STIND_I2)
3416 ++ip;
3417 sp -= 2;
3418 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3419 MINT_IN_BREAK;
3420 MINT_IN_CASE(MINT_STIND_I4)
3421 ++ip;
3422 sp -= 2;
3423 * (gint32 *) sp->data.p = sp[1].data.i;
3424 MINT_IN_BREAK;
3425 MINT_IN_CASE(MINT_STIND_I)
3426 ++ip;
3427 sp -= 2;
3428 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3429 MINT_IN_BREAK;
3430 MINT_IN_CASE(MINT_STIND_I8)
3431 ++ip;
3432 sp -= 2;
3433 * (gint64 *) sp->data.p = sp[1].data.l;
3434 MINT_IN_BREAK;
3435 MINT_IN_CASE(MINT_STIND_R4)
3436 ++ip;
3437 sp -= 2;
3438 * (float *) sp->data.p = (gfloat)sp[1].data.f;
3439 MINT_IN_BREAK;
3440 MINT_IN_CASE(MINT_STIND_R8)
3441 ++ip;
3442 sp -= 2;
3443 * (double *) sp->data.p = sp[1].data.f;
3444 MINT_IN_BREAK;
3445 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3446 ++ip;
3447 sp -= 2;
3448 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3449 MINT_IN_BREAK;
3450 #define BINOP(datamem, op) \
3451 --sp; \
3452 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3453 ++ip;
3454 MINT_IN_CASE(MINT_ADD_I4)
3455 BINOP(i, +);
3456 MINT_IN_BREAK;
3457 MINT_IN_CASE(MINT_ADD_I8)
3458 BINOP(l, +);
3459 MINT_IN_BREAK;
3460 MINT_IN_CASE(MINT_ADD_R8)
3461 BINOP(f, +);
3462 MINT_IN_BREAK;
3463 MINT_IN_CASE(MINT_ADD1_I4)
3464 ++sp [-1].data.i;
3465 ++ip;
3466 MINT_IN_BREAK;
3467 MINT_IN_CASE(MINT_ADD1_I8)
3468 ++sp [-1].data.l;
3469 ++ip;
3470 MINT_IN_BREAK;
3471 MINT_IN_CASE(MINT_SUB_I4)
3472 BINOP(i, -);
3473 MINT_IN_BREAK;
3474 MINT_IN_CASE(MINT_SUB_I8)
3475 BINOP(l, -);
3476 MINT_IN_BREAK;
3477 MINT_IN_CASE(MINT_SUB_R8)
3478 BINOP(f, -);
3479 MINT_IN_BREAK;
3480 MINT_IN_CASE(MINT_SUB1_I4)
3481 --sp [-1].data.i;
3482 ++ip;
3483 MINT_IN_BREAK;
3484 MINT_IN_CASE(MINT_SUB1_I8)
3485 --sp [-1].data.l;
3486 ++ip;
3487 MINT_IN_BREAK;
3488 MINT_IN_CASE(MINT_MUL_I4)
3489 BINOP(i, *);
3490 MINT_IN_BREAK;
3491 MINT_IN_CASE(MINT_MUL_I8)
3492 BINOP(l, *);
3493 MINT_IN_BREAK;
3494 MINT_IN_CASE(MINT_MUL_R8)
3495 BINOP(f, *);
3496 MINT_IN_BREAK;
3497 MINT_IN_CASE(MINT_DIV_I4)
3498 if (sp [-1].data.i == 0)
3499 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3500 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3501 THROW_EX (mono_get_exception_overflow (), ip);
3502 BINOP(i, /);
3503 MINT_IN_BREAK;
3504 MINT_IN_CASE(MINT_DIV_I8)
3505 if (sp [-1].data.l == 0)
3506 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3507 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3508 THROW_EX (mono_get_exception_overflow (), ip);
3509 BINOP(l, /);
3510 MINT_IN_BREAK;
3511 MINT_IN_CASE(MINT_DIV_R8)
3512 BINOP(f, /);
3513 MINT_IN_BREAK;
3515 #define BINOP_CAST(datamem, op, type) \
3516 --sp; \
3517 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3518 ++ip;
3519 MINT_IN_CASE(MINT_DIV_UN_I4)
3520 if (sp [-1].data.i == 0)
3521 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3522 BINOP_CAST(i, /, guint32);
3523 MINT_IN_BREAK;
3524 MINT_IN_CASE(MINT_DIV_UN_I8)
3525 if (sp [-1].data.l == 0)
3526 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3527 BINOP_CAST(l, /, guint64);
3528 MINT_IN_BREAK;
3529 MINT_IN_CASE(MINT_REM_I4)
3530 if (sp [-1].data.i == 0)
3531 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3532 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3533 THROW_EX (mono_get_exception_overflow (), ip);
3534 BINOP(i, %);
3535 MINT_IN_BREAK;
3536 MINT_IN_CASE(MINT_REM_I8)
3537 if (sp [-1].data.l == 0)
3538 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3539 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3540 THROW_EX (mono_get_exception_overflow (), ip);
3541 BINOP(l, %);
3542 MINT_IN_BREAK;
3543 MINT_IN_CASE(MINT_REM_R8)
3544 /* FIXME: what do we actually do here? */
3545 --sp;
3546 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3547 ++ip;
3548 MINT_IN_BREAK;
3549 MINT_IN_CASE(MINT_REM_UN_I4)
3550 if (sp [-1].data.i == 0)
3551 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3552 BINOP_CAST(i, %, guint32);
3553 MINT_IN_BREAK;
3554 MINT_IN_CASE(MINT_REM_UN_I8)
3555 if (sp [-1].data.l == 0)
3556 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3557 BINOP_CAST(l, %, guint64);
3558 MINT_IN_BREAK;
3559 MINT_IN_CASE(MINT_AND_I4)
3560 BINOP(i, &);
3561 MINT_IN_BREAK;
3562 MINT_IN_CASE(MINT_AND_I8)
3563 BINOP(l, &);
3564 MINT_IN_BREAK;
3565 MINT_IN_CASE(MINT_OR_I4)
3566 BINOP(i, |);
3567 MINT_IN_BREAK;
3568 MINT_IN_CASE(MINT_OR_I8)
3569 BINOP(l, |);
3570 MINT_IN_BREAK;
3571 MINT_IN_CASE(MINT_XOR_I4)
3572 BINOP(i, ^);
3573 MINT_IN_BREAK;
3574 MINT_IN_CASE(MINT_XOR_I8)
3575 BINOP(l, ^);
3576 MINT_IN_BREAK;
3578 #define SHIFTOP(datamem, op) \
3579 --sp; \
3580 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3581 ++ip;
3583 MINT_IN_CASE(MINT_SHL_I4)
3584 SHIFTOP(i, <<);
3585 MINT_IN_BREAK;
3586 MINT_IN_CASE(MINT_SHL_I8)
3587 SHIFTOP(l, <<);
3588 MINT_IN_BREAK;
3589 MINT_IN_CASE(MINT_SHR_I4)
3590 SHIFTOP(i, >>);
3591 MINT_IN_BREAK;
3592 MINT_IN_CASE(MINT_SHR_I8)
3593 SHIFTOP(l, >>);
3594 MINT_IN_BREAK;
3595 MINT_IN_CASE(MINT_SHR_UN_I4)
3596 --sp;
3597 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3598 ++ip;
3599 MINT_IN_BREAK;
3600 MINT_IN_CASE(MINT_SHR_UN_I8)
3601 --sp;
3602 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3603 ++ip;
3604 MINT_IN_BREAK;
3605 MINT_IN_CASE(MINT_NEG_I4)
3606 sp [-1].data.i = - sp [-1].data.i;
3607 ++ip;
3608 MINT_IN_BREAK;
3609 MINT_IN_CASE(MINT_NEG_I8)
3610 sp [-1].data.l = - sp [-1].data.l;
3611 ++ip;
3612 MINT_IN_BREAK;
3613 MINT_IN_CASE(MINT_NEG_R8)
3614 sp [-1].data.f = - sp [-1].data.f;
3615 ++ip;
3616 MINT_IN_BREAK;
3617 MINT_IN_CASE(MINT_NOT_I4)
3618 sp [-1].data.i = ~ sp [-1].data.i;
3619 ++ip;
3620 MINT_IN_BREAK;
3621 MINT_IN_CASE(MINT_NOT_I8)
3622 sp [-1].data.l = ~ sp [-1].data.l;
3623 ++ip;
3624 MINT_IN_BREAK;
3625 MINT_IN_CASE(MINT_CONV_I1_I4)
3626 sp [-1].data.i = (gint8)sp [-1].data.i;
3627 ++ip;
3628 MINT_IN_BREAK;
3629 MINT_IN_CASE(MINT_CONV_I1_I8)
3630 sp [-1].data.i = (gint8)sp [-1].data.l;
3631 ++ip;
3632 MINT_IN_BREAK;
3633 MINT_IN_CASE(MINT_CONV_I1_R8)
3634 /* without gint32 cast, C compiler is allowed to use undefined
3635 * behaviour if data.f is bigger than >255. See conv.fpint section
3636 * in C standard:
3637 * > The conversion truncates; that is, the fractional part
3638 * > is discarded. The behavior is undefined if the truncated
3639 * > value cannot be represented in the destination type.
3640 * */
3641 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
3642 ++ip;
3643 MINT_IN_BREAK;
3644 MINT_IN_CASE(MINT_CONV_U1_I4)
3645 sp [-1].data.i = (guint8)sp [-1].data.i;
3646 ++ip;
3647 MINT_IN_BREAK;
3648 MINT_IN_CASE(MINT_CONV_U1_I8)
3649 sp [-1].data.i = (guint8)sp [-1].data.l;
3650 ++ip;
3651 MINT_IN_BREAK;
3652 MINT_IN_CASE(MINT_CONV_U1_R8)
3653 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
3654 ++ip;
3655 MINT_IN_BREAK;
3656 MINT_IN_CASE(MINT_CONV_I2_I4)
3657 sp [-1].data.i = (gint16)sp [-1].data.i;
3658 ++ip;
3659 MINT_IN_BREAK;
3660 MINT_IN_CASE(MINT_CONV_I2_I8)
3661 sp [-1].data.i = (gint16)sp [-1].data.l;
3662 ++ip;
3663 MINT_IN_BREAK;
3664 MINT_IN_CASE(MINT_CONV_I2_R8)
3665 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
3666 ++ip;
3667 MINT_IN_BREAK;
3668 MINT_IN_CASE(MINT_CONV_U2_I4)
3669 sp [-1].data.i = (guint16)sp [-1].data.i;
3670 ++ip;
3671 MINT_IN_BREAK;
3672 MINT_IN_CASE(MINT_CONV_U2_I8)
3673 sp [-1].data.i = (guint16)sp [-1].data.l;
3674 ++ip;
3675 MINT_IN_BREAK;
3676 MINT_IN_CASE(MINT_CONV_U2_R8)
3677 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
3678 ++ip;
3679 MINT_IN_BREAK;
3680 MINT_IN_CASE(MINT_CONV_I4_R8)
3681 sp [-1].data.i = (gint32)sp [-1].data.f;
3682 ++ip;
3683 MINT_IN_BREAK;
3684 MINT_IN_CASE(MINT_CONV_U4_I8)
3685 MINT_IN_CASE(MINT_CONV_I4_I8)
3686 sp [-1].data.i = (gint32)sp [-1].data.l;
3687 ++ip;
3688 MINT_IN_BREAK;
3689 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3690 sp [-2].data.i = (gint32)sp [-2].data.l;
3691 ++ip;
3692 MINT_IN_BREAK;
3693 MINT_IN_CASE(MINT_CONV_U4_R8)
3694 /* needed on arm64 */
3695 if (isinf (sp [-1].data.f))
3696 sp [-1].data.i = 0;
3697 /* needed by wasm */
3698 else if (isnan (sp [-1].data.f))
3699 sp [-1].data.i = 0;
3700 else
3701 sp [-1].data.i = (guint32)sp [-1].data.f;
3702 ++ip;
3703 MINT_IN_BREAK;
3704 MINT_IN_CASE(MINT_CONV_I8_I4)
3705 sp [-1].data.l = sp [-1].data.i;
3706 ++ip;
3707 MINT_IN_BREAK;
3708 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3709 sp [-2].data.l = sp [-2].data.i;
3710 ++ip;
3711 MINT_IN_BREAK;
3712 MINT_IN_CASE(MINT_CONV_I8_U4)
3713 sp [-1].data.l = (guint32)sp [-1].data.i;
3714 ++ip;
3715 MINT_IN_BREAK;
3716 MINT_IN_CASE(MINT_CONV_I8_R8)
3717 sp [-1].data.l = (gint64)sp [-1].data.f;
3718 ++ip;
3719 MINT_IN_BREAK;
3720 MINT_IN_CASE(MINT_CONV_R4_I4)
3721 sp [-1].data.f = (float)sp [-1].data.i;
3722 ++ip;
3723 MINT_IN_BREAK;
3724 MINT_IN_CASE(MINT_CONV_R4_I8)
3725 sp [-1].data.f = (float)sp [-1].data.l;
3726 ++ip;
3727 MINT_IN_BREAK;
3728 MINT_IN_CASE(MINT_CONV_R4_R8)
3729 sp [-1].data.f = (float)sp [-1].data.f;
3730 ++ip;
3731 MINT_IN_BREAK;
3732 MINT_IN_CASE(MINT_CONV_R8_I4)
3733 sp [-1].data.f = (double)sp [-1].data.i;
3734 ++ip;
3735 MINT_IN_BREAK;
3736 MINT_IN_CASE(MINT_CONV_R8_I8)
3737 sp [-1].data.f = (double)sp [-1].data.l;
3738 ++ip;
3739 MINT_IN_BREAK;
3740 MINT_IN_CASE(MINT_CONV_U8_I4)
3741 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3742 ++ip;
3743 MINT_IN_BREAK;
3744 MINT_IN_CASE(MINT_CONV_U8_R8)
3745 sp [-1].data.l = (guint64)sp [-1].data.f;
3746 ++ip;
3747 MINT_IN_BREAK;
3748 MINT_IN_CASE(MINT_CPOBJ) {
3749 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
3750 g_assert (m_class_is_valuetype (c));
3751 /* if this assertion fails, we need to add a write barrier */
3752 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
3753 if (mint_type (m_class_get_byval_arg (c)) == MINT_TYPE_VT)
3754 stackval_from_data (m_class_get_byval_arg (c), &sp [-2], sp [-1].data.p, FALSE);
3755 else
3756 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
3757 ip += 2;
3758 sp -= 2;
3759 MINT_IN_BREAK;
3761 MINT_IN_CASE(MINT_LDOBJ) {
3762 void *p;
3763 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
3764 ip += 2;
3765 p = sp [-1].data.p;
3766 if (mint_type (m_class_get_byval_arg (c)) == MINT_TYPE_VT && !m_class_is_enumtype (c)) {
3767 int size = mono_class_value_size (c, NULL);
3768 sp [-1].data.p = vt_sp;
3769 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
3771 stackval_from_data (m_class_get_byval_arg (c), &sp [-1], p, FALSE);
3772 MINT_IN_BREAK;
3774 MINT_IN_CASE(MINT_LDSTR)
3775 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3776 ++sp;
3777 ip += 2;
3778 MINT_IN_BREAK;
3779 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
3780 MonoString *s = NULL;
3781 guint32 strtoken = (guint32)(gsize)rtm->data_items [* (guint16 *)(ip + 1)];
3783 MonoMethod *method = frame->imethod->method;
3784 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
3785 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
3786 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
3787 s = mono_string_new_wrapper ((const char*)mono_method_get_wrapper_data (method, strtoken));
3788 } else {
3789 g_assert_not_reached ();
3791 sp->data.p = s;
3792 ++sp;
3793 ip += 2;
3794 MINT_IN_BREAK;
3796 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
3797 MonoClass *newobj_class;
3798 InterpMethod *imethod;
3799 guint32 token = * (guint16 *)(ip + 1);
3800 guint16 param_count = * (guint16 *)(ip + 2);
3802 imethod = (InterpMethod*) rtm->data_items [token];
3803 newobj_class = imethod->method->klass;
3805 sp -= param_count;
3806 sp->data.p = ves_array_create (rtm->domain, newobj_class, param_count, sp, error);
3807 if (!mono_error_ok (error))
3808 THROW_EX (mono_error_convert_to_exception (error), ip);
3810 ++sp;
3811 ip += 3;
3812 MINT_IN_BREAK;
3814 MINT_IN_CASE(MINT_NEWOBJ_FAST)
3815 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
3816 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
3817 guint16 param_count;
3818 gboolean vt = *ip != MINT_NEWOBJ_FAST;
3819 stackval valuetype_this;
3821 frame->ip = ip;
3823 child_frame.imethod = (InterpMethod*) rtm->data_items [*(guint16*)(ip + 1)];
3824 param_count = *(guint16*)(ip + 2);
3826 if (param_count) {
3827 sp -= param_count;
3828 memmove (sp + 1, sp, param_count * sizeof (stackval));
3830 child_frame.stack_args = sp;
3832 if (vt) {
3833 gboolean vtst = *ip == MINT_NEWOBJ_VTST_FAST;
3834 memset (&valuetype_this, 0, sizeof (stackval));
3835 if (vtst) {
3836 sp->data.p = vt_sp;
3837 valuetype_this.data.p = vt_sp;
3838 } else {
3839 sp->data.p = &valuetype_this;
3841 } else {
3842 MonoVTable *vtable = (MonoVTable*) rtm->data_items [*(guint16*)(ip + 3)];
3843 if (G_UNLIKELY (!vtable->initialized)) {
3844 mono_runtime_class_init_full (vtable, error);
3845 if (!mono_error_ok (error))
3846 THROW_EX (mono_error_convert_to_exception (error), ip);
3848 o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3849 if (G_UNLIKELY (!o)) {
3850 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
3851 THROW_EX (mono_error_convert_to_exception (error), ip);
3853 sp->data.p = o;
3856 interp_exec_method (&child_frame, context);
3858 context->current_frame = frame;
3860 if (context->has_resume_state) {
3861 if (frame == context->handler_frame)
3862 SET_RESUME_STATE (context);
3863 else
3864 goto exit_frame;
3866 CHECK_CHILD_EX (child_frame, ip);
3867 if (vt)
3868 *sp = valuetype_this;
3869 else
3870 sp->data.p = o;
3871 ip += 4 - vt;
3872 ++sp;
3873 MINT_IN_BREAK;
3875 MINT_IN_CASE(MINT_NEWOBJ) {
3876 MonoClass *newobj_class;
3877 MonoMethodSignature *csig;
3878 stackval valuetype_this;
3879 guint32 token;
3880 stackval retval;
3882 frame->ip = ip;
3884 token = * (guint16 *)(ip + 1);
3885 ip += 2;
3887 child_frame.ip = NULL;
3888 child_frame.ex = NULL;
3890 child_frame.imethod = (InterpMethod*)rtm->data_items [token];
3891 csig = mono_method_signature (child_frame.imethod->method);
3892 newobj_class = child_frame.imethod->method->klass;
3893 /*if (profiling_classes) {
3894 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3895 count++;
3896 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3899 g_assert (csig->hasthis);
3900 if (csig->param_count) {
3901 sp -= csig->param_count;
3902 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3904 child_frame.stack_args = sp;
3907 * First arg is the object.
3909 if (m_class_is_valuetype (newobj_class)) {
3910 MonoType *t = m_class_get_byval_arg (newobj_class);
3911 memset (&valuetype_this, 0, sizeof (stackval));
3912 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3913 sp->data.p = vt_sp;
3914 valuetype_this.data.p = vt_sp;
3915 } else {
3916 sp->data.p = &valuetype_this;
3918 } else {
3919 if (newobj_class != mono_defaults.string_class) {
3920 MonoVTable *vtable = mono_class_vtable_checked (rtm->domain, newobj_class, error);
3921 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
3922 THROW_EX (mono_error_convert_to_exception (error), ip);
3923 o = mono_object_new_checked (rtm->domain, newobj_class, error);
3924 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3925 EXCEPTION_CHECKPOINT;
3926 sp->data.p = o;
3927 #ifndef DISABLE_REMOTING
3928 if (mono_object_is_transparent_proxy (o)) {
3929 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
3930 mono_error_assert_ok (error);
3931 child_frame.imethod = mono_interp_get_imethod (rtm->domain, remoting_invoke_method, error);
3932 mono_error_assert_ok (error);
3934 #endif
3935 } else {
3936 sp->data.p = NULL;
3937 child_frame.retval = &retval;
3941 interp_exec_method (&child_frame, context);
3943 context->current_frame = frame;
3945 if (context->has_resume_state) {
3946 if (frame == context->handler_frame)
3947 SET_RESUME_STATE (context);
3948 else
3949 goto exit_frame;
3952 CHECK_CHILD_EX (child_frame, ip - 2);
3954 * a constructor returns void, but we need to return the object we created
3956 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3957 *sp = valuetype_this;
3958 } else if (newobj_class == mono_defaults.string_class) {
3959 *sp = retval;
3960 } else {
3961 sp->data.p = o;
3963 ++sp;
3964 MINT_IN_BREAK;
3966 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
3967 guint32 token;
3969 frame->ip = ip;
3970 token = * (guint16 *)(ip + 1);
3971 ip += 2;
3973 MINT_IN_BREAK;
3975 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
3976 MonoClass *newobj_class;
3977 MonoMethodSignature *csig;
3978 guint32 token;
3980 frame->ip = ip;
3981 token = * (guint16 *)(ip + 1);
3982 ip += 2;
3984 InterpMethod *cmethod = (InterpMethod*)rtm->data_items [token];
3985 csig = mono_method_signature (cmethod->method);
3986 newobj_class = cmethod->method->klass;
3988 g_assert (csig->hasthis);
3989 sp -= csig->param_count;
3991 gpointer arg0 = sp [0].data.p;
3993 gpointer *byreference_this = (gpointer*)vt_sp;
3994 *byreference_this = arg0;
3996 /* Followed by a VTRESULT opcode which will push the result on the stack */
3997 ++sp;
3998 MINT_IN_BREAK;
3999 break;
4001 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4002 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4003 sp [-1].data.p = *byreference_this;
4004 ++ip;
4005 MINT_IN_BREAK;
4006 break;
4008 MINT_IN_CASE(MINT_CASTCLASS)
4009 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
4010 if ((o = sp [-1].data.o)) {
4011 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4012 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4013 if (!isinst_obj)
4014 THROW_EX (mono_get_exception_invalid_cast (), ip);
4016 ip += 2;
4017 MINT_IN_BREAK;
4018 MINT_IN_CASE(MINT_ISINST)
4019 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
4020 if ((o = sp [-1].data.o)) {
4021 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4022 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4023 if (!isinst_obj)
4024 sp [-1].data.p = NULL;
4026 ip += 2;
4027 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4029 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4030 ++ip;
4031 MINT_IN_BREAK;
4032 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4033 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4034 ++ip;
4035 MINT_IN_BREAK;
4036 MINT_IN_CASE(MINT_UNBOX)
4037 c = (MonoClass*)rtm->data_items[*(guint16 *)(ip + 1)];
4039 o = sp [-1].data.o;
4040 if (!o)
4041 THROW_EX (mono_get_exception_null_reference (), ip);
4043 MonoObject *isinst_obj;
4044 isinst_obj = mono_object_isinst_checked (o, c, error);
4045 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4046 if (!(isinst_obj || ((m_class_get_rank (o->vtable->klass) == 0) && (m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))))
4047 THROW_EX (mono_get_exception_invalid_cast (), ip);
4049 sp [-1].data.p = mono_object_unbox (o);
4050 ip += 2;
4051 MINT_IN_BREAK;
4052 MINT_IN_CASE(MINT_THROW)
4053 --sp;
4054 frame->ex_handler = NULL;
4055 if (!sp->data.p)
4056 sp->data.p = mono_get_exception_null_reference ();
4058 THROW_EX ((MonoException *)sp->data.p, ip);
4059 MINT_IN_BREAK;
4060 MINT_IN_CASE(MINT_CHECKPOINT)
4061 /* Do synchronous checking of abort requests */
4062 EXCEPTION_CHECKPOINT;
4063 ++ip;
4064 MINT_IN_BREAK;
4065 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
4066 o = sp [-1].data.o;
4067 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4068 ip += 2;
4069 MINT_IN_BREAK;
4070 MINT_IN_CASE(MINT_LDFLDA)
4071 o = sp [-1].data.o;
4072 if (!o)
4073 THROW_EX (mono_get_exception_null_reference (), ip);
4074 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4075 ip += 2;
4076 MINT_IN_BREAK;
4077 MINT_IN_CASE(MINT_CKNULL)
4078 o = sp [-1].data.o;
4079 if (!o)
4080 THROW_EX (mono_get_exception_null_reference (), ip);
4081 ++ip;
4082 MINT_IN_BREAK;
4083 MINT_IN_CASE(MINT_CKNULL_N) {
4084 /* Same as CKNULL, but further down the stack */
4085 int n = *(guint16*)(ip + 1);
4086 o = sp [-n].data.o;
4087 if (!o)
4088 THROW_EX (mono_get_exception_null_reference (), ip);
4089 ip += 2;
4090 MINT_IN_BREAK;
4093 #define LDFLD(datamem, fieldtype) \
4094 o = sp [-1].data.o; \
4095 if (!o) \
4096 THROW_EX (mono_get_exception_null_reference (), ip); \
4097 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4098 ip += 2;
4100 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4101 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4102 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4103 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4104 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4105 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4106 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
4107 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4108 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4109 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4111 MINT_IN_CASE(MINT_LDFLD_VT) {
4112 o = sp [-1].data.o;
4113 if (!o)
4114 THROW_EX (mono_get_exception_null_reference (), ip);
4116 MonoClassField *field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 2)];
4117 MonoClass *klass = mono_class_from_mono_type (field->type);
4118 i32 = mono_class_value_size (klass, NULL);
4120 sp [-1].data.p = vt_sp;
4121 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
4122 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4123 ip += 3;
4124 MINT_IN_BREAK;
4127 MINT_IN_CASE(MINT_LDRMFLD) {
4128 MonoClassField *field;
4129 char *addr;
4131 o = sp [-1].data.o;
4132 if (!o)
4133 THROW_EX (mono_get_exception_null_reference (), ip);
4134 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4135 ip += 2;
4136 #ifndef DISABLE_REMOTING
4137 if (mono_object_is_transparent_proxy (o)) {
4138 gpointer tmp;
4139 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4141 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4142 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4143 } else
4144 #endif
4145 addr = (char*)o + field->offset;
4147 stackval_from_data (field->type, &sp [-1], addr, FALSE);
4148 MINT_IN_BREAK;
4151 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4152 MonoClassField *field;
4153 char *addr;
4155 o = sp [-1].data.o;
4156 if (!o)
4157 THROW_EX (mono_get_exception_null_reference (), ip);
4159 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4160 MonoClass *klass = mono_class_from_mono_type (field->type);
4161 i32 = mono_class_value_size (klass, NULL);
4163 ip += 2;
4164 #ifndef DISABLE_REMOTING
4165 if (mono_object_is_transparent_proxy (o)) {
4166 gpointer tmp;
4167 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4168 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4169 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4170 } else
4171 #endif
4172 addr = (char*)o + field->offset;
4174 sp [-1].data.p = vt_sp;
4175 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
4176 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4177 memcpy(sp [-1].data.p, addr, i32);
4178 MINT_IN_BREAK;
4181 #define STFLD(datamem, fieldtype) \
4182 o = sp [-2].data.o; \
4183 if (!o) \
4184 THROW_EX (mono_get_exception_null_reference (), ip); \
4185 sp -= 2; \
4186 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4187 ip += 2;
4189 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4190 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4191 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4192 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4193 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4194 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4195 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
4196 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4197 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4198 MINT_IN_CASE(MINT_STFLD_O)
4199 o = sp [-2].data.o;
4200 if (!o)
4201 THROW_EX (mono_get_exception_null_reference (), ip);
4202 sp -= 2;
4203 mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
4204 ip += 2;
4205 MINT_IN_BREAK;
4207 MINT_IN_CASE(MINT_STFLD_VT) {
4208 o = sp [-2].data.o;
4209 if (!o)
4210 THROW_EX (mono_get_exception_null_reference (), ip);
4211 sp -= 2;
4213 MonoClassField *field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 2)];
4214 MonoClass *klass = mono_class_from_mono_type (field->type);
4215 i32 = mono_class_value_size (klass, NULL);
4217 guint16 offset = * (guint16 *)(ip + 1);
4218 mono_value_copy ((char *) o + offset, sp [1].data.p, klass);
4220 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4221 ip += 3;
4222 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_STRMFLD) {
4225 MonoClassField *field;
4227 o = sp [-2].data.o;
4228 if (!o)
4229 THROW_EX (mono_get_exception_null_reference (), ip);
4231 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4232 ip += 2;
4234 #ifndef DISABLE_REMOTING
4235 if (mono_object_is_transparent_proxy (o)) {
4236 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4237 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4238 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4239 } else
4240 #endif
4241 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4243 sp -= 2;
4244 MINT_IN_BREAK;
4246 MINT_IN_CASE(MINT_STRMFLD_VT) {
4247 MonoClassField *field;
4249 o = sp [-2].data.o;
4250 if (!o)
4251 THROW_EX (mono_get_exception_null_reference (), ip);
4252 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4253 MonoClass *klass = mono_class_from_mono_type (field->type);
4254 i32 = mono_class_value_size (klass, NULL);
4255 ip += 2;
4257 #ifndef DISABLE_REMOTING
4258 if (mono_object_is_transparent_proxy (o)) {
4259 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4260 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4261 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4262 } else
4263 #endif
4264 mono_value_copy ((char *) o + field->offset, sp [-1].data.p, klass);
4266 sp -= 2;
4267 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4268 MINT_IN_BREAK;
4270 MINT_IN_CASE(MINT_LDSFLDA) {
4271 MonoClassField *field = (MonoClassField*)rtm->data_items[*(guint16 *)(ip + 1)];
4272 sp->data.p = mono_class_static_field_address (rtm->domain, field);
4273 EXCEPTION_CHECKPOINT;
4274 ip += 2;
4275 ++sp;
4276 MINT_IN_BREAK;
4278 MINT_IN_CASE(MINT_LDSFLD) {
4279 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4280 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4281 EXCEPTION_CHECKPOINT;
4282 stackval_from_data (field->type, sp, addr, FALSE);
4283 ip += 2;
4284 ++sp;
4285 MINT_IN_BREAK;
4287 MINT_IN_CASE(MINT_LDSFLD_VT) {
4288 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4289 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4290 EXCEPTION_CHECKPOINT;
4291 int size = READ32 (ip + 2);
4292 ip += 4;
4294 sp->data.p = vt_sp;
4295 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4296 stackval_from_data (field->type, sp, addr, FALSE);
4297 ++sp;
4298 MINT_IN_BREAK;
4300 MINT_IN_CASE(MINT_STSFLD) {
4301 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4302 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4303 EXCEPTION_CHECKPOINT;
4304 ip += 2;
4305 --sp;
4306 stackval_to_data (field->type, sp, addr, FALSE);
4307 MINT_IN_BREAK;
4309 MINT_IN_CASE(MINT_STSFLD_VT) {
4310 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4311 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4312 EXCEPTION_CHECKPOINT;
4313 MonoClass *klass = mono_class_from_mono_type (field->type);
4314 i32 = mono_class_value_size (klass, NULL);
4315 ip += 2;
4317 --sp;
4318 stackval_to_data (field->type, sp, addr, FALSE);
4319 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4320 MINT_IN_BREAK;
4322 MINT_IN_CASE(MINT_STOBJ_VT) {
4323 int size;
4324 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4325 ip += 2;
4326 size = mono_class_value_size (c, NULL);
4327 memcpy(sp [-2].data.p, sp [-1].data.p, size);
4328 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
4329 sp -= 2;
4330 MINT_IN_BREAK;
4332 MINT_IN_CASE(MINT_STOBJ) {
4333 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4334 ip += 2;
4336 g_assert (!m_class_get_byval_arg (c)->byref);
4337 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)))
4338 mono_gc_wbarrier_generic_store (sp [-2].data.o, sp [-1].data.o);
4339 else
4340 stackval_to_data (m_class_get_byval_arg (c), &sp [-1], sp [-2].data.p, FALSE);
4341 sp -= 2;
4342 MINT_IN_BREAK;
4344 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
4345 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
4346 THROW_EX (mono_get_exception_overflow (), ip);
4347 sp [-1].data.i = (gint32)sp [-1].data.f;
4348 ++ip;
4349 MINT_IN_BREAK;
4350 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
4351 if (sp [-1].data.i < 0)
4352 THROW_EX (mono_get_exception_overflow (), ip);
4353 sp [-1].data.l = sp [-1].data.i;
4354 ++ip;
4355 MINT_IN_BREAK;
4356 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
4357 if (sp [-1].data.l < 0)
4358 THROW_EX (mono_get_exception_overflow (), ip);
4359 ++ip;
4360 MINT_IN_BREAK;
4361 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
4362 if ((guint64) sp [-1].data.l > G_MAXINT64)
4363 THROW_EX (mono_get_exception_overflow (), ip);
4364 ++ip;
4365 MINT_IN_BREAK;
4366 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
4367 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64)
4368 THROW_EX (mono_get_exception_overflow (), ip);
4369 sp [-1].data.l = (guint64)sp [-1].data.f;
4370 ++ip;
4371 MINT_IN_BREAK;
4372 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
4373 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
4374 THROW_EX (mono_get_exception_overflow (), ip);
4375 sp [-1].data.l = (gint64)sp [-1].data.f;
4376 ++ip;
4377 MINT_IN_BREAK;
4378 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
4379 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64)
4380 THROW_EX (mono_get_exception_overflow (), ip);
4381 sp [-1].data.l = (gint64)sp [-1].data.f;
4382 ++ip;
4383 MINT_IN_BREAK;
4384 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
4385 if ((guint64)sp [-1].data.l > G_MAXINT32)
4386 THROW_EX (mono_get_exception_overflow (), ip);
4387 sp [-1].data.i = (gint32)sp [-1].data.l;
4388 ++ip;
4389 MINT_IN_BREAK;
4390 MINT_IN_CASE(MINT_BOX) {
4391 c = (MonoClass*)rtm->data_items [* (guint16 *)(ip + 1)];
4392 guint16 offset = * (guint16 *)(ip + 2);
4393 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
4394 offset &= ~BOX_NOT_CLEAR_VT_SP;
4396 if (mint_type (m_class_get_byval_arg (c)) == MINT_TYPE_VT && !m_class_is_enumtype (c) && !(mono_class_is_magic_int (c) || mono_class_is_magic_float (c))) {
4397 int size = mono_class_value_size (c, NULL);
4398 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, error);
4399 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4400 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
4401 if (pop_vt_sp)
4402 vt_sp -= size;
4403 } else {
4404 stackval_to_data (m_class_get_byval_arg (c), &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
4405 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], error);
4406 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4408 ip += 3;
4409 MINT_IN_BREAK;
4411 MINT_IN_CASE(MINT_NEWARR)
4412 sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, (MonoClass*)rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, error);
4413 if (!mono_error_ok (error)) {
4414 THROW_EX (mono_error_convert_to_exception (error), ip);
4416 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4417 ip += 2;
4418 /*if (profiling_classes) {
4419 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
4420 count++;
4421 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
4424 MINT_IN_BREAK;
4425 MINT_IN_CASE(MINT_LDLEN)
4426 o = sp [-1].data.o;
4427 if (!o)
4428 THROW_EX (mono_get_exception_null_reference (), ip);
4429 sp [-1].data.nati = mono_array_length_fast ((MonoArray *)o);
4430 ++ip;
4431 MINT_IN_BREAK;
4432 MINT_IN_CASE(MINT_LDLEN_SPAN) {
4433 o = sp [-1].data.o;
4434 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
4435 if (!o)
4436 THROW_EX (mono_get_exception_null_reference (), ip);
4437 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
4438 ip += 2;
4439 MINT_IN_BREAK;
4441 MINT_IN_CASE(MINT_GETCHR) {
4442 MonoString *s;
4443 s = (MonoString*)sp [-2].data.p;
4444 if (!s)
4445 THROW_EX (mono_get_exception_null_reference (), ip);
4446 i32 = sp [-1].data.i;
4447 if (i32 < 0 || i32 >= mono_string_length (s))
4448 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4449 --sp;
4450 sp [-1].data.i = mono_string_chars(s)[i32];
4451 ++ip;
4452 MINT_IN_BREAK;
4454 MINT_IN_CASE(MINT_GETITEM_SPAN) {
4455 guint8 *span = (guint8 *) sp [-2].data.p;
4456 int index = sp [-1].data.i;
4457 gsize element_size = (gsize) *(gint16 *) (ip + 1);
4458 gsize offset_length = (gsize) *(gint16 *) (ip + 2);
4459 gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
4460 sp--;
4462 if (!span)
4463 THROW_EX (mono_get_exception_null_reference (), ip);
4465 gint32 length = *(gint32 *) (span + offset_length);
4466 if (index < 0 || index >= length)
4467 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4469 gpointer pointer = *(gpointer *)(span + offset_pointer);
4470 sp [-1].data.p = (guint8 *) pointer + index * element_size;
4472 ip += 4;
4473 MINT_IN_BREAK;
4475 MINT_IN_CASE(MINT_STRLEN)
4476 ++ip;
4477 o = sp [-1].data.o;
4478 if (!o)
4479 THROW_EX (mono_get_exception_null_reference (), ip);
4480 sp [-1].data.i = mono_string_length ((MonoString*) o);
4481 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_ARRAY_RANK)
4483 o = sp [-1].data.o;
4484 if (!o)
4485 THROW_EX (mono_get_exception_null_reference (), ip);
4486 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
4487 ip++;
4488 MINT_IN_BREAK;
4489 MINT_IN_CASE(MINT_LDELEMA)
4490 MINT_IN_CASE(MINT_LDELEMA_TC) {
4491 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
4493 MonoClass *klass = (MonoClass*)rtm->data_items [*(guint16 *) (ip + 1)];
4494 guint16 numargs = *(guint16 *) (ip + 2);
4495 ip += 3;
4496 sp -= numargs;
4498 o = sp [0].data.o;
4499 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
4500 if (frame->ex)
4501 THROW_EX (frame->ex, ip);
4502 ++sp;
4504 MINT_IN_BREAK;
4506 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4507 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4508 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4509 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4510 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4511 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4512 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
4513 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
4514 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4515 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4516 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4517 MINT_IN_CASE(MINT_LDELEM_VT) {
4518 MonoArray *o;
4519 mono_u aindex;
4521 sp -= 2;
4523 o = (MonoArray*)sp [0].data.p;
4524 if (!o)
4525 THROW_EX (mono_get_exception_null_reference (), ip);
4527 aindex = sp [1].data.i;
4528 if (aindex >= mono_array_length_fast (o))
4529 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4532 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4534 switch (*ip) {
4535 case MINT_LDELEM_I1:
4536 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
4537 break;
4538 case MINT_LDELEM_U1:
4539 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
4540 break;
4541 case MINT_LDELEM_I2:
4542 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
4543 break;
4544 case MINT_LDELEM_U2:
4545 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
4546 break;
4547 case MINT_LDELEM_I:
4548 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
4549 break;
4550 case MINT_LDELEM_I4:
4551 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
4552 break;
4553 case MINT_LDELEM_U4:
4554 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
4555 break;
4556 case MINT_LDELEM_I8:
4557 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
4558 break;
4559 case MINT_LDELEM_R4:
4560 sp [0].data.f = mono_array_get_fast (o, float, aindex);
4561 break;
4562 case MINT_LDELEM_R8:
4563 sp [0].data.f = mono_array_get_fast (o, double, aindex);
4564 break;
4565 case MINT_LDELEM_REF:
4566 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
4567 break;
4568 case MINT_LDELEM_VT: {
4569 MonoClass *klass_vt = (MonoClass*)rtm->data_items [*(guint16 *) (ip + 1)];
4570 i32 = READ32 (ip + 2);
4571 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
4572 sp [0].data.vt = vt_sp;
4573 stackval_from_data (m_class_get_byval_arg (klass_vt), sp, src_addr, FALSE);
4574 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4575 ip += 3;
4576 break;
4578 default:
4579 ves_abort();
4582 ++ip;
4583 ++sp;
4584 MINT_IN_BREAK;
4586 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
4587 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4588 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4589 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4590 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4591 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4592 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4593 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4594 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4595 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4596 MINT_IN_CASE(MINT_STELEM_VT) {
4597 mono_u aindex;
4599 sp -= 3;
4601 o = sp [0].data.o;
4602 if (!o)
4603 THROW_EX (mono_get_exception_null_reference (), ip);
4605 aindex = sp [1].data.i;
4606 if (aindex >= mono_array_length_fast ((MonoArray *)o))
4607 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4609 switch (*ip) {
4610 case MINT_STELEM_I:
4611 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4612 break;
4613 case MINT_STELEM_I1:
4614 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4615 break;
4616 case MINT_STELEM_U1:
4617 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4618 break;
4619 case MINT_STELEM_I2:
4620 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4621 break;
4622 case MINT_STELEM_U2:
4623 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4624 break;
4625 case MINT_STELEM_I4:
4626 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4627 break;
4628 case MINT_STELEM_I8:
4629 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4630 break;
4631 case MINT_STELEM_R4:
4632 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f);
4633 break;
4634 case MINT_STELEM_R8:
4635 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
4636 break;
4637 case MINT_STELEM_REF: {
4638 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
4639 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4640 if (sp [2].data.p && !isinst_obj)
4641 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4642 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
4643 break;
4645 case MINT_STELEM_VT: {
4646 MonoClass *klass_vt = (MonoClass*)rtm->data_items [*(guint16 *) (ip + 1)];
4647 i32 = READ32 (ip + 2);
4648 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
4650 stackval_to_data (m_class_get_byval_arg (klass_vt), &sp [2], dst_addr, FALSE);
4651 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4652 ip += 3;
4653 break;
4655 default:
4656 ves_abort();
4659 ++ip;
4660 MINT_IN_BREAK;
4662 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4663 if (sp [-1].data.i < 0)
4664 THROW_EX (mono_get_exception_overflow (), ip);
4665 ++ip;
4666 MINT_IN_BREAK;
4667 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4668 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
4669 THROW_EX (mono_get_exception_overflow (), ip);
4670 sp [-1].data.i = (gint32) sp [-1].data.l;
4671 ++ip;
4672 MINT_IN_BREAK;
4673 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4674 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
4675 THROW_EX (mono_get_exception_overflow (), ip);
4676 sp [-1].data.i = (gint32) sp [-1].data.l;
4677 ++ip;
4678 MINT_IN_BREAK;
4679 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4680 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
4681 THROW_EX (mono_get_exception_overflow (), ip);
4682 sp [-1].data.i = (gint32) sp [-1].data.f;
4683 ++ip;
4684 MINT_IN_BREAK;
4685 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4686 if (sp [-1].data.i < 0)
4687 THROW_EX (mono_get_exception_overflow (), ip);
4688 ++ip;
4689 MINT_IN_BREAK;
4690 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4691 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
4692 THROW_EX (mono_get_exception_overflow (), ip);
4693 sp [-1].data.i = (guint32) sp [-1].data.l;
4694 ++ip;
4695 MINT_IN_BREAK;
4696 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4697 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
4698 THROW_EX (mono_get_exception_overflow (), ip);
4699 sp [-1].data.i = (guint32) sp [-1].data.f;
4700 ++ip;
4701 MINT_IN_BREAK;
4702 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4703 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
4704 THROW_EX (mono_get_exception_overflow (), ip);
4705 ++ip;
4706 MINT_IN_BREAK;
4707 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
4708 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
4709 THROW_EX (mono_get_exception_overflow (), ip);
4710 ++ip;
4711 MINT_IN_BREAK;
4712 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4713 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
4714 THROW_EX (mono_get_exception_overflow (), ip);
4715 sp [-1].data.i = (gint16) sp [-1].data.l;
4716 ++ip;
4717 MINT_IN_BREAK;
4718 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
4719 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
4720 THROW_EX (mono_get_exception_overflow (), ip);
4721 sp [-1].data.i = (gint16) sp [-1].data.l;
4722 ++ip;
4723 MINT_IN_BREAK;
4724 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4725 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
4726 THROW_EX (mono_get_exception_overflow (), ip);
4727 sp [-1].data.i = (gint16) sp [-1].data.f;
4728 ++ip;
4729 MINT_IN_BREAK;
4730 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
4731 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
4732 THROW_EX (mono_get_exception_overflow (), ip);
4733 sp [-1].data.i = (gint16) sp [-1].data.f;
4734 ++ip;
4735 MINT_IN_BREAK;
4736 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4737 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
4738 THROW_EX (mono_get_exception_overflow (), ip);
4739 ++ip;
4740 MINT_IN_BREAK;
4741 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4742 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
4743 THROW_EX (mono_get_exception_overflow (), ip);
4744 sp [-1].data.i = (guint16) sp [-1].data.l;
4745 ++ip;
4746 MINT_IN_BREAK;
4747 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4748 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
4749 THROW_EX (mono_get_exception_overflow (), ip);
4750 sp [-1].data.i = (guint16) sp [-1].data.f;
4751 ++ip;
4752 MINT_IN_BREAK;
4753 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4754 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
4755 THROW_EX (mono_get_exception_overflow (), ip);
4756 ++ip;
4757 MINT_IN_BREAK;
4758 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
4759 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
4760 THROW_EX (mono_get_exception_overflow (), ip);
4761 ++ip;
4762 MINT_IN_BREAK;
4763 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4764 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
4765 THROW_EX (mono_get_exception_overflow (), ip);
4766 sp [-1].data.i = (gint8) sp [-1].data.l;
4767 ++ip;
4768 MINT_IN_BREAK;
4769 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
4770 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
4771 THROW_EX (mono_get_exception_overflow (), ip);
4772 sp [-1].data.i = (gint8) sp [-1].data.l;
4773 ++ip;
4774 MINT_IN_BREAK;
4775 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4776 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
4777 THROW_EX (mono_get_exception_overflow (), ip);
4778 sp [-1].data.i = (gint8) sp [-1].data.f;
4779 ++ip;
4780 MINT_IN_BREAK;
4781 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
4782 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
4783 THROW_EX (mono_get_exception_overflow (), ip);
4784 sp [-1].data.i = (gint8) sp [-1].data.f;
4785 ++ip;
4786 MINT_IN_BREAK;
4787 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4788 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
4789 THROW_EX (mono_get_exception_overflow (), ip);
4790 ++ip;
4791 MINT_IN_BREAK;
4792 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4793 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
4794 THROW_EX (mono_get_exception_overflow (), ip);
4795 sp [-1].data.i = (guint8) sp [-1].data.l;
4796 ++ip;
4797 MINT_IN_BREAK;
4798 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4799 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
4800 THROW_EX (mono_get_exception_overflow (), ip);
4801 sp [-1].data.i = (guint8) sp [-1].data.f;
4802 ++ip;
4803 MINT_IN_BREAK;
4804 #if 0
4805 MINT_IN_CASE(MINT_LDELEM)
4806 MINT_IN_CASE(MINT_STELEM)
4807 MINT_IN_CASE(MINT_UNBOX_ANY)
4808 #endif
4809 MINT_IN_CASE(MINT_CKFINITE)
4810 if (!isfinite(sp [-1].data.f))
4811 THROW_EX (mono_get_exception_arithmetic (), ip);
4812 ++ip;
4813 MINT_IN_BREAK;
4814 MINT_IN_CASE(MINT_MKREFANY) {
4815 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
4817 /* The value address is on the stack */
4818 gpointer addr = sp [-1].data.p;
4819 /* Push the typedref value on the stack */
4820 sp [-1].data.p = vt_sp;
4821 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
4823 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
4824 tref->klass = c;
4825 tref->type = m_class_get_byval_arg (c);
4826 tref->value = addr;
4828 ip += 2;
4829 MINT_IN_BREAK;
4831 MINT_IN_CASE(MINT_REFANYTYPE) {
4832 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
4833 MonoType *type = tref->type;
4835 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
4836 sp [-1].data.p = vt_sp;
4837 vt_sp += 8;
4838 *(gpointer*)sp [-1].data.p = type;
4839 ip ++;
4840 MINT_IN_BREAK;
4842 MINT_IN_CASE(MINT_REFANYVAL) {
4843 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
4844 gpointer addr = tref->value;
4846 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
4847 if (c != tref->klass)
4848 THROW_EX (mono_get_exception_invalid_cast (), ip);
4850 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
4852 sp [-1].data.p = addr;
4853 ip += 2;
4854 MINT_IN_BREAK;
4856 MINT_IN_CASE(MINT_LDTOKEN)
4857 sp->data.p = vt_sp;
4858 vt_sp += 8;
4859 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4860 ip += 2;
4861 ++sp;
4862 MINT_IN_BREAK;
4863 MINT_IN_CASE(MINT_ADD_OVF_I4)
4864 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4865 THROW_EX (mono_get_exception_overflow (), ip);
4866 BINOP(i, +);
4867 MINT_IN_BREAK;
4868 MINT_IN_CASE(MINT_ADD_OVF_I8)
4869 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4870 THROW_EX (mono_get_exception_overflow (), ip);
4871 BINOP(l, +);
4872 MINT_IN_BREAK;
4873 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4874 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4875 THROW_EX (mono_get_exception_overflow (), ip);
4876 BINOP_CAST(i, +, guint32);
4877 MINT_IN_BREAK;
4878 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4879 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4880 THROW_EX (mono_get_exception_overflow (), ip);
4881 BINOP_CAST(l, +, guint64);
4882 MINT_IN_BREAK;
4883 MINT_IN_CASE(MINT_MUL_OVF_I4)
4884 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4885 THROW_EX (mono_get_exception_overflow (), ip);
4886 BINOP(i, *);
4887 MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_MUL_OVF_I8)
4889 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4890 THROW_EX (mono_get_exception_overflow (), ip);
4891 BINOP(l, *);
4892 MINT_IN_BREAK;
4893 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4894 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4895 THROW_EX (mono_get_exception_overflow (), ip);
4896 BINOP_CAST(i, *, guint32);
4897 MINT_IN_BREAK;
4898 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4899 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4900 THROW_EX (mono_get_exception_overflow (), ip);
4901 BINOP_CAST(l, *, guint64);
4902 MINT_IN_BREAK;
4903 MINT_IN_CASE(MINT_SUB_OVF_I4)
4904 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4905 THROW_EX (mono_get_exception_overflow (), ip);
4906 BINOP(i, -);
4907 MINT_IN_BREAK;
4908 MINT_IN_CASE(MINT_SUB_OVF_I8)
4909 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4910 THROW_EX (mono_get_exception_overflow (), ip);
4911 BINOP(l, -);
4912 MINT_IN_BREAK;
4913 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4914 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4915 THROW_EX (mono_get_exception_overflow (), ip);
4916 BINOP_CAST(i, -, guint32);
4917 MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4919 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4920 THROW_EX (mono_get_exception_overflow (), ip);
4921 BINOP_CAST(l, -, guint64);
4922 MINT_IN_BREAK;
4923 MINT_IN_CASE(MINT_START_ABORT_PROT)
4924 mono_threads_begin_abort_protected_block ();
4925 ip ++;
4926 MINT_IN_BREAK;
4927 MINT_IN_CASE(MINT_ENDFINALLY) {
4928 ip ++;
4929 int clause_index = *ip;
4930 gboolean pending_abort = mono_threads_end_abort_protected_block ();
4932 if (clause_index == exit_at_finally)
4933 goto exit_frame;
4934 while (sp > frame->stack) {
4935 --sp;
4937 if (finally_ips) {
4938 ip = (const guint16*)finally_ips->data;
4939 finally_ips = g_slist_remove (finally_ips, ip);
4940 /* Throw abort after the last finally block to avoid confusing EH */
4941 if (pending_abort && !finally_ips)
4942 EXCEPTION_CHECKPOINT;
4943 goto main_loop;
4945 ves_abort();
4946 MINT_IN_BREAK;
4949 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4950 MINT_IN_CASE(MINT_LEAVE_S)
4951 while (sp > frame->stack) {
4952 --sp;
4954 frame->ip = ip;
4956 if (*ip == MINT_LEAVE_S) {
4957 ip += (short) *(ip + 1);
4958 } else {
4959 ip += (gint32) READ32 (ip + 1);
4961 endfinally_ip = ip;
4962 goto handle_finally;
4963 MINT_IN_BREAK;
4964 MINT_IN_CASE(MINT_LEAVE_CHECK)
4965 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
4966 while (sp > frame->stack) {
4967 --sp;
4969 frame->ip = ip;
4971 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4972 frame->ex_handler = NULL;
4973 frame->ex = NULL;
4976 if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4977 stackval tmp_sp;
4979 child_frame.parent = frame;
4980 child_frame.imethod = NULL;
4982 * We need for mono_thread_get_undeniable_exception to be able to unwind
4983 * to check the abort threshold. For this to work we use child_frame as a
4984 * dummy frame that is stored in the lmf and serves as the transition frame
4986 context->current_frame = &child_frame;
4987 do_icall (context, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception);
4988 context->current_frame = frame;
4990 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
4991 if (abort_exc)
4992 THROW_EX (abort_exc, frame->ip);
4995 if (*ip == MINT_LEAVE_S_CHECK) {
4996 ip += (short) *(ip + 1);
4997 } else {
4998 ip += (gint32) READ32 (ip + 1);
5000 endfinally_ip = ip;
5001 goto handle_finally;
5002 MINT_IN_BREAK;
5003 MINT_IN_CASE(MINT_ICALL_V_V)
5004 MINT_IN_CASE(MINT_ICALL_V_P)
5005 MINT_IN_CASE(MINT_ICALL_P_V)
5006 MINT_IN_CASE(MINT_ICALL_P_P)
5007 MINT_IN_CASE(MINT_ICALL_PP_V)
5008 MINT_IN_CASE(MINT_ICALL_PP_P)
5009 MINT_IN_CASE(MINT_ICALL_PPP_V)
5010 MINT_IN_CASE(MINT_ICALL_PPP_P)
5011 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5012 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5013 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5014 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5015 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5016 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5017 frame->ip = ip;
5018 sp = do_icall (context, NULL, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
5019 EXCEPTION_CHECKPOINT;
5020 if (context->has_resume_state) {
5021 if (frame == context->handler_frame)
5022 SET_RESUME_STATE (context);
5023 else
5024 goto exit_frame;
5026 ip += 2;
5027 MINT_IN_BREAK;
5028 MINT_IN_CASE(MINT_MONO_LDPTR)
5029 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
5030 ip += 2;
5031 ++sp;
5032 MINT_IN_BREAK;
5033 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5034 sp->data.p = mono_object_new_checked (rtm->domain, (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)], error);
5035 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5036 ip += 2;
5037 sp++;
5038 MINT_IN_BREAK;
5039 MINT_IN_CASE(MINT_MONO_FREE)
5040 ++ip;
5041 --sp;
5042 g_error ("that doesn't seem right");
5043 g_free (sp->data.p);
5044 MINT_IN_BREAK;
5045 MINT_IN_CASE(MINT_MONO_RETOBJ)
5046 ++ip;
5047 sp--;
5048 stackval_from_data (mono_method_signature (frame->imethod->method)->ret, frame->retval, sp->data.p,
5049 mono_method_signature (frame->imethod->method)->pinvoke);
5050 if (sp > frame->stack)
5051 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5052 goto exit_frame;
5053 MINT_IN_CASE(MINT_MONO_TLS) {
5054 MonoTlsKey key = (MonoTlsKey)*(gint32 *)(ip + 1);
5055 sp->data.p = ((gpointer (*)(void)) mono_tls_get_tls_getter (key, FALSE)) ();
5056 sp++;
5057 ip += 3;
5058 MINT_IN_BREAK;
5060 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5061 ++ip;
5062 mono_memory_barrier ();
5063 MINT_IN_BREAK;
5065 MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
5066 ++ip;
5068 context->original_domain = NULL;
5069 MonoDomain *tls_domain = (MonoDomain *) mono_tls_get_domain ();
5070 gpointer tls_jit = mono_tls_get_jit_tls ();
5072 if (tls_domain != rtm->domain || !tls_jit) {
5073 context->original_domain = mono_jit_thread_attach (rtm->domain);
5075 * Make sure the JitTlsData contains the interp context, in case
5076 * we weren't yet attached at interp_entry time.
5078 g_assert (context == mono_native_tls_get_value (thread_context_id));
5079 set_context (context);
5081 MINT_IN_BREAK;
5083 MINT_IN_CASE(MINT_MONO_JIT_DETACH)
5084 ++ip;
5085 mono_jit_set_domain (context->original_domain);
5086 MINT_IN_BREAK;
5087 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5088 sp->data.p = mono_domain_get ();
5089 ++sp;
5090 ++ip;
5091 MINT_IN_BREAK;
5092 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5093 if (G_UNLIKELY (ss_enabled)) {
5094 typedef void (*T) (void);
5095 static T ss_tramp;
5097 if (!ss_tramp) {
5098 void *tramp = mini_get_single_step_trampoline ();
5099 mono_memory_barrier ();
5100 ss_tramp = (T)tramp;
5104 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5105 * the address of that instruction is stored as the seq point address.
5107 frame->ip = ip + 1;
5110 * Use the same trampoline as the JIT. This ensures that
5111 * the debugger has the context for the last interpreter
5112 * native frame.
5114 do_debugger_tramp (ss_tramp, frame);
5116 if (context->has_resume_state) {
5117 if (frame == context->handler_frame)
5118 SET_RESUME_STATE (context);
5119 else
5120 goto exit_frame;
5123 ++ip;
5124 MINT_IN_BREAK;
5125 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5126 /* Just a placeholder for a breakpoint */
5127 ++ip;
5128 MINT_IN_BREAK;
5129 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
5130 typedef void (*T) (void);
5131 static T bp_tramp;
5132 if (!bp_tramp) {
5133 void *tramp = mini_get_breakpoint_trampoline ();
5134 mono_memory_barrier ();
5135 bp_tramp = (T)tramp;
5138 frame->ip = ip;
5140 /* Use the same trampoline as the JIT */
5141 do_debugger_tramp (bp_tramp, frame);
5143 if (context->has_resume_state) {
5144 if (frame == context->handler_frame)
5145 SET_RESUME_STATE (context);
5146 else
5147 goto exit_frame;
5150 ++ip;
5151 MINT_IN_BREAK;
5154 #define RELOP(datamem, op) \
5155 --sp; \
5156 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5157 ++ip;
5159 #define RELOP_FP(datamem, op, noorder) \
5160 --sp; \
5161 if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5162 sp [-1].data.i = noorder; \
5163 else \
5164 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5165 ++ip;
5167 MINT_IN_CASE(MINT_CEQ_I4)
5168 RELOP(i, ==);
5169 MINT_IN_BREAK;
5170 MINT_IN_CASE(MINT_CEQ0_I4)
5171 sp [-1].data.i = (sp [-1].data.i == 0);
5172 ++ip;
5173 MINT_IN_BREAK;
5174 MINT_IN_CASE(MINT_CEQ_I8)
5175 RELOP(l, ==);
5176 MINT_IN_BREAK;
5177 MINT_IN_CASE(MINT_CEQ_R8)
5178 RELOP_FP(f, ==, 0);
5179 MINT_IN_BREAK;
5180 MINT_IN_CASE(MINT_CNE_I4)
5181 RELOP(i, !=);
5182 MINT_IN_BREAK;
5183 MINT_IN_CASE(MINT_CNE_I8)
5184 RELOP(l, !=);
5185 MINT_IN_BREAK;
5186 MINT_IN_CASE(MINT_CNE_R8)
5187 RELOP_FP(f, !=, 1);
5188 MINT_IN_BREAK;
5189 MINT_IN_CASE(MINT_CGT_I4)
5190 RELOP(i, >);
5191 MINT_IN_BREAK;
5192 MINT_IN_CASE(MINT_CGT_I8)
5193 RELOP(l, >);
5194 MINT_IN_BREAK;
5195 MINT_IN_CASE(MINT_CGT_R8)
5196 RELOP_FP(f, >, 0);
5197 MINT_IN_BREAK;
5198 MINT_IN_CASE(MINT_CGE_I4)
5199 RELOP(i, >=);
5200 MINT_IN_BREAK;
5201 MINT_IN_CASE(MINT_CGE_I8)
5202 RELOP(l, >=);
5203 MINT_IN_BREAK;
5204 MINT_IN_CASE(MINT_CGE_R8)
5205 RELOP_FP(f, >=, 0);
5206 MINT_IN_BREAK;
5208 #define RELOP_CAST(datamem, op, type) \
5209 --sp; \
5210 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5211 ++ip;
5213 MINT_IN_CASE(MINT_CGE_UN_I4)
5214 RELOP_CAST(l, >=, guint32);
5215 MINT_IN_BREAK;
5216 MINT_IN_CASE(MINT_CGE_UN_I8)
5217 RELOP_CAST(l, >=, guint64);
5218 MINT_IN_BREAK;
5220 MINT_IN_CASE(MINT_CGT_UN_I4)
5221 RELOP_CAST(i, >, guint32);
5222 MINT_IN_BREAK;
5223 MINT_IN_CASE(MINT_CGT_UN_I8)
5224 RELOP_CAST(l, >, guint64);
5225 MINT_IN_BREAK;
5226 MINT_IN_CASE(MINT_CGT_UN_R8)
5227 RELOP_FP(f, >, 1);
5228 MINT_IN_BREAK;
5229 MINT_IN_CASE(MINT_CLT_I4)
5230 RELOP(i, <);
5231 MINT_IN_BREAK;
5232 MINT_IN_CASE(MINT_CLT_I8)
5233 RELOP(l, <);
5234 MINT_IN_BREAK;
5235 MINT_IN_CASE(MINT_CLT_R8)
5236 RELOP_FP(f, <, 0);
5237 MINT_IN_BREAK;
5238 MINT_IN_CASE(MINT_CLT_UN_I4)
5239 RELOP_CAST(i, <, guint32);
5240 MINT_IN_BREAK;
5241 MINT_IN_CASE(MINT_CLT_UN_I8)
5242 RELOP_CAST(l, <, guint64);
5243 MINT_IN_BREAK;
5244 MINT_IN_CASE(MINT_CLT_UN_R8)
5245 RELOP_FP(f, <, 1);
5246 MINT_IN_BREAK;
5247 MINT_IN_CASE(MINT_CLE_I4)
5248 RELOP(i, <=);
5249 MINT_IN_BREAK;
5250 MINT_IN_CASE(MINT_CLE_I8)
5251 RELOP(l, <=);
5252 MINT_IN_BREAK;
5253 MINT_IN_CASE(MINT_CLE_UN_I4)
5254 RELOP_CAST(l, <=, guint32);
5255 MINT_IN_BREAK;
5256 MINT_IN_CASE(MINT_CLE_UN_I8)
5257 RELOP_CAST(l, <=, guint64);
5258 MINT_IN_BREAK;
5259 MINT_IN_CASE(MINT_CLE_R8)
5260 RELOP_FP(f, <=, 0);
5261 MINT_IN_BREAK;
5263 #undef RELOP
5264 #undef RELOP_FP
5265 #undef RELOP_CAST
5267 MINT_IN_CASE(MINT_LDFTN) {
5268 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
5269 ++sp;
5270 ip += 2;
5271 MINT_IN_BREAK;
5273 MINT_IN_CASE(MINT_LDVIRTFTN) {
5274 InterpMethod *m = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
5275 ip += 2;
5276 --sp;
5277 if (!sp->data.p)
5278 THROW_EX (mono_get_exception_null_reference (), ip - 2);
5280 sp->data.p = get_virtual_method (m, sp->data.o);
5281 ++sp;
5282 MINT_IN_BREAK;
5285 #define LDARG(datamem, argtype) \
5286 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
5287 ip += 2; \
5288 ++sp;
5290 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
5291 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
5292 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
5293 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
5294 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
5295 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
5296 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
5297 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
5298 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
5299 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
5301 MINT_IN_CASE(MINT_LDARG_VT)
5302 sp->data.p = vt_sp;
5303 i32 = READ32(ip + 2);
5304 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
5305 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5306 ip += 4;
5307 ++sp;
5308 MINT_IN_BREAK;
5310 #define STARG(datamem, argtype) \
5311 --sp; \
5312 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5313 ip += 2; \
5315 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
5316 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
5317 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
5318 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
5319 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
5320 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
5321 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
5322 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
5323 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
5324 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
5326 MINT_IN_CASE(MINT_STARG_VT)
5327 i32 = READ32(ip + 2);
5328 --sp;
5329 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
5330 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5331 ip += 4;
5332 MINT_IN_BREAK;
5334 #define STINARG(datamem, argtype) \
5335 do { \
5336 int n = * (guint16 *)(ip + 1); \
5337 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
5338 ip += 2; \
5339 } while (0)
5341 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
5342 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
5343 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
5344 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
5345 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
5346 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
5347 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
5348 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
5349 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
5350 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
5352 MINT_IN_CASE(MINT_STINARG_VT) {
5353 int n = * (guint16 *)(ip + 1);
5354 i32 = READ32(ip + 2);
5355 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
5356 ip += 4;
5357 MINT_IN_BREAK;
5360 MINT_IN_CASE(MINT_PROF_ENTER) {
5361 ip += 1;
5363 if (MONO_PROFILER_ENABLED (method_enter)) {
5364 MonoProfilerCallContext *prof_ctx = NULL;
5366 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
5367 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
5368 prof_ctx->interp_frame = frame;
5369 prof_ctx->method = frame->imethod->method;
5372 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
5374 g_free (prof_ctx);
5377 MINT_IN_BREAK;
5380 MINT_IN_CASE(MINT_LDARGA)
5381 sp->data.p = frame->args + * (guint16 *)(ip + 1);
5382 ip += 2;
5383 ++sp;
5384 MINT_IN_BREAK;
5386 #define LDLOC(datamem, argtype) \
5387 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
5388 ip += 2; \
5389 ++sp;
5391 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
5392 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
5393 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
5394 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
5395 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
5396 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
5397 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
5398 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
5399 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
5400 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
5402 MINT_IN_CASE(MINT_LDLOC_VT)
5403 sp->data.p = vt_sp;
5404 i32 = READ32(ip + 2);
5405 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
5406 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5407 ip += 4;
5408 ++sp;
5409 MINT_IN_BREAK;
5411 MINT_IN_CASE(MINT_LDLOCA_S)
5412 sp->data.p = locals + * (guint16 *)(ip + 1);
5413 ip += 2;
5414 ++sp;
5415 MINT_IN_BREAK;
5417 #define STLOC(datamem, argtype) \
5418 --sp; \
5419 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5420 ip += 2;
5422 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
5423 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
5424 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
5425 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
5426 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
5427 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
5428 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
5429 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
5430 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
5431 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
5433 #define STLOC_NP(datamem, argtype) \
5434 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
5435 ip += 2;
5437 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
5438 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
5440 MINT_IN_CASE(MINT_STLOC_VT)
5441 i32 = READ32(ip + 2);
5442 --sp;
5443 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
5444 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5445 ip += 4;
5446 MINT_IN_BREAK;
5448 MINT_IN_CASE(MINT_LOCALLOC) {
5449 if (sp != frame->stack + 1) /*FIX?*/
5450 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
5452 int len = sp [-1].data.i;
5453 sp [-1].data.p = alloca (len);
5455 if (frame->imethod->init_locals)
5456 memset (sp [-1].data.p, 0, len);
5457 ++ip;
5458 MINT_IN_BREAK;
5460 MINT_IN_CASE(MINT_ENDFILTER)
5461 /* top of stack is result of filter */
5462 frame->retval = &sp [-1];
5463 goto exit_frame;
5464 MINT_IN_CASE(MINT_INITOBJ)
5465 --sp;
5466 memset (sp->data.vt, 0, READ32(ip + 1));
5467 ip += 3;
5468 MINT_IN_BREAK;
5469 MINT_IN_CASE(MINT_CPBLK)
5470 sp -= 3;
5471 if (!sp [0].data.p || !sp [1].data.p)
5472 THROW_EX (mono_get_exception_null_reference(), ip - 1);
5473 ++ip;
5474 /* FIXME: value and size may be int64... */
5475 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
5476 MINT_IN_BREAK;
5477 #if 0
5478 MINT_IN_CASE(MINT_CONSTRAINED_) {
5479 guint32 token;
5480 /* FIXME: implement */
5481 ++ip;
5482 token = READ32 (ip);
5483 ip += 2;
5484 MINT_IN_BREAK;
5486 #endif
5487 MINT_IN_CASE(MINT_INITBLK)
5488 sp -= 3;
5489 if (!sp [0].data.p)
5490 THROW_EX (mono_get_exception_null_reference(), ip - 1);
5491 ++ip;
5492 /* FIXME: value and size may be int64... */
5493 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
5494 MINT_IN_BREAK;
5495 #if 0
5496 MINT_IN_CASE(MINT_NO_)
5497 /* FIXME: implement */
5498 ip += 2;
5499 MINT_IN_BREAK;
5500 #endif
5501 MINT_IN_CASE(MINT_RETHROW) {
5503 * need to clarify what this should actually do:
5504 * start the search from the last found handler in
5505 * this method or continue in the caller or what.
5506 * Also, do we need to run finally/fault handlers after a retrow?
5507 * Well, this implementation will follow the usual search
5508 * for an handler, considering the current ip as throw spot.
5509 * We need to NULL frame->ex_handler for the later code to
5510 * actually run the new found handler.
5512 int exvar_offset = *(guint16*)(ip + 1);
5513 frame->ex_handler = NULL;
5514 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip - 1, TRUE);
5515 MINT_IN_BREAK;
5517 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
5518 MonoDelegate *del;
5520 --sp;
5521 del = (MonoDelegate*)sp->data.p;
5522 if (!del->interp_method) {
5523 /* Not created from interpreted code */
5524 ERROR_DECL (error);
5525 g_assert (del->method);
5526 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
5527 mono_error_assert_ok (error);
5529 g_assert (del->interp_method);
5530 sp->data.p = del->interp_method;
5531 ++sp;
5532 ip += 1;
5533 MINT_IN_BREAK;
5535 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
5536 MonoDelegate *del;
5537 int n = *(guint16*)(ip + 1);
5538 del = (MonoDelegate*)sp [-n].data.p;
5539 if (!del->interp_invoke_impl) {
5541 * First time we are called. Set up the invoke wrapper. We might be able to do this
5542 * in ctor but we would need to handle AllocDelegateLike_internal separately
5544 ERROR_DECL (error);
5545 MonoMethod *invoke = mono_get_delegate_invoke (del->object.vtable->klass);
5546 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
5547 mono_error_assert_ok (error);
5549 sp ++;
5550 sp [-1].data.p = del->interp_invoke_impl;
5551 ip += 2;
5552 MINT_IN_BREAK;
5554 MINT_IN_DEFAULT
5555 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
5556 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
5560 g_assert_not_reached ();
5561 handle_finally:
5563 int i;
5564 guint32 ip_offset;
5565 MonoExceptionClause *clause;
5566 GSList *old_list = finally_ips;
5567 MonoMethod *method = frame->imethod->method;
5569 #if DEBUG_INTERP
5570 if (tracing)
5571 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
5572 #endif
5573 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5574 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5575 goto exit_frame;
5577 ip_offset = frame->ip - rtm->code;
5579 if (endfinally_ip != NULL)
5580 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
5581 for (i = 0; i < rtm->num_clauses; ++i)
5582 if (frame->ex_handler == &rtm->clauses [i])
5583 break;
5585 while (i > 0) {
5586 --i;
5587 clause = &rtm->clauses [i];
5588 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
5589 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5590 ip = rtm->code + clause->handler_offset;
5591 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5592 #if DEBUG_INTERP
5593 if (tracing)
5594 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5595 #endif
5600 endfinally_ip = NULL;
5602 if (old_list != finally_ips && finally_ips) {
5603 ip = (const guint16*)finally_ips->data;
5604 finally_ips = g_slist_remove (finally_ips, ip);
5605 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5606 vt_sp = (unsigned char *) sp + rtm->stack_size;
5607 goto main_loop;
5610 ves_abort();
5613 exit_frame:
5615 if (base_frame)
5616 memcpy (base_frame->args, frame->args, rtm->alloca_size);
5618 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
5619 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
5620 MonoProfilerCallContext *prof_ctx = NULL;
5622 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
5623 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
5624 prof_ctx->interp_frame = frame;
5625 prof_ctx->method = frame->imethod->method;
5627 MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
5629 switch (rtype->type) {
5630 case MONO_TYPE_VOID:
5631 break;
5632 case MONO_TYPE_VALUETYPE:
5633 prof_ctx->return_value = frame->retval->data.p;
5634 break;
5635 default:
5636 prof_ctx->return_value = frame->retval;
5637 break;
5641 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
5643 g_free (prof_ctx);
5644 } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
5645 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
5647 DEBUG_LEAVE ();
5650 static void
5651 interp_parse_options (const char *options)
5653 char **args, **ptr;
5655 if (!options)
5656 return;
5658 args = g_strsplit (options, ",", -1);
5659 for (ptr = args; ptr && *ptr; ptr ++) {
5660 char *arg = *ptr;
5662 if (strncmp (arg, "jit=", 4) == 0)
5663 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
5664 if (strncmp (arg, "interp-only=", 4) == 0)
5665 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
5669 typedef int (*TestMethod) (void);
5672 * interp_set_resume_state:
5674 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5676 static void
5677 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
5679 ThreadContext *context;
5681 g_assert (jit_tls);
5682 context = (ThreadContext*)jit_tls->interp_context;
5683 g_assert (context);
5685 context->has_resume_state = TRUE;
5686 context->handler_frame = (InterpFrame*)interp_frame;
5687 context->handler_ei = ei;
5688 /* This is on the stack, so it doesn't need a wbarrier */
5689 context->handler_frame->ex = ex;
5690 /* Ditto */
5691 if (ei)
5692 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
5693 context->handler_ip = handler_ip;
5697 * interp_run_finally:
5699 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5700 * frame->interp_frame.
5701 * Return TRUE if the finally clause threw an exception.
5703 static gboolean
5704 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5706 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
5707 ThreadContext *context = (ThreadContext*)mono_native_tls_get_value (thread_context_id);
5708 const unsigned short *old_ip = iframe->ip;
5711 interp_exec_method_full (iframe, context, (guint16*)handler_ip, NULL, clause_index, NULL);
5712 if (context->has_resume_state) {
5713 return TRUE;
5714 } else {
5715 iframe->ip = old_ip;
5716 return FALSE;
5721 * interp_run_filter:
5723 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
5724 * frame->interp_frame.
5726 static gboolean
5727 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip)
5729 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
5730 ThreadContext *context = (ThreadContext*)mono_native_tls_get_value (thread_context_id);
5731 InterpFrame child_frame;
5732 stackval retval;
5735 * Have to run the clause in a new frame which is a copy of IFRAME, since
5736 * during debugging, there are two copies of the frame on the stack.
5738 memset (&child_frame, 0, sizeof (InterpFrame));
5739 child_frame.imethod = iframe->imethod;
5740 child_frame.retval = &retval;
5741 child_frame.parent = iframe;
5743 interp_exec_method_full (&child_frame, context, (guint16*)handler_ip, ex, clause_index, iframe);
5744 /* ENDFILTER stores the result into child_frame->retval */
5745 return child_frame.retval->data.i ? TRUE : FALSE;
5748 typedef struct {
5749 InterpFrame *current;
5750 } StackIter;
5753 * interp_frame_iter_init:
5755 * Initialize an iterator for iterating through interpreted frames.
5757 static void
5758 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5760 StackIter *stack_iter = (StackIter*)iter;
5762 stack_iter->current = (InterpFrame*)interp_exit_data;
5766 * interp_frame_iter_next:
5768 * Fill out FRAME with date for the next interpreter frame.
5770 static gboolean
5771 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5773 StackIter *stack_iter = (StackIter*)iter;
5774 InterpFrame *iframe = stack_iter->current;
5776 memset (frame, 0, sizeof (StackFrameInfo));
5777 /* pinvoke frames doesn't have imethod set */
5778 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
5779 iframe = iframe->parent;
5780 if (!iframe)
5781 return FALSE;
5783 MonoMethod *method = iframe->imethod->method;
5784 frame->domain = iframe->domain;
5785 frame->interp_frame = iframe;
5786 frame->method = method;
5787 frame->actual_method = method;
5788 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
5789 frame->native_offset = -1;
5790 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
5791 } else {
5792 frame->type = FRAME_TYPE_INTERP;
5793 /* This is the offset in the interpreter IR */
5794 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
5795 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
5796 frame->managed = TRUE;
5798 frame->ji = iframe->imethod->jinfo;
5799 frame->frame_addr = iframe;
5801 stack_iter->current = iframe->parent;
5803 return TRUE;
5806 static MonoJitInfo*
5807 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
5809 InterpMethod* rtm;
5811 rtm = lookup_imethod (domain, method);
5812 if (rtm)
5813 return rtm->jinfo;
5814 else
5815 return NULL;
5818 static void
5819 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5821 guint16 *code = (guint16*)ip;
5822 g_assert (*code == MINT_SDB_SEQ_POINT);
5823 *code = MINT_SDB_BREAKPOINT;
5826 static void
5827 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5829 guint16 *code = (guint16*)ip;
5830 g_assert (*code == MINT_SDB_BREAKPOINT);
5831 *code = MINT_SDB_SEQ_POINT;
5834 static MonoJitInfo*
5835 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
5837 InterpFrame *iframe = (InterpFrame*)frame;
5839 g_assert (iframe->imethod);
5840 return iframe->imethod->jinfo;
5843 static gpointer
5844 interp_frame_get_ip (MonoInterpFrameHandle frame)
5846 InterpFrame *iframe = (InterpFrame*)frame;
5848 g_assert (iframe->imethod);
5849 return (gpointer)iframe->ip;
5852 static gpointer
5853 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
5855 InterpFrame *iframe = (InterpFrame*)frame;
5857 g_assert (iframe->imethod);
5859 int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)];
5861 return iframe->args + arg_offset;
5864 static gpointer
5865 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
5867 InterpFrame *iframe = (InterpFrame*)frame;
5869 g_assert (iframe->imethod);
5871 return iframe->locals + iframe->imethod->local_offsets [pos];
5874 static gpointer
5875 interp_frame_get_this (MonoInterpFrameHandle frame)
5877 InterpFrame *iframe = (InterpFrame*)frame;
5879 g_assert (iframe->imethod);
5880 g_assert (iframe->imethod->hasthis);
5882 int arg_offset = iframe->imethod->arg_offsets [0];
5884 return iframe->args + arg_offset;
5887 static MonoInterpFrameHandle
5888 interp_frame_get_parent (MonoInterpFrameHandle frame)
5890 InterpFrame *iframe = (InterpFrame*)frame;
5892 return iframe->parent;
5895 static void
5896 interp_start_single_stepping (void)
5898 ss_enabled = TRUE;
5901 static void
5902 interp_stop_single_stepping (void)
5904 ss_enabled = FALSE;
5907 void
5908 mono_ee_interp_init (const char *opts)
5910 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
5911 g_assert (!interp_init_done);
5912 interp_init_done = TRUE;
5914 mono_native_tls_alloc (&thread_context_id, NULL);
5915 set_context (NULL);
5917 interp_parse_options (opts);
5918 mono_interp_transform_init ();
5920 MonoEECallbacks c;
5921 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
5922 c.entry_from_trampoline = interp_entry_from_trampoline;
5923 #endif
5924 c.create_method_pointer = interp_create_method_pointer;
5925 c.runtime_invoke = interp_runtime_invoke;
5926 c.init_delegate = interp_init_delegate;
5927 c.delegate_ctor = interp_delegate_ctor;
5928 c.get_remoting_invoke = interp_get_remoting_invoke;
5929 c.set_resume_state = interp_set_resume_state;
5930 c.run_finally = interp_run_finally;
5931 c.run_filter = interp_run_filter;
5932 c.frame_iter_init = interp_frame_iter_init;
5933 c.frame_iter_next = interp_frame_iter_next;
5934 c.find_jit_info = interp_find_jit_info;
5935 c.set_breakpoint = interp_set_breakpoint;
5936 c.clear_breakpoint = interp_clear_breakpoint;
5937 c.frame_get_jit_info = interp_frame_get_jit_info;
5938 c.frame_get_ip = interp_frame_get_ip;
5939 c.frame_get_arg = interp_frame_get_arg;
5940 c.frame_get_local = interp_frame_get_local;
5941 c.frame_get_this = interp_frame_get_this;
5942 c.frame_get_parent = interp_frame_get_parent;
5943 c.frame_arg_to_data = interp_frame_arg_to_data;
5944 c.data_to_frame_arg = interp_data_to_frame_arg;
5945 c.frame_arg_to_storage = interp_frame_arg_to_storage;
5946 c.frame_arg_set_storage = interp_frame_arg_set_storage;
5947 c.start_single_stepping = interp_start_single_stepping;
5948 c.stop_single_stepping = interp_stop_single_stepping;
5949 mini_install_interp_callbacks (&c);