[interp] Cleanup: Replace retval-> with result. and retval with &result. (#18951)
[mono-project.git] / mono / mini / interp / interp.c
blob4aa8e5d115fbf6e1e67d53fd9bee66c02efb597b
1 /**
2 * \file
4 * interp.c: Interpreter for CIL byte codes
6 * Authors:
7 * Paolo Molaro (lupus@ximian.com)
8 * Miguel de Icaza (miguel@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2001, 2002 Ximian, Inc.
13 #ifndef __USE_ISOC99
14 #define __USE_ISOC99
15 #endif
16 #include "config.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <math.h>
23 #include <locale.h>
25 #include <mono/utils/gc_wrapper.h>
26 #include <mono/utils/mono-math.h>
27 #include <mono/utils/mono-counters.h>
28 #include <mono/utils/mono-tls-inline.h>
29 #include <mono/utils/mono-membar.h>
31 #ifdef HAVE_ALLOCA_H
32 # include <alloca.h>
33 #else
34 # ifdef __CYGWIN__
35 # define alloca __builtin_alloca
36 # endif
37 #endif
39 /* trim excessive headers */
40 #include <mono/metadata/image.h>
41 #include <mono/metadata/assembly-internals.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/metadata/mono-endian.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/loader.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/profiler-private.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/reflection.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/utils/atomic.h>
63 #include "interp.h"
64 #include "interp-internals.h"
65 #include "mintops.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/mini-runtime.h>
69 #include <mono/mini/aot-runtime.h>
70 #include <mono/mini/llvm-runtime.h>
71 #include <mono/mini/llvmonly-runtime.h>
72 #include <mono/mini/jit-icalls.h>
73 #include <mono/mini/debugger-agent.h>
74 #include <mono/mini/ee.h>
75 #include <mono/mini/trace.h>
77 #ifdef TARGET_ARM
78 #include <mono/mini/mini-arm.h>
79 #endif
80 #include <mono/metadata/icall-decl.h>
82 #ifdef _MSC_VER
83 #pragma warning(disable:4102) // label' : unreferenced label
84 #endif
86 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
87 struct FrameClauseArgs {
88 /* Where we start the frame execution from */
89 const guint16 *start_with_ip;
91 * End ip of the exit_clause. We need it so we know whether the resume
92 * state is for this frame (which is called from EH) or for the original
93 * frame further down the stack.
95 const guint16 *end_at_ip;
96 /* When exiting this clause we also exit the frame */
97 int exit_clause;
98 /* Exception that we are filtering */
99 MonoException *filter_exception;
100 InterpFrame *base_frame;
104 * This code synchronizes with interp_mark_stack () using compiler memory barriers.
107 static StackFragment*
108 stack_frag_new (int size)
110 StackFragment *frag = (StackFragment*)g_malloc (size);
112 frag->pos = (guint8*)&frag->data;
113 frag->end = (guint8*)frag + size;
114 frag->next = NULL;
115 return frag;
118 static void
119 frame_stack_init (FrameStack *stack, int size)
121 StackFragment *frag;
123 frag = stack_frag_new (size);
124 stack->first = stack->current = frag;
125 mono_compiler_barrier ();
126 stack->inited = 1;
129 static StackFragment*
130 add_frag (FrameStack *stack, int size)
132 StackFragment *new_frag;
134 // FIXME:
135 int frag_size = 4096;
136 if (size + sizeof (StackFragment) > frag_size)
137 frag_size = size + sizeof (StackFragment);
138 new_frag = stack_frag_new (frag_size);
139 mono_compiler_barrier ();
140 stack->current->next = new_frag;
141 stack->current = new_frag;
142 return new_frag;
145 static void
146 free_frag (StackFragment *frag)
148 while (frag) {
149 StackFragment *next = frag->next;
150 g_free (frag);
151 frag = next;
155 static MONO_ALWAYS_INLINE gpointer
156 frame_stack_alloc_ovf (FrameStack *stack, int size, StackFragment **out_frag)
158 StackFragment *current = stack->current;
159 gpointer res;
161 if (current->next && current->next->pos + size <= current->next->end) {
162 current = stack->current = current->next;
163 current->pos = (guint8*)&current->data;
164 } else {
165 StackFragment *tmp = current->next;
166 /* avoid linking to be freed fragments, so the GC can't trip over it */
167 current->next = NULL;
168 mono_compiler_barrier ();
169 free_frag (tmp);
171 current = add_frag (stack, size);
173 g_assert (current->pos + size <= current->end);
174 res = (gpointer)current->pos;
175 current->pos += size;
177 mono_compiler_barrier ();
179 if (out_frag)
180 *out_frag = current;
181 return res;
184 static MONO_ALWAYS_INLINE gpointer
185 frame_stack_alloc (FrameStack *stack, int size, StackFragment **out_frag)
187 StackFragment *current = stack->current;
188 gpointer res;
190 if (G_LIKELY (current->pos + size <= current->end)) {
191 res = current->pos;
192 current->pos += size;
193 mono_compiler_barrier ();
195 if (out_frag)
196 *out_frag = current;
197 return res;
198 } else {
199 return frame_stack_alloc_ovf (stack, size, out_frag);
203 static MONO_ALWAYS_INLINE void
204 frame_stack_pop (FrameStack *stack, StackFragment *frag, gpointer pos)
206 g_assert ((guint8*)pos >= (guint8*)&frag->data && (guint8*)pos <= (guint8*)frag->end);
207 stack->current = frag;
208 mono_compiler_barrier ();
209 stack->current->pos = (guint8*)pos;
210 mono_compiler_barrier ();
211 //memset (stack->current->pos, 0, stack->current->end - stack->current->pos);
214 static void
215 frame_stack_free (FrameStack *stack)
217 stack->inited = 0;
218 mono_compiler_barrier ();
219 free_frag (stack->first);
223 * alloc_frame:
225 * Allocate a new frame from the frame stack.
227 static InterpFrame*
228 alloc_frame (ThreadContext *ctx, gpointer native_stack_addr, InterpFrame *parent, InterpMethod *imethod, stackval *stack_args, stackval *retval)
230 StackFragment *frag;
231 InterpFrame *frame;
233 // FIXME: Add stack overflow checks
234 frame = (InterpFrame*)frame_stack_alloc (&ctx->iframe_stack, sizeof (InterpFrame), &frag);
236 frame->iframe_frag = frag;
237 frame->parent = parent;
238 frame->native_stack_addr = native_stack_addr;
239 frame->imethod = imethod;
240 frame->stack_args = stack_args;
241 frame->retval = retval;
242 frame->stack = NULL;
243 frame->ip = NULL;
244 frame->state.ip = NULL;
246 return frame;
250 * alloc_data_stack:
252 * Allocate stack space for a frame.
254 static MONO_ALWAYS_INLINE void
255 alloc_stack_data (ThreadContext *ctx, InterpFrame *frame, int size)
257 StackFragment *frag;
258 gpointer res;
260 res = frame_stack_alloc (&ctx->data_stack, size, &frag);
262 frame->stack = (stackval*)res;
263 frame->data_frag = frag;
266 static gpointer
267 alloc_extra_stack_data (ThreadContext *ctx, int size)
269 StackFragment *frag;
271 return frame_stack_alloc (&ctx->data_stack, size, &frag);
275 * pop_frame:
277 * Pop FRAME and its child frames from the frame stack.
278 * FRAME stays valid until the next alloc_frame () call.
280 static void
281 pop_frame (ThreadContext *context, InterpFrame *frame)
283 if (frame->stack)
284 frame_stack_pop (&context->data_stack, frame->data_frag, frame->stack);
285 frame_stack_pop (&context->iframe_stack, frame->iframe_frag, frame);
288 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
291 * List of classes whose methods will be executed by transitioning to JITted code.
292 * Used for testing.
294 GSList *mono_interp_jit_classes;
295 /* Optimizations enabled with interpreter */
296 int mono_interp_opt = INTERP_OPT_DEFAULT;
297 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
298 static gboolean ss_enabled;
300 static gboolean interp_init_done = FALSE;
302 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
304 static InterpMethod* lookup_method_pointer (gpointer addr);
306 typedef void (*ICallMethod) (InterpFrame *frame);
308 static MonoNativeTlsKey thread_context_id;
310 #define DEBUG_INTERP 0
311 #define COUNT_OPS 0
313 #if DEBUG_INTERP
314 int mono_interp_traceopt = 2;
315 /* If true, then we output the opcodes as we interpret them */
316 static int global_tracing = 2;
318 static int debug_indent_level = 0;
320 static int break_on_method = 0;
321 static int nested_trace = 0;
322 static GList *db_methods = NULL;
323 static char* dump_args (InterpFrame *inv);
325 static void
326 output_indent (void)
328 int h;
330 for (h = 0; h < debug_indent_level; h++)
331 g_print (" ");
334 static void
335 db_match_method (gpointer data, gpointer user_data)
337 MonoMethod *m = (MonoMethod*)user_data;
338 MonoMethodDesc *desc = (MonoMethodDesc*)data;
340 if (mono_method_desc_full_match (desc, m))
341 break_on_method = 1;
344 static void
345 debug_enter (InterpFrame *frame, int *tracing)
347 if (db_methods) {
348 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
349 if (break_on_method)
350 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
351 break_on_method = 0;
353 if (*tracing) {
354 MonoMethod *method = frame->imethod->method;
355 char *mn, *args = dump_args (frame);
356 debug_indent_level++;
357 output_indent ();
358 mn = mono_method_full_name (method, FALSE);
359 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
360 g_free (mn);
361 g_print ("%s)\n", args);
362 g_free (args);
366 #define DEBUG_LEAVE() \
367 if (tracing) { \
368 char *mn, *args; \
369 args = dump_retval (frame); \
370 output_indent (); \
371 mn = mono_method_full_name (frame->imethod->method, FALSE); \
372 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
373 g_free (mn); \
374 g_print (" => %s\n", args); \
375 g_free (args); \
376 debug_indent_level--; \
377 if (tracing == 3) global_tracing = 0; \
380 #else
382 int mono_interp_traceopt = 0;
383 #define DEBUG_LEAVE()
385 #endif
387 #if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP
388 #define USE_COMPUTED_GOTO 1
389 #endif
391 #if USE_COMPUTED_GOTO
393 #define MINT_IN_DISPATCH(op) goto *in_labels [opcode = (MintOpcode)(op)]
394 #define MINT_IN_SWITCH(op) MINT_IN_DISPATCH (op);
395 #define MINT_IN_BREAK MINT_IN_DISPATCH (*ip)
396 #define MINT_IN_CASE(x) LAB_ ## x:
398 #else
400 #define MINT_IN_SWITCH(op) COUNT_OP(op); switch (opcode = (MintOpcode)(op))
401 #define MINT_IN_CASE(x) case x:
402 #define MINT_IN_BREAK break
404 #endif
406 static GSList*
407 clear_resume_state (ThreadContext *context, GSList *finally_ips)
409 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
410 while (finally_ips &&
411 finally_ips->data >= context->handler_ei->try_start &&
412 finally_ips->data < context->handler_ei->try_end)
413 finally_ips = g_slist_remove (finally_ips, finally_ips->data);
414 context->has_resume_state = 0;
415 context->handler_frame = NULL;
416 context->handler_ei = NULL;
417 g_assert (context->exc_gchandle);
418 mono_gchandle_free_internal (context->exc_gchandle);
419 context->exc_gchandle = 0;
420 return finally_ips;
424 * If this bit is set, it means the call has thrown the exception, and we
425 * reached this point because the EH code in mono_handle_exception ()
426 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
427 * has set the fields in context to indicate where we have to resume execution.
429 #define CHECK_RESUME_STATE(context) do { \
430 if ((context)->has_resume_state) \
431 goto resume; \
432 } while (0)
434 static void
435 set_context (ThreadContext *context)
437 mono_native_tls_set_value (thread_context_id, context);
439 if (!context)
440 return;
442 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
443 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
445 /* jit_tls assumes ownership of 'context' */
446 jit_tls->interp_context = context;
449 static ThreadContext *
450 get_context (void)
452 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
453 if (context == NULL) {
454 context = g_new0 (ThreadContext, 1);
456 * Use two stacks, one for InterpFrame structures, one for data.
457 * This is useful because InterpFrame structures don't need to be GC tracked.
459 frame_stack_init (&context->iframe_stack, 8192);
460 frame_stack_init (&context->data_stack, 8192);
461 set_context (context);
463 return context;
466 static void
467 interp_free_context (gpointer ctx)
469 ThreadContext *context = (ThreadContext*)ctx;
471 frame_stack_free (&context->iframe_stack);
472 frame_stack_free (&context->data_stack);
473 g_free (context);
476 static void
477 mono_interp_error_cleanup (MonoError* error)
479 mono_error_cleanup (error); /* FIXME: don't swallow the error */
480 error_init_reuse (error); // one instruction, so this function is good inline candidate
483 static MONO_NEVER_INLINE void
484 ves_real_abort (int line, MonoMethod *mh,
485 const unsigned short *ip, stackval *stack, stackval *sp)
487 ERROR_DECL (error);
488 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
489 mono_error_cleanup (error); /* FIXME: don't swallow the error */
490 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
491 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
492 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
493 mono_metadata_free_mh (header);
494 g_assert_not_reached ();
497 #define ves_abort() \
498 do {\
499 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
500 goto abort_label; \
501 } while (0);
503 static InterpMethod*
504 lookup_imethod (MonoDomain *domain, MonoMethod *method)
506 InterpMethod *imethod;
507 MonoJitDomainInfo *info;
509 info = domain_jit_info (domain);
510 mono_domain_jit_code_hash_lock (domain);
511 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
512 mono_domain_jit_code_hash_unlock (domain);
513 return imethod;
516 static gpointer
517 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
519 #ifndef DISABLE_REMOTING
520 InterpMethod *imethod;
522 if (addr) {
523 imethod = lookup_method_pointer (addr);
524 } else {
525 g_assert (method);
526 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
527 return_val_if_nok (error, NULL);
529 g_assert (imethod);
530 g_assert (mono_use_interpreter);
532 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
533 return_val_if_nok (error, NULL);
534 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
535 #else
536 g_assert_not_reached ();
537 return NULL;
538 #endif
541 InterpMethod*
542 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
544 InterpMethod *imethod;
545 MonoJitDomainInfo *info;
546 MonoMethodSignature *sig;
547 int i;
549 error_init (error);
551 info = domain_jit_info (domain);
552 mono_domain_jit_code_hash_lock (domain);
553 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
554 mono_domain_jit_code_hash_unlock (domain);
555 if (imethod)
556 return imethod;
558 sig = mono_method_signature_internal (method);
560 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
561 imethod->method = method;
562 imethod->domain = domain;
563 imethod->param_count = sig->param_count;
564 imethod->hasthis = sig->hasthis;
565 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
566 imethod->code_type = IMETHOD_CODE_UNKNOWN;
567 if (imethod->method->string_ctor)
568 imethod->rtype = m_class_get_byval_arg (mono_defaults.string_class);
569 else
570 imethod->rtype = mini_get_underlying_type (sig->ret);
571 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
572 for (i = 0; i < sig->param_count; ++i)
573 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
575 mono_domain_jit_code_hash_lock (domain);
576 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
577 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
578 mono_domain_jit_code_hash_unlock (domain);
580 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
582 return imethod;
585 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
586 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
587 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
589 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
590 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
591 * (registers are not accurate), thus resuming to the label does not work. */
592 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
593 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
594 #elif defined (_MSC_VER)
595 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
596 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
597 (ext).interp_exit_label_set = FALSE; \
598 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
599 if ((ext).interp_exit_label_set == FALSE) \
600 mono_arch_do_ip_adjustment (&(ext).ctx); \
601 if ((ext).interp_exit_label_set == TRUE) \
602 goto exit_label; \
603 (ext).interp_exit_label_set = TRUE;
604 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
605 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
606 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
607 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
608 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
609 mono_arch_do_ip_adjustment (&(ext).ctx);
610 #else
611 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
612 #endif
614 /* INTERP_PUSH_LMF_WITH_CTX:
616 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
617 * This is needed to resume into the interp when the exception is thrown from
618 * native code (see ./mono/tests/install_eh_callback.exe).
620 * This must be a macro in order to retrieve the right register values for
621 * MonoContext.
623 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
624 memset (&(ext), 0, sizeof (MonoLMFExt)); \
625 (ext).interp_exit_data = (frame); \
626 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
627 mono_push_lmf (&(ext));
630 * interp_push_lmf:
632 * Push an LMF frame on the LMF stack
633 * to mark the transition to native code.
634 * This is needed for the native code to
635 * be able to do stack walks.
637 static void
638 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
640 memset (ext, 0, sizeof (MonoLMFExt));
641 ext->kind = MONO_LMFEXT_INTERP_EXIT;
642 ext->interp_exit_data = frame;
644 mono_push_lmf (ext);
647 static void
648 interp_pop_lmf (MonoLMFExt *ext)
650 mono_pop_lmf (&ext->lmf);
653 static InterpMethod*
654 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
656 MonoMethod *m = imethod->method;
657 MonoDomain *domain = imethod->domain;
658 InterpMethod *ret = NULL;
660 #ifndef DISABLE_REMOTING
661 if (mono_class_is_transparent_proxy (vtable->klass)) {
662 ERROR_DECL (error);
663 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
664 mono_error_assert_ok (error);
665 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
666 mono_error_assert_ok (error);
667 return ret;
669 #endif
671 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
672 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
673 ERROR_DECL (error);
674 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
675 mono_error_cleanup (error); /* FIXME: don't swallow the error */
676 } else {
677 ret = imethod;
679 return ret;
682 mono_class_setup_vtable (vtable->klass);
684 int slot = mono_method_get_vtable_slot (m);
685 if (mono_class_is_interface (m->klass)) {
686 g_assert (vtable->klass != m->klass);
687 /* TODO: interface offset lookup is slow, go through IMT instead */
688 gboolean non_exact_match;
689 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
692 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
693 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
694 MonoGenericContext context = { NULL, NULL };
696 if (mono_class_is_ginst (virtual_method->klass))
697 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
698 else if (mono_class_is_gtd (virtual_method->klass))
699 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
700 context.method_inst = mono_method_get_context (m)->method_inst;
702 ERROR_DECL (error);
703 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
704 mono_error_cleanup (error); /* FIXME: don't swallow the error */
707 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
708 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
711 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
712 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
715 ERROR_DECL (error);
716 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
717 mono_error_cleanup (error); /* FIXME: don't swallow the error */
718 return virtual_imethod;
721 typedef struct {
722 InterpMethod *imethod;
723 InterpMethod *target_imethod;
724 } InterpVTableEntry;
726 /* domain lock must be held */
727 static GSList*
728 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
730 GSList *ret;
731 InterpVTableEntry *entry;
733 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
734 entry->imethod = imethod;
735 entry->target_imethod = target_imethod;
736 ret = g_slist_append_mempool (domain->mp, list, entry);
738 return ret;
741 static InterpMethod*
742 get_target_imethod (GSList *list, InterpMethod *imethod)
744 while (list != NULL) {
745 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
746 if (entry->imethod == imethod)
747 return entry->target_imethod;
748 list = list->next;
750 return NULL;
753 static gpointer*
754 get_method_table (MonoVTable *vtable, int offset)
756 if (offset >= 0)
757 return vtable->interp_vtable;
758 else
759 return (gpointer*)vtable;
762 static gpointer*
763 alloc_method_table (MonoVTable *vtable, int offset)
765 gpointer *table;
767 if (offset >= 0) {
768 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
769 vtable->interp_vtable = table;
770 } else {
771 table = (gpointer*)vtable;
774 return table;
777 static InterpMethod* // Inlining causes additional stack use in caller.
778 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
780 gpointer *table;
782 #ifndef DISABLE_REMOTING
783 /* FIXME Remoting */
784 if (mono_class_is_transparent_proxy (vtable->klass))
785 return get_virtual_method (imethod, vtable);
786 #endif
788 table = get_method_table (vtable, offset);
790 if (!table) {
791 /* Lazily allocate method table */
792 mono_domain_lock (vtable->domain);
793 table = get_method_table (vtable, offset);
794 if (!table)
795 table = alloc_method_table (vtable, offset);
796 mono_domain_unlock (vtable->domain);
799 if (!table [offset]) {
800 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
801 /* Lazily initialize the method table slot */
802 mono_domain_lock (vtable->domain);
803 if (!table [offset]) {
804 if (imethod->method->is_inflated || offset < 0)
805 table [offset] = append_imethod (vtable->domain, NULL, imethod, target_imethod);
806 else
807 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
809 mono_domain_unlock (vtable->domain);
812 if ((gsize)table [offset] & 0x1) {
813 /* Non generic virtual call. Only one method in slot */
814 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
815 } else {
816 /* Virtual generic or interface call. Multiple methods in slot */
817 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
819 if (!target_imethod) {
820 target_imethod = get_virtual_method (imethod, vtable);
821 mono_domain_lock (vtable->domain);
822 if (!get_target_imethod ((GSList*)table [offset], imethod))
823 table [offset] = append_imethod (vtable->domain, (GSList*)table [offset], imethod, target_imethod);
824 mono_domain_unlock (vtable->domain);
826 return target_imethod;
830 static void inline
831 stackval_from_data (MonoType *type, stackval *result, const void *data, gboolean pinvoke)
833 type = mini_native_type_replace_type (type);
834 if (type->byref) {
835 switch (type->type) {
836 case MONO_TYPE_OBJECT:
837 case MONO_TYPE_CLASS:
838 case MONO_TYPE_STRING:
839 case MONO_TYPE_ARRAY:
840 case MONO_TYPE_SZARRAY:
841 break;
842 default:
843 break;
845 result->data.p = *(gpointer*)data;
846 return;
848 switch (type->type) {
849 case MONO_TYPE_VOID:
850 return;
851 case MONO_TYPE_I1:
852 result->data.i = *(gint8*)data;
853 return;
854 case MONO_TYPE_U1:
855 case MONO_TYPE_BOOLEAN:
856 result->data.i = *(guint8*)data;
857 return;
858 case MONO_TYPE_I2:
859 result->data.i = *(gint16*)data;
860 return;
861 case MONO_TYPE_U2:
862 case MONO_TYPE_CHAR:
863 result->data.i = *(guint16*)data;
864 return;
865 case MONO_TYPE_I4:
866 result->data.i = *(gint32*)data;
867 return;
868 case MONO_TYPE_U:
869 case MONO_TYPE_I:
870 result->data.nati = *(mono_i*)data;
871 return;
872 case MONO_TYPE_PTR:
873 result->data.p = *(gpointer*)data;
874 return;
875 case MONO_TYPE_U4:
876 result->data.i = *(guint32*)data;
877 return;
878 case MONO_TYPE_R4:
879 /* memmove handles unaligned case */
880 memmove (&result->data.f_r4, data, sizeof (float));
881 return;
882 case MONO_TYPE_I8:
883 case MONO_TYPE_U8:
884 memmove (&result->data.l, data, sizeof (gint64));
885 return;
886 case MONO_TYPE_R8:
887 memmove (&result->data.f, data, sizeof (double));
888 return;
889 case MONO_TYPE_STRING:
890 case MONO_TYPE_SZARRAY:
891 case MONO_TYPE_CLASS:
892 case MONO_TYPE_OBJECT:
893 case MONO_TYPE_ARRAY:
894 result->data.p = *(gpointer*)data;
895 return;
896 case MONO_TYPE_VALUETYPE:
897 if (m_class_is_enumtype (type->data.klass)) {
898 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
899 return;
900 } else if (pinvoke) {
901 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
902 } else {
903 mono_value_copy_internal (result->data.vt, data, type->data.klass);
905 return;
906 case MONO_TYPE_GENERICINST: {
907 if (mono_type_generic_inst_is_valuetype (type)) {
908 MonoClass *klass = mono_class_from_mono_type_internal (type);
909 if (pinvoke)
910 memcpy (result->data.vt, data, mono_class_native_size (klass, NULL));
911 else
912 mono_value_copy_internal (result->data.vt, data, klass);
913 return;
915 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
916 return;
918 default:
919 g_error ("got type 0x%02x", type->type);
923 static void inline
924 stackval_to_data (MonoType *type, stackval *val, void *data, gboolean pinvoke)
926 type = mini_native_type_replace_type (type);
927 if (type->byref) {
928 gpointer *p = (gpointer*)data;
929 *p = val->data.p;
930 return;
932 /* printf ("TODAT0 %p\n", data); */
933 switch (type->type) {
934 case MONO_TYPE_I1:
935 case MONO_TYPE_U1: {
936 guint8 *p = (guint8*)data;
937 *p = val->data.i;
938 return;
940 case MONO_TYPE_BOOLEAN: {
941 guint8 *p = (guint8*)data;
942 *p = (val->data.i != 0);
943 return;
945 case MONO_TYPE_I2:
946 case MONO_TYPE_U2:
947 case MONO_TYPE_CHAR: {
948 guint16 *p = (guint16*)data;
949 *p = val->data.i;
950 return;
952 case MONO_TYPE_I: {
953 mono_i *p = (mono_i*)data;
954 /* In theory the value used by stloc should match the local var type
955 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
956 a native int - both by csc and mcs). Not sure what to do about sign extension
957 as it is outside the spec... doing the obvious */
958 *p = (mono_i)val->data.nati;
959 return;
961 case MONO_TYPE_U: {
962 mono_u *p = (mono_u*)data;
963 /* see above. */
964 *p = (mono_u)val->data.nati;
965 return;
967 case MONO_TYPE_I4:
968 case MONO_TYPE_U4: {
969 gint32 *p = (gint32*)data;
970 *p = val->data.i;
971 return;
973 case MONO_TYPE_I8:
974 case MONO_TYPE_U8: {
975 memmove (data, &val->data.l, sizeof (gint64));
976 return;
978 case MONO_TYPE_R4: {
979 /* memmove handles unaligned case */
980 memmove (data, &val->data.f_r4, sizeof (float));
981 return;
983 case MONO_TYPE_R8: {
984 memmove (data, &val->data.f, sizeof (double));
985 return;
987 case MONO_TYPE_STRING:
988 case MONO_TYPE_SZARRAY:
989 case MONO_TYPE_CLASS:
990 case MONO_TYPE_OBJECT:
991 case MONO_TYPE_ARRAY: {
992 gpointer *p = (gpointer *) data;
993 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
994 return;
996 case MONO_TYPE_PTR: {
997 gpointer *p = (gpointer *) data;
998 *p = val->data.p;
999 return;
1001 case MONO_TYPE_VALUETYPE:
1002 if (m_class_is_enumtype (type->data.klass)) {
1003 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
1004 return;
1005 } else if (pinvoke) {
1006 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
1007 } else {
1008 mono_value_copy_internal (data, val->data.vt, type->data.klass);
1010 return;
1011 case MONO_TYPE_GENERICINST: {
1012 MonoClass *container_class = type->data.generic_class->container_class;
1014 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
1015 MonoClass *klass = mono_class_from_mono_type_internal (type);
1016 if (pinvoke)
1017 memcpy (data, val->data.vt, mono_class_native_size (klass, NULL));
1018 else
1019 mono_value_copy_internal (data, val->data.vt, klass);
1020 return;
1022 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
1023 return;
1025 default:
1026 g_error ("got type %x", type->type);
1031 * Same as stackval_to_data but return address of storage instead
1032 * of copying the value.
1034 static gpointer
1035 stackval_to_data_addr (MonoType *type, stackval *val)
1037 type = mini_native_type_replace_type (type);
1038 if (type->byref)
1039 return &val->data.p;
1041 switch (type->type) {
1042 case MONO_TYPE_I1:
1043 case MONO_TYPE_U1:
1044 case MONO_TYPE_BOOLEAN:
1045 case MONO_TYPE_I2:
1046 case MONO_TYPE_U2:
1047 case MONO_TYPE_CHAR:
1048 case MONO_TYPE_I4:
1049 case MONO_TYPE_U4:
1050 return &val->data.i;
1051 case MONO_TYPE_I:
1052 case MONO_TYPE_U:
1053 return &val->data.nati;
1054 case MONO_TYPE_I8:
1055 case MONO_TYPE_U8:
1056 return &val->data.l;
1057 case MONO_TYPE_R4:
1058 return &val->data.f_r4;
1059 case MONO_TYPE_R8:
1060 return &val->data.f;
1061 case MONO_TYPE_STRING:
1062 case MONO_TYPE_SZARRAY:
1063 case MONO_TYPE_CLASS:
1064 case MONO_TYPE_OBJECT:
1065 case MONO_TYPE_ARRAY:
1066 case MONO_TYPE_PTR:
1067 return &val->data.p;
1068 case MONO_TYPE_VALUETYPE:
1069 if (m_class_is_enumtype (type->data.klass))
1070 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
1071 else
1072 return val->data.vt;
1073 case MONO_TYPE_TYPEDBYREF:
1074 return val->data.vt;
1075 case MONO_TYPE_GENERICINST: {
1076 MonoClass *container_class = type->data.generic_class->container_class;
1078 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
1079 return val->data.vt;
1080 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
1082 default:
1083 g_error ("got type %x", type->type);
1088 * interp_throw:
1089 * Throw an exception from the interpreter.
1091 static MONO_NEVER_INLINE void
1092 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, const guint16* ip, gboolean rethrow)
1094 ERROR_DECL (error);
1095 MonoLMFExt ext;
1097 interp_push_lmf (&ext, frame);
1098 frame->ip = ip;
1100 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
1101 MonoException *mono_ex = ex;
1102 if (!rethrow) {
1103 mono_ex->stack_trace = NULL;
1104 mono_ex->trace_ips = NULL;
1107 mono_error_assert_ok (error);
1109 MonoContext ctx;
1110 memset (&ctx, 0, sizeof (MonoContext));
1111 MONO_CONTEXT_SET_SP (&ctx, frame->native_stack_addr);
1114 * Call the JIT EH code. The EH code will call back to us using:
1115 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
1116 * Since ctx.ip is 0, this will start unwinding from the LMF frame
1117 * pushed above, which points to our frames.
1119 mono_handle_exception (&ctx, (MonoObject*)ex);
1120 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
1121 /* We need to unwind into non-interpreter code */
1122 mono_restore_context (&ctx);
1123 g_assert_not_reached ();
1126 interp_pop_lmf (&ext);
1128 g_assert (context->has_resume_state);
1131 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
1132 do { \
1133 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
1134 goto resume; \
1135 } while (0)
1137 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
1139 #define NULL_CHECK(o) do { \
1140 if (G_UNLIKELY (!(o))) \
1141 goto null_label; \
1142 } while (0)
1144 #define EXCEPTION_CHECKPOINT \
1145 do { \
1146 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
1147 MonoException *exc = mono_thread_interruption_checkpoint (); \
1148 if (exc) \
1149 THROW_EX (exc, ip); \
1151 } while (0)
1153 /* Don't throw exception if thread is in GC Safe mode. Should only happen in managed-to-native wrapper. */
1154 #define EXCEPTION_CHECKPOINT_GC_UNSAFE \
1155 do { \
1156 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method) && mono_thread_is_gc_unsafe_mode ()) { \
1157 MonoException *exc = mono_thread_interruption_checkpoint (); \
1158 if (exc) \
1159 THROW_EX (exc, ip); \
1161 } while (0)
1163 static MonoObject*
1164 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
1166 uintptr_t *lengths;
1167 intptr_t *lower_bounds;
1168 int i;
1170 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
1171 for (i = 0; i < param_count; ++i) {
1172 lengths [i] = values->data.i;
1173 values ++;
1175 if (m_class_get_rank (klass) == param_count) {
1176 /* Only lengths provided. */
1177 lower_bounds = NULL;
1178 } else {
1179 /* lower bounds are first. */
1180 lower_bounds = (intptr_t *) lengths;
1181 lengths += m_class_get_rank (klass);
1183 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
1186 static gint32
1187 ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
1189 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1191 guint32 pos = 0;
1192 if (ao->bounds) {
1193 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
1194 guint32 idx = sp [i].data.i;
1195 guint32 lower = ao->bounds [i].lower_bound;
1196 guint32 len = ao->bounds [i].length;
1197 if (safe && (idx < lower || (idx - lower) >= len))
1198 return -1;
1199 pos = (pos * len) + idx - lower;
1201 } else {
1202 pos = sp [0].data.i;
1203 if (safe && pos >= ao->max_length)
1204 return -1;
1206 return pos;
1209 static MonoException*
1210 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1212 MonoObject *o = sp->data.o;
1213 MonoArray *ao = (MonoArray *) o;
1214 MonoClass *ac = o->vtable->klass;
1216 g_assert (m_class_get_rank (ac) >= 1);
1218 gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
1219 if (pos == -1)
1220 return mono_get_exception_index_out_of_range ();
1222 gint32 esize = mono_array_element_size (ac);
1223 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1225 MonoType *mt = sig->ret;
1226 stackval_from_data (mt, retval, ea, FALSE);
1227 return NULL;
1230 static MonoException*
1231 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1233 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1235 g_assert (m_class_get_rank (ac) >= 1);
1237 gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
1238 if (pos == -1)
1239 return mono_get_exception_index_out_of_range ();
1241 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
1242 return mono_get_exception_array_type_mismatch ();
1243 gint32 esize = mono_array_element_size (ac);
1244 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
1245 return NULL;
1248 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1249 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1250 #endif
1252 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1253 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1255 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1257 #ifdef TARGET_ARM
1258 g_assert (mono_arm_eabi_supported ());
1259 int i8_align = mono_arm_i8_align ();
1260 #endif
1262 #ifdef TARGET_WASM
1263 margs->sig = sig;
1264 #endif
1266 if (sig->hasthis)
1267 margs->ilen++;
1269 for (int i = 0; i < sig->param_count; i++) {
1270 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1271 switch (ptype) {
1272 case MONO_TYPE_BOOLEAN:
1273 case MONO_TYPE_CHAR:
1274 case MONO_TYPE_I1:
1275 case MONO_TYPE_U1:
1276 case MONO_TYPE_I2:
1277 case MONO_TYPE_U2:
1278 case MONO_TYPE_I4:
1279 case MONO_TYPE_U4:
1280 case MONO_TYPE_I:
1281 case MONO_TYPE_U:
1282 case MONO_TYPE_PTR:
1283 case MONO_TYPE_SZARRAY:
1284 case MONO_TYPE_CLASS:
1285 case MONO_TYPE_OBJECT:
1286 case MONO_TYPE_STRING:
1287 case MONO_TYPE_VALUETYPE:
1288 case MONO_TYPE_GENERICINST:
1289 #if SIZEOF_VOID_P == 8
1290 case MONO_TYPE_I8:
1291 case MONO_TYPE_U8:
1292 #endif
1293 margs->ilen++;
1294 break;
1295 #if SIZEOF_VOID_P == 4
1296 case MONO_TYPE_I8:
1297 case MONO_TYPE_U8:
1298 #ifdef TARGET_ARM
1299 /* pairs begin at even registers */
1300 if (i8_align == 8 && margs->ilen & 1)
1301 margs->ilen++;
1302 #endif
1303 margs->ilen += 2;
1304 break;
1305 #endif
1306 case MONO_TYPE_R4:
1307 #if SIZEOF_VOID_P == 8
1308 case MONO_TYPE_R8:
1309 #endif
1310 margs->flen++;
1311 break;
1312 #if SIZEOF_VOID_P == 4
1313 case MONO_TYPE_R8:
1314 margs->flen += 2;
1315 break;
1316 #endif
1317 default:
1318 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1322 if (margs->ilen > 0)
1323 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1325 if (margs->flen > 0)
1326 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1328 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1329 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1331 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1332 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1335 size_t int_i = 0;
1336 size_t int_f = 0;
1338 if (sig->hasthis) {
1339 margs->iargs [0] = frame->stack_args->data.p;
1340 int_i++;
1343 for (int i = 0; i < sig->param_count; i++) {
1344 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1345 switch (ptype) {
1346 case MONO_TYPE_BOOLEAN:
1347 case MONO_TYPE_CHAR:
1348 case MONO_TYPE_I1:
1349 case MONO_TYPE_U1:
1350 case MONO_TYPE_I2:
1351 case MONO_TYPE_U2:
1352 case MONO_TYPE_I4:
1353 case MONO_TYPE_U4:
1354 case MONO_TYPE_I:
1355 case MONO_TYPE_U:
1356 case MONO_TYPE_PTR:
1357 case MONO_TYPE_SZARRAY:
1358 case MONO_TYPE_CLASS:
1359 case MONO_TYPE_OBJECT:
1360 case MONO_TYPE_STRING:
1361 case MONO_TYPE_VALUETYPE:
1362 case MONO_TYPE_GENERICINST:
1363 #if SIZEOF_VOID_P == 8
1364 case MONO_TYPE_I8:
1365 case MONO_TYPE_U8:
1366 #endif
1367 margs->iargs [int_i] = frame->stack_args [i].data.p;
1368 #if DEBUG_INTERP
1369 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1370 #endif
1371 int_i++;
1372 break;
1373 #if SIZEOF_VOID_P == 4
1374 case MONO_TYPE_I8:
1375 case MONO_TYPE_U8: {
1376 stackval *sarg = &frame->stack_args [i];
1377 #ifdef TARGET_ARM
1378 /* pairs begin at even registers */
1379 if (i8_align == 8 && int_i & 1)
1380 int_i++;
1381 #endif
1382 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1383 int_i++;
1384 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1385 #if DEBUG_INTERP
1386 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016" PRIx64 ", 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);
1387 #endif
1388 int_i++;
1389 break;
1391 #endif
1392 case MONO_TYPE_R4:
1393 case MONO_TYPE_R8:
1394 if (ptype == MONO_TYPE_R4)
1395 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1396 else
1397 margs->fargs [int_f] = frame->stack_args [i].data.f;
1398 #if DEBUG_INTERP
1399 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);
1400 #endif
1401 #if SIZEOF_VOID_P == 4
1402 int_f += 2;
1403 #else
1404 int_f++;
1405 #endif
1406 break;
1407 default:
1408 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1412 switch (sig->ret->type) {
1413 case MONO_TYPE_BOOLEAN:
1414 case MONO_TYPE_CHAR:
1415 case MONO_TYPE_I1:
1416 case MONO_TYPE_U1:
1417 case MONO_TYPE_I2:
1418 case MONO_TYPE_U2:
1419 case MONO_TYPE_I4:
1420 case MONO_TYPE_U4:
1421 case MONO_TYPE_I:
1422 case MONO_TYPE_U:
1423 case MONO_TYPE_PTR:
1424 case MONO_TYPE_SZARRAY:
1425 case MONO_TYPE_CLASS:
1426 case MONO_TYPE_OBJECT:
1427 case MONO_TYPE_STRING:
1428 case MONO_TYPE_I8:
1429 case MONO_TYPE_U8:
1430 case MONO_TYPE_VALUETYPE:
1431 case MONO_TYPE_GENERICINST:
1432 margs->retval = &frame->retval->data.p;
1433 margs->is_float_ret = 0;
1434 break;
1435 case MONO_TYPE_R4:
1436 case MONO_TYPE_R8:
1437 margs->retval = &frame->retval->data.p;
1438 margs->is_float_ret = 1;
1439 break;
1440 case MONO_TYPE_VOID:
1441 margs->retval = NULL;
1442 break;
1443 default:
1444 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1447 return margs;
1449 #endif
1451 static void
1452 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1454 InterpFrame *iframe = (InterpFrame*)frame;
1456 if (index == -1)
1457 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1458 else
1459 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1462 static void
1463 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1465 InterpFrame *iframe = (InterpFrame*)frame;
1467 if (index == -1)
1468 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1469 else if (sig->hasthis && index == 0)
1470 iframe->stack_args [index].data.p = *(gpointer*)data;
1471 else
1472 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1475 static gpointer
1476 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1478 InterpFrame *iframe = (InterpFrame*)frame;
1480 if (index == -1)
1481 return stackval_to_data_addr (sig->ret, iframe->retval);
1482 else
1483 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1486 static void
1487 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1489 InterpFrame *iframe = (InterpFrame*)frame;
1490 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1491 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1493 switch (type->type) {
1494 case MONO_TYPE_GENERICINST:
1495 if (!MONO_TYPE_IS_REFERENCE (type))
1496 val->data.vt = storage;
1497 break;
1498 case MONO_TYPE_VALUETYPE:
1499 val->data.vt = storage;
1500 break;
1501 default:
1502 g_assert_not_reached ();
1506 static MonoPIFunc
1507 get_interp_to_native_trampoline (void)
1509 static MonoPIFunc trampoline = NULL;
1511 if (!trampoline) {
1512 if (mono_ee_features.use_aot_trampolines) {
1513 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1514 } else {
1515 MonoTrampInfo *info;
1516 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1517 mono_tramp_info_register (info, NULL);
1519 mono_memory_barrier ();
1521 return trampoline;
1524 static void
1525 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1527 get_interp_to_native_trampoline () (addr, ccontext);
1530 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1531 #ifdef _MSC_VER
1532 #pragma optimize ("", off)
1533 #endif
1534 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1535 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, ThreadContext *context, gboolean save_last_error)
1537 MonoLMFExt ext;
1538 gpointer args;
1540 g_assert (!frame->imethod);
1542 static MonoPIFunc entry_func = NULL;
1543 if (!entry_func) {
1544 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1545 ERROR_DECL (error);
1546 entry_func = (MonoPIFunc) mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper ("mono_interp_to_native_trampoline", (gpointer) mono_interp_to_native_trampoline), error);
1547 mono_error_assert_ok (error);
1548 #else
1549 entry_func = get_interp_to_native_trampoline ();
1550 #endif
1551 mono_memory_barrier ();
1554 #ifdef ENABLE_NETCORE
1555 if (save_last_error) {
1556 mono_marshal_clear_last_error ();
1558 #endif
1560 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1561 CallContext ccontext;
1562 MONO_ENTER_GC_UNSAFE;
1563 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1564 MONO_EXIT_GC_UNSAFE;
1565 args = &ccontext;
1566 #else
1567 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1568 args = margs;
1569 #endif
1571 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1572 entry_func ((gpointer) addr, args);
1573 if (save_last_error)
1574 mono_marshal_set_last_error ();
1575 interp_pop_lmf (&ext);
1577 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1578 if (!context->has_resume_state) {
1579 MONO_ENTER_GC_UNSAFE;
1580 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1581 MONO_EXIT_GC_UNSAFE;
1584 if (ccontext.stack != NULL)
1585 g_free (ccontext.stack);
1586 #else
1587 if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
1588 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1590 g_free (margs->iargs);
1591 g_free (margs->fargs);
1592 g_free (margs);
1593 #endif
1594 goto exit_pinvoke; // prevent unused label warning in some configurations
1595 exit_pinvoke:
1596 return;
1598 #ifdef _MSC_VER
1599 #pragma optimize ("", on)
1600 #endif
1603 * interp_init_delegate:
1605 * Initialize del->interp_method.
1607 static void
1608 interp_init_delegate (MonoDelegate *del, MonoError *error)
1610 MonoMethod *method;
1612 if (del->interp_method) {
1613 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1614 del->method = ((InterpMethod *)del->interp_method)->method;
1615 } else if (del->method) {
1616 /* Delegate created dynamically */
1617 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1618 } else {
1619 /* Created from JITted code */
1620 g_assert_not_reached ();
1623 method = ((InterpMethod*)del->interp_method)->method;
1624 if (del->target &&
1625 method &&
1626 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1627 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1628 mono_class_is_abstract (method->klass))
1629 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1631 method = ((InterpMethod*)del->interp_method)->method;
1632 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1633 const char *name = method->name;
1634 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1636 * When invoking the delegate interp_method is executed directly. If it's an
1637 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1639 * FIXME We should do this later, when we also know the delegate on which the
1640 * target method is called.
1642 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1643 mono_error_assert_ok (error);
1647 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1648 /* Return any errors from method compilation */
1649 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1650 return_if_nok (error);
1654 static void
1655 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1658 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1660 InterpMethod *imethod = (InterpMethod*)addr;
1662 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1663 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1664 /* virtual invoke delegates must not have null check */
1665 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1666 && MONO_HANDLE_IS_NULL (target)) {
1667 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1668 return;
1672 g_assert (imethod->method);
1673 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1674 return_if_nok (error);
1676 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1678 mono_delegate_ctor (this_obj, target, entry, error);
1682 * From the spec:
1683 * runtime specifies that the implementation of the method is automatically
1684 * provided by the runtime and is primarily used for the methods of delegates.
1686 #ifndef ENABLE_NETCORE
1687 static MONO_NEVER_INLINE MonoException*
1688 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1690 const char *name = method->name;
1691 mono_class_init_internal (method->klass);
1693 if (method->klass == mono_defaults.array_class) {
1694 if (!strcmp (name, "UnsafeMov")) {
1695 /* TODO: layout checks */
1696 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1697 return NULL;
1699 if (!strcmp (name, "UnsafeLoad"))
1700 return ves_array_get (frame, sp, retval, sig, FALSE);
1703 g_error ("Don't know how to exec runtime method %s.%s::%s",
1704 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1705 method->name);
1707 #endif
1709 #if DEBUG_INTERP
1710 static char*
1711 dump_stack (stackval *stack, stackval *sp)
1713 stackval *s = stack;
1714 GString *str = g_string_new ("");
1716 if (sp == stack)
1717 return g_string_free (str, FALSE);
1719 while (s < sp) {
1720 g_string_append_printf (str, "[%p (%" PRId64 ")] ", s->data.l, (gint64)s->data.l);
1721 ++s;
1723 return g_string_free (str, FALSE);
1726 static void
1727 dump_stackval (GString *str, stackval *s, MonoType *type)
1729 switch (type->type) {
1730 case MONO_TYPE_I1:
1731 case MONO_TYPE_U1:
1732 case MONO_TYPE_I2:
1733 case MONO_TYPE_U2:
1734 case MONO_TYPE_I4:
1735 case MONO_TYPE_U4:
1736 case MONO_TYPE_CHAR:
1737 case MONO_TYPE_BOOLEAN:
1738 g_string_append_printf (str, "[%d] ", s->data.i);
1739 break;
1740 case MONO_TYPE_STRING:
1741 case MONO_TYPE_SZARRAY:
1742 case MONO_TYPE_CLASS:
1743 case MONO_TYPE_OBJECT:
1744 case MONO_TYPE_ARRAY:
1745 case MONO_TYPE_PTR:
1746 case MONO_TYPE_I:
1747 case MONO_TYPE_U:
1748 g_string_append_printf (str, "[%p] ", s->data.p);
1749 break;
1750 case MONO_TYPE_VALUETYPE:
1751 if (m_class_is_enumtype (type->data.klass))
1752 g_string_append_printf (str, "[%d] ", s->data.i);
1753 else
1754 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1755 break;
1756 case MONO_TYPE_R4:
1757 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1758 break;
1759 case MONO_TYPE_R8:
1760 g_string_append_printf (str, "[%g] ", s->data.f);
1761 break;
1762 case MONO_TYPE_I8:
1763 case MONO_TYPE_U8:
1764 default: {
1765 GString *res = g_string_new ("");
1766 mono_type_get_desc (res, type, TRUE);
1767 g_string_append_printf (str, "[{%s} %" PRId64 "/0x%0" PRIx64 "] ", res->str, (gint64)s->data.l, (guint64)s->data.l);
1768 g_string_free (res, TRUE);
1769 break;
1774 static char*
1775 dump_retval (InterpFrame *inv)
1777 GString *str = g_string_new ("");
1778 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1780 if (ret->type != MONO_TYPE_VOID)
1781 dump_stackval (str, inv->retval, ret);
1783 return g_string_free (str, FALSE);
1786 static char*
1787 dump_args (InterpFrame *inv)
1789 GString *str = g_string_new ("");
1790 int i;
1791 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1793 if (signature->param_count == 0 && !signature->hasthis)
1794 return g_string_free (str, FALSE);
1796 if (signature->hasthis) {
1797 MonoMethod *method = inv->imethod->method;
1798 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1801 for (i = 0; i < signature->param_count; ++i)
1802 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1804 return g_string_free (str, FALSE);
1806 #endif
1808 #define CHECK_ADD_OVERFLOW(a,b) \
1809 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1810 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1812 #define CHECK_SUB_OVERFLOW(a,b) \
1813 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1814 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1816 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1817 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1819 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1820 (guint32)(a) < (guint32)(b) ? -1 : 0
1822 #define CHECK_ADD_OVERFLOW64(a,b) \
1823 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1824 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1826 #define CHECK_SUB_OVERFLOW64(a,b) \
1827 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1828 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1830 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1831 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1833 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1834 (guint64)(a) < (guint64)(b) ? -1 : 0
1836 #if SIZEOF_VOID_P == 4
1837 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1838 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1839 #else
1840 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1841 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1842 #endif
1844 /* Resolves to TRUE if the operands would overflow */
1845 #define CHECK_MUL_OVERFLOW(a,b) \
1846 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1847 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1848 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1849 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1850 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1851 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1852 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1854 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1855 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1856 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1858 #define CHECK_MUL_OVERFLOW64(a,b) \
1859 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1860 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1861 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1862 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1863 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1864 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1865 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1867 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1868 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1869 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1871 #if SIZEOF_VOID_P == 4
1872 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1873 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1874 #else
1875 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1876 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1877 #endif
1879 static MonoObject*
1880 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1882 InterpFrame *frame;
1883 ThreadContext *context = get_context ();
1884 MonoMethodSignature *sig = mono_method_signature_internal (method);
1885 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1886 stackval result;
1887 MonoMethod *target_method = method;
1889 error_init (error);
1890 if (exc)
1891 *exc = NULL;
1893 MonoDomain *domain = mono_domain_get ();
1895 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1896 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1897 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1899 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1901 result.data.vt = alloca (mono_class_instance_size (klass));
1902 stackval args [4];
1904 if (sig->hasthis)
1905 args [0].data.p = obj;
1906 else
1907 args [0].data.p = NULL;
1908 args [1].data.p = params;
1909 args [2].data.p = exc;
1910 args [3].data.p = target_method;
1912 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1913 mono_error_assert_ok (error);
1914 frame = alloc_frame (context, &result, NULL, imethod, args, &result);
1916 interp_exec_method (frame, context, error);
1918 if (context->has_resume_state) {
1919 // This can happen on wasm !?
1920 MonoException *thrown_exc = (MonoException*) mono_gchandle_get_target_internal (context->exc_gchandle);
1921 if (exc)
1922 *exc = (MonoObject*)thrown_exc;
1923 else
1924 mono_error_set_exception_instance (error, thrown_exc);
1925 return NULL;
1927 return (MonoObject*)result.data.p;
1930 typedef struct {
1931 InterpMethod *rmethod;
1932 gpointer this_arg;
1933 gpointer res;
1934 gpointer args [16];
1935 gpointer *many_args;
1936 } InterpEntryData;
1938 /* Main function for entering the interpreter from compiled code */
1939 static void
1940 interp_entry (InterpEntryData *data)
1942 InterpFrame *frame;
1943 InterpMethod *rmethod;
1944 ThreadContext *context;
1945 stackval result;
1946 stackval *args;
1947 MonoMethod *method;
1948 MonoMethodSignature *sig;
1949 MonoType *type;
1950 gpointer orig_domain = NULL, attach_cookie;
1951 int i;
1953 if ((gsize)data->rmethod & 1) {
1954 /* Unbox */
1955 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1956 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1958 rmethod = data->rmethod;
1960 if (rmethod->needs_thread_attach)
1961 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1963 context = get_context ();
1965 method = rmethod->method;
1966 sig = mono_method_signature_internal (method);
1968 // FIXME: Optimize this
1970 //printf ("%s\n", mono_method_full_name (method, 1));
1972 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1973 if (sig->hasthis)
1974 args [0].data.p = data->this_arg;
1976 gpointer *params;
1977 if (data->many_args)
1978 params = data->many_args;
1979 else
1980 params = data->args;
1981 for (i = 0; i < sig->param_count; ++i) {
1982 int a_index = i + (sig->hasthis ? 1 : 0);
1983 if (sig->params [i]->byref) {
1984 args [a_index].data.p = params [i];
1985 continue;
1987 type = rmethod->param_types [i];
1988 switch (type->type) {
1989 case MONO_TYPE_VALUETYPE:
1990 args [a_index].data.p = params [i];
1991 break;
1992 case MONO_TYPE_GENERICINST:
1993 if (MONO_TYPE_IS_REFERENCE (type))
1994 args [a_index].data.p = *(gpointer*)params [i];
1995 else
1996 args [a_index].data.vt = params [i];
1997 break;
1998 default:
1999 stackval_from_data (type, &args [a_index], params [i], FALSE);
2000 break;
2004 memset (&result, 0, sizeof (result));
2005 frame = alloc_frame (context, &result, NULL, data->rmethod, args, &result);
2007 type = rmethod->rtype;
2008 switch (type->type) {
2009 case MONO_TYPE_GENERICINST:
2010 if (!MONO_TYPE_IS_REFERENCE (type))
2011 result.data.vt = data->res;
2012 break;
2013 case MONO_TYPE_VALUETYPE:
2014 result.data.vt = data->res;
2015 break;
2016 default:
2017 break;
2020 ERROR_DECL (error);
2021 interp_exec_method (frame, context, error);
2023 g_assert (!context->has_resume_state);
2025 if (rmethod->needs_thread_attach)
2026 mono_threads_detach_coop (orig_domain, &attach_cookie);
2028 if (mono_llvm_only) {
2029 if (context->has_resume_state)
2030 mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
2031 } else {
2032 g_assert (!context->has_resume_state);
2035 type = rmethod->rtype;
2036 switch (type->type) {
2037 case MONO_TYPE_VOID:
2038 break;
2039 case MONO_TYPE_OBJECT:
2040 /* No need for a write barrier */
2041 *(MonoObject**)data->res = (MonoObject*)result.data.p;
2042 break;
2043 case MONO_TYPE_GENERICINST:
2044 if (MONO_TYPE_IS_REFERENCE (type)) {
2045 *(MonoObject**)data->res = (MonoObject*)result.data.p;
2046 } else {
2047 /* Already set before the call */
2049 break;
2050 case MONO_TYPE_VALUETYPE:
2051 /* Already set before the call */
2052 break;
2053 default:
2054 stackval_to_data (type, &result, data->res, FALSE);
2055 break;
2059 static stackval *
2060 do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2062 #ifdef ENABLE_NETCORE
2063 if (save_last_error)
2064 mono_marshal_clear_last_error ();
2065 #endif
2067 switch (op) {
2068 case MINT_ICALL_V_V: {
2069 typedef void (*T)(void);
2070 T func = (T)ptr;
2071 func ();
2072 break;
2074 case MINT_ICALL_V_P: {
2075 typedef gpointer (*T)(void);
2076 T func = (T)ptr;
2077 sp++;
2078 sp [-1].data.p = func ();
2079 break;
2081 case MINT_ICALL_P_V: {
2082 typedef void (*T)(gpointer);
2083 T func = (T)ptr;
2084 func (sp [-1].data.p);
2085 sp --;
2086 break;
2088 case MINT_ICALL_P_P: {
2089 typedef gpointer (*T)(gpointer);
2090 T func = (T)ptr;
2091 sp [-1].data.p = func (sp [-1].data.p);
2092 break;
2094 case MINT_ICALL_PP_V: {
2095 typedef void (*T)(gpointer,gpointer);
2096 T func = (T)ptr;
2097 sp -= 2;
2098 func (sp [0].data.p, sp [1].data.p);
2099 break;
2101 case MINT_ICALL_PP_P: {
2102 typedef gpointer (*T)(gpointer,gpointer);
2103 T func = (T)ptr;
2104 --sp;
2105 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
2106 break;
2108 case MINT_ICALL_PPP_V: {
2109 typedef void (*T)(gpointer,gpointer,gpointer);
2110 T func = (T)ptr;
2111 sp -= 3;
2112 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
2113 break;
2115 case MINT_ICALL_PPP_P: {
2116 typedef gpointer (*T)(gpointer,gpointer,gpointer);
2117 T func = (T)ptr;
2118 sp -= 2;
2119 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
2120 break;
2122 case MINT_ICALL_PPPP_V: {
2123 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
2124 T func = (T)ptr;
2125 sp -= 4;
2126 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
2127 break;
2129 case MINT_ICALL_PPPP_P: {
2130 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
2131 T func = (T)ptr;
2132 sp -= 3;
2133 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
2134 break;
2136 case MINT_ICALL_PPPPP_V: {
2137 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2138 T func = (T)ptr;
2139 sp -= 5;
2140 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
2141 break;
2143 case MINT_ICALL_PPPPP_P: {
2144 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2145 T func = (T)ptr;
2146 sp -= 4;
2147 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);
2148 break;
2150 case MINT_ICALL_PPPPPP_V: {
2151 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2152 T func = (T)ptr;
2153 sp -= 6;
2154 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);
2155 break;
2157 case MINT_ICALL_PPPPPP_P: {
2158 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2159 T func = (T)ptr;
2160 sp -= 5;
2161 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);
2162 break;
2164 default:
2165 g_assert_not_reached ();
2168 if (save_last_error)
2169 mono_marshal_set_last_error ();
2171 /* convert the native representation to the stackval representation */
2172 if (sig)
2173 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2175 return sp;
2178 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2179 #ifdef _MSC_VER
2180 #pragma optimize ("", off)
2181 #endif
2182 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2183 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2185 MonoLMFExt ext;
2186 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2188 sp = do_icall (sig, op, sp, ptr, save_last_error);
2190 interp_pop_lmf (&ext);
2192 goto exit_icall; // prevent unused label warning in some configurations
2193 exit_icall:
2194 return sp;
2196 #ifdef _MSC_VER
2197 #pragma optimize ("", on)
2198 #endif
2200 typedef struct {
2201 int pindex;
2202 gpointer jit_wrapper;
2203 gpointer *args;
2204 MonoFtnDesc *ftndesc;
2205 } JitCallCbData;
2207 static void
2208 jit_call_cb (gpointer arg)
2210 JitCallCbData *cb_data = (JitCallCbData*)arg;
2211 gpointer jit_wrapper = cb_data->jit_wrapper;
2212 int pindex = cb_data->pindex;
2213 gpointer *args = cb_data->args;
2214 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2216 switch (pindex) {
2217 case 0: {
2218 typedef void (*T)(gpointer);
2219 T func = (T)jit_wrapper;
2221 func (&ftndesc);
2222 break;
2224 case 1: {
2225 typedef void (*T)(gpointer, gpointer);
2226 T func = (T)jit_wrapper;
2228 func (args [0], &ftndesc);
2229 break;
2231 case 2: {
2232 typedef void (*T)(gpointer, gpointer, gpointer);
2233 T func = (T)jit_wrapper;
2235 func (args [0], args [1], &ftndesc);
2236 break;
2238 case 3: {
2239 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2240 T func = (T)jit_wrapper;
2242 func (args [0], args [1], args [2], &ftndesc);
2243 break;
2245 case 4: {
2246 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2247 T func = (T)jit_wrapper;
2249 func (args [0], args [1], args [2], args [3], &ftndesc);
2250 break;
2252 case 5: {
2253 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2254 T func = (T)jit_wrapper;
2256 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2257 break;
2259 case 6: {
2260 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2261 T func = (T)jit_wrapper;
2263 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2264 break;
2266 case 7: {
2267 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2268 T func = (T)jit_wrapper;
2270 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2271 break;
2273 case 8: {
2274 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2275 T func = (T)jit_wrapper;
2277 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2278 break;
2280 default:
2281 g_assert_not_reached ();
2282 break;
2286 static MONO_NEVER_INLINE void
2287 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2289 MonoMethodSignature *sig;
2290 MonoFtnDesc ftndesc;
2291 guint8 res_buf [256];
2292 MonoType *type;
2293 MonoLMFExt ext;
2295 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2298 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2299 * by ref and return a return value using an explicit return value argument.
2301 if (G_UNLIKELY (!rmethod->jit_wrapper)) {
2302 MonoMethod *method = rmethod->method;
2304 sig = mono_method_signature_internal (method);
2305 g_assert (sig);
2307 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2308 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2310 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2311 mono_error_assert_ok (error);
2313 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2314 return_if_nok (error);
2315 g_assert (addr);
2317 rmethod->jit_addr = addr;
2318 rmethod->jit_sig = sig;
2319 mono_memory_barrier ();
2320 rmethod->jit_wrapper = jit_wrapper;
2322 } else {
2323 sig = rmethod->jit_sig;
2326 ftndesc.addr = rmethod->jit_addr;
2327 ftndesc.arg = NULL;
2329 // FIXME: Optimize this
2331 gpointer args [32];
2332 int pindex = 0;
2333 int stack_index = 0;
2334 if (rmethod->hasthis) {
2335 args [pindex ++] = sp [0].data.p;
2336 stack_index ++;
2338 type = rmethod->rtype;
2339 if (type->type != MONO_TYPE_VOID) {
2340 if (MONO_TYPE_ISSTRUCT (type))
2341 args [pindex ++] = vt_sp;
2342 else
2343 args [pindex ++] = res_buf;
2345 for (int i = 0; i < rmethod->param_count; ++i) {
2346 MonoType *t = rmethod->param_types [i];
2347 stackval *sval = &sp [stack_index + i];
2348 if (sig->params [i]->byref) {
2349 args [pindex ++] = sval->data.p;
2350 } else if (MONO_TYPE_ISSTRUCT (t)) {
2351 args [pindex ++] = sval->data.p;
2352 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2353 args [pindex ++] = &sval->data.p;
2354 } else {
2355 switch (t->type) {
2356 case MONO_TYPE_I1:
2357 case MONO_TYPE_U1:
2358 case MONO_TYPE_I2:
2359 case MONO_TYPE_U2:
2360 case MONO_TYPE_I4:
2361 case MONO_TYPE_U4:
2362 case MONO_TYPE_VALUETYPE:
2363 args [pindex ++] = &sval->data.i;
2364 break;
2365 case MONO_TYPE_PTR:
2366 case MONO_TYPE_FNPTR:
2367 case MONO_TYPE_I:
2368 case MONO_TYPE_U:
2369 case MONO_TYPE_OBJECT:
2370 args [pindex ++] = &sval->data.p;
2371 break;
2372 case MONO_TYPE_I8:
2373 case MONO_TYPE_U8:
2374 args [pindex ++] = &sval->data.l;
2375 break;
2376 case MONO_TYPE_R4:
2377 args [pindex ++] = &sval->data.f_r4;
2378 break;
2379 case MONO_TYPE_R8:
2380 args [pindex ++] = &sval->data.f;
2381 break;
2382 default:
2383 printf ("%s\n", mono_type_full_name (t));
2384 g_assert_not_reached ();
2389 interp_push_lmf (&ext, frame);
2391 JitCallCbData cb_data;
2392 memset (&cb_data, 0, sizeof (cb_data));
2393 cb_data.jit_wrapper = rmethod->jit_wrapper;
2394 cb_data.pindex = pindex;
2395 cb_data.args = args;
2396 cb_data.ftndesc = &ftndesc;
2398 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2399 /* Catch the exception thrown by the native code using a try-catch */
2400 gboolean thrown = FALSE;
2401 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2402 interp_pop_lmf (&ext);
2403 if (thrown) {
2404 MonoObject *obj = mono_llvm_load_exception ();
2405 g_assert (obj);
2406 mono_error_set_exception_instance (error, (MonoException*)obj);
2407 return;
2409 } else {
2410 jit_call_cb (&cb_data);
2411 interp_pop_lmf (&ext);
2414 MonoType *rtype = rmethod->rtype;
2415 switch (rtype->type) {
2416 case MONO_TYPE_VOID:
2417 case MONO_TYPE_OBJECT:
2418 case MONO_TYPE_STRING:
2419 case MONO_TYPE_CLASS:
2420 case MONO_TYPE_ARRAY:
2421 case MONO_TYPE_SZARRAY:
2422 case MONO_TYPE_I:
2423 case MONO_TYPE_U:
2424 case MONO_TYPE_PTR:
2425 sp->data.p = *(gpointer*)res_buf;
2426 break;
2427 case MONO_TYPE_I1:
2428 sp->data.i = *(gint8*)res_buf;
2429 break;
2430 case MONO_TYPE_U1:
2431 sp->data.i = *(guint8*)res_buf;
2432 break;
2433 case MONO_TYPE_I2:
2434 sp->data.i = *(gint16*)res_buf;
2435 break;
2436 case MONO_TYPE_U2:
2437 sp->data.i = *(guint16*)res_buf;
2438 break;
2439 case MONO_TYPE_I4:
2440 sp->data.i = *(gint32*)res_buf;
2441 break;
2442 case MONO_TYPE_U4:
2443 sp->data.i = *(guint32*)res_buf;
2444 break;
2445 case MONO_TYPE_I8:
2446 sp->data.l = *(gint64*)res_buf;
2447 break;
2448 case MONO_TYPE_U8:
2449 sp->data.l = *(guint64*)res_buf;
2450 break;
2451 case MONO_TYPE_R4:
2452 sp->data.f_r4 = *(float*)res_buf;
2453 break;
2454 case MONO_TYPE_R8:
2455 sp->data.f = *(double*)res_buf;
2456 break;
2457 case MONO_TYPE_TYPEDBYREF:
2458 case MONO_TYPE_VALUETYPE:
2459 /* The result was written to vt_sp */
2460 sp->data.p = vt_sp;
2461 break;
2462 case MONO_TYPE_GENERICINST:
2463 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2464 sp->data.p = *(gpointer*)res_buf;
2465 } else {
2466 /* The result was written to vt_sp */
2467 sp->data.p = vt_sp;
2469 break;
2470 default:
2471 g_print ("%s\n", mono_type_full_name (rtype));
2472 g_assert_not_reached ();
2473 break;
2477 static MONO_NEVER_INLINE void
2478 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2480 MonoLMFExt ext;
2481 interp_push_lmf (&ext, frame);
2482 tramp ();
2483 interp_pop_lmf (&ext);
2486 static MONO_NEVER_INLINE MonoException*
2487 do_transform_method (InterpFrame *frame, ThreadContext *context)
2489 MonoLMFExt ext;
2490 /* Don't push lmf if we have no interp data */
2491 gboolean push_lmf = frame->parent != NULL;
2492 ERROR_DECL (error);
2494 /* Use the parent frame as the current frame is not complete yet */
2495 if (push_lmf)
2496 interp_push_lmf (&ext, frame->parent);
2498 mono_interp_transform_method (frame->imethod, context, error);
2500 if (push_lmf)
2501 interp_pop_lmf (&ext);
2503 return mono_error_convert_to_exception (error);
2506 static guchar*
2507 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start)
2509 stackval *first_arg = sp - csig->param_count;
2510 guchar *vt_sp = vt_sp_start;
2513 * We need to have the varargs linearly on the stack so the ArgIterator
2514 * can iterate over them. We pass the signature first and then copy them
2515 * one by one on the vtstack. At the end we pass the original vt_stack
2516 * so the callee (MINT_ARGLIST) can find the varargs space.
2518 *(gpointer*)vt_sp = csig;
2519 vt_sp += sizeof (gpointer);
2521 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2522 int align, arg_size;
2523 arg_size = mono_type_stack_size (csig->params [i], &align);
2524 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2526 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2527 vt_sp += arg_size;
2530 vt_sp += sizeof (gpointer);
2531 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2533 ((gpointer*)vt_sp) [-1] = vt_sp_start;
2535 return vt_sp;
2539 * These functions are the entry points into the interpreter from compiled code.
2540 * They are called by the interp_in wrappers. They have the following signature:
2541 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2542 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2543 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2544 * more wrappers then these functions.
2545 * this/static * ret/void * 16 arguments -> 64 functions.
2548 #define MAX_INTERP_ENTRY_ARGS 8
2550 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2551 InterpEntryData data; \
2552 (data).rmethod = (_method); \
2553 (data).res = (_res); \
2554 (data).this_arg = (_this_arg); \
2555 (data).many_args = NULL;
2557 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2558 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2559 interp_entry (&data); \
2561 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2562 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2563 (data).args [0] = arg1; \
2564 interp_entry (&data); \
2566 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2567 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2568 (data).args [0] = arg1; \
2569 (data).args [1] = arg2; \
2570 interp_entry (&data); \
2572 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2573 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2574 (data).args [0] = arg1; \
2575 (data).args [1] = arg2; \
2576 (data).args [2] = arg3; \
2577 interp_entry (&data); \
2579 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2580 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2581 (data).args [0] = arg1; \
2582 (data).args [1] = arg2; \
2583 (data).args [2] = arg3; \
2584 (data).args [3] = arg4; \
2585 interp_entry (&data); \
2587 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2588 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2589 (data).args [0] = arg1; \
2590 (data).args [1] = arg2; \
2591 (data).args [2] = arg3; \
2592 (data).args [3] = arg4; \
2593 (data).args [4] = arg5; \
2594 interp_entry (&data); \
2596 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2597 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2598 (data).args [0] = arg1; \
2599 (data).args [1] = arg2; \
2600 (data).args [2] = arg3; \
2601 (data).args [3] = arg4; \
2602 (data).args [4] = arg5; \
2603 (data).args [5] = arg6; \
2604 interp_entry (&data); \
2606 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2607 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2608 (data).args [0] = arg1; \
2609 (data).args [1] = arg2; \
2610 (data).args [2] = arg3; \
2611 (data).args [3] = arg4; \
2612 (data).args [4] = arg5; \
2613 (data).args [5] = arg6; \
2614 (data).args [6] = arg7; \
2615 interp_entry (&data); \
2617 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2618 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2619 (data).args [0] = arg1; \
2620 (data).args [1] = arg2; \
2621 (data).args [2] = arg3; \
2622 (data).args [3] = arg4; \
2623 (data).args [4] = arg5; \
2624 (data).args [5] = arg6; \
2625 (data).args [6] = arg7; \
2626 (data).args [7] = arg8; \
2627 interp_entry (&data); \
2630 #define ARGLIST0 InterpMethod *rmethod
2631 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2632 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2633 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2634 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2635 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2636 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2637 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2638 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2640 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2641 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2642 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2643 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2644 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2645 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2646 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2647 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2648 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2649 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2650 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2651 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2652 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2653 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2654 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2655 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2656 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2657 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2658 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2659 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2660 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2661 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2662 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2663 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2664 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2665 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2666 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2667 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2668 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2669 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2670 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2671 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2672 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2673 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2674 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2675 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2677 #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
2679 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2680 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2681 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2682 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2684 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2685 static void
2686 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2688 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2689 data.many_args = args;
2690 interp_entry (&data);
2693 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2695 // inline so we can alloc on stack
2696 #define alloc_storage_for_stackval(s, t, p) do { \
2697 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2698 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2699 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2700 if (p) \
2701 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2702 else \
2703 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2705 } while (0)
2707 static void
2708 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2710 InterpFrame *frame;
2711 ThreadContext *context;
2712 stackval result;
2713 stackval *args;
2714 MonoMethod *method;
2715 MonoMethodSignature *sig;
2716 CallContext *ccontext = (CallContext*) ccontext_untyped;
2717 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2718 gpointer orig_domain = NULL, attach_cookie;
2719 int i;
2721 if (rmethod->needs_thread_attach)
2722 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2724 context = get_context ();
2726 method = rmethod->method;
2727 sig = mono_method_signature_internal (method);
2728 if (method->string_ctor) {
2729 MonoMethodSignature *newsig = g_alloca (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
2730 memcpy (newsig, sig, mono_metadata_signature_size (sig));
2731 newsig->ret = m_class_get_byval_arg (mono_defaults.string_class);
2732 sig = newsig;
2735 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2737 frame = alloc_frame (context, &result, NULL, rmethod, args, &result);
2739 /* Allocate storage for value types */
2740 for (i = 0; i < sig->param_count; i++) {
2741 MonoType *type = sig->params [i];
2742 alloc_storage_for_stackval (&frame->stack_args [i + sig->hasthis], type, sig->pinvoke);
2745 if (sig->ret->type != MONO_TYPE_VOID)
2746 alloc_storage_for_stackval (frame->retval, sig->ret, sig->pinvoke);
2748 /* Copy the args saved in the trampoline to the frame stack */
2749 mono_arch_get_native_call_context_args (ccontext, frame, sig);
2751 ERROR_DECL (error);
2752 interp_exec_method (frame, context, error);
2754 g_assert (!context->has_resume_state);
2756 if (rmethod->needs_thread_attach)
2757 mono_threads_detach_coop (orig_domain, &attach_cookie);
2759 /* Write back the return value */
2760 /* 'frame' is still valid */
2761 mono_arch_set_native_call_context_ret (ccontext, frame, sig);
2764 #else
2766 static void
2767 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2769 g_assert_not_reached ();
2772 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2774 static InterpMethod*
2775 lookup_method_pointer (gpointer addr)
2777 MonoDomain *domain = mono_domain_get ();
2778 MonoJitDomainInfo *info = domain_jit_info (domain);
2779 InterpMethod *res = NULL;
2781 mono_domain_lock (domain);
2782 if (info->interp_method_pointer_hash)
2783 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2784 mono_domain_unlock (domain);
2786 return res;
2789 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2790 static void
2791 interp_no_native_to_managed (void)
2793 g_error ("interpreter: native-to-managed transition not available on this platform");
2795 #endif
2797 static void
2798 no_llvmonly_interp_method_pointer (void)
2800 g_assert_not_reached ();
2804 * interp_create_method_pointer_llvmonly:
2806 * Return an ftndesc for entering the interpreter and executing METHOD.
2808 static MonoFtnDesc*
2809 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2811 MonoDomain *domain = mono_domain_get ();
2812 gpointer addr, entry_func, entry_wrapper;
2813 MonoMethodSignature *sig;
2814 MonoMethod *wrapper;
2815 MonoJitDomainInfo *info;
2816 InterpMethod *imethod;
2818 imethod = mono_interp_get_imethod (domain, method, error);
2819 return_val_if_nok (error, NULL);
2821 if (unbox) {
2822 if (imethod->llvmonly_unbox_entry)
2823 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2824 } else {
2825 if (imethod->jit_entry)
2826 return (MonoFtnDesc*)imethod->jit_entry;
2829 sig = mono_method_signature_internal (method);
2832 * The entry functions need access to the method to call, so we have
2833 * to use a ftndesc. The caller uses a normal signature, while the
2834 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2835 * a gsharedvt_in_sig wrapper.
2837 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2839 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2840 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2841 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2842 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2844 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2845 g_assert_not_reached ();
2846 //entry_func = (gpointer)interp_entry_general;
2847 } else if (sig->hasthis) {
2848 if (sig->ret->type == MONO_TYPE_VOID)
2849 entry_func = entry_funcs_instance [sig->param_count];
2850 else
2851 entry_func = entry_funcs_instance_ret [sig->param_count];
2852 } else {
2853 if (sig->ret->type == MONO_TYPE_VOID)
2854 entry_func = entry_funcs_static [sig->param_count];
2855 else
2856 entry_func = entry_funcs_static_ret [sig->param_count];
2858 g_assert (entry_func);
2860 /* Encode unbox in the lower bit of imethod */
2861 gpointer entry_arg = imethod;
2862 if (unbox)
2863 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2864 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2866 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2868 info = domain_jit_info (domain);
2869 mono_domain_lock (domain);
2870 if (!info->interp_method_pointer_hash)
2871 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2872 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2873 mono_domain_unlock (domain);
2875 mono_memory_barrier ();
2876 if (unbox)
2877 imethod->llvmonly_unbox_entry = addr;
2878 else
2879 imethod->jit_entry = addr;
2881 return (MonoFtnDesc*)addr;
2885 * interp_create_method_pointer:
2887 * Return a function pointer which can be used to call METHOD using the
2888 * interpreter. Return NULL for methods which are not supported.
2890 static gpointer
2891 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2893 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2894 if (mono_llvm_only)
2895 return (gpointer)no_llvmonly_interp_method_pointer;
2896 return (gpointer)interp_no_native_to_managed;
2897 #else
2898 gpointer addr, entry_func, entry_wrapper = NULL;
2899 MonoDomain *domain = mono_domain_get ();
2900 MonoJitDomainInfo *info;
2901 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2903 if (mono_llvm_only)
2904 return (gpointer)no_llvmonly_interp_method_pointer;
2906 if (imethod->jit_entry)
2907 return imethod->jit_entry;
2909 if (compile && !imethod->transformed) {
2910 /* Return any errors from method compilation */
2911 mono_interp_transform_method (imethod, get_context (), error);
2912 return_val_if_nok (error, NULL);
2915 MonoMethodSignature *sig = mono_method_signature_internal (method);
2916 if (method->string_ctor) {
2917 MonoMethodSignature *newsig = g_alloca (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
2918 memcpy (newsig, sig, mono_metadata_signature_size (sig));
2919 newsig->ret = m_class_get_byval_arg (mono_defaults.string_class);
2920 sig = newsig;
2923 if (mono_llvm_only)
2924 /* The caller should call interp_create_method_pointer_llvmonly */
2925 g_assert_not_reached ();
2927 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2928 return imethod;
2930 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2932 * Interp in wrappers get the argument in the rgctx register. If
2933 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2934 * on that arch the rgctx register is not scratch, so we use a
2935 * separate temp register. We should update the wrappers for this
2936 * if we really care about those architectures (arm).
2938 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2940 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2941 #endif
2942 if (entry_wrapper) {
2943 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2944 entry_func = (gpointer)interp_entry_general;
2945 } else if (sig->hasthis) {
2946 if (sig->ret->type == MONO_TYPE_VOID)
2947 entry_func = entry_funcs_instance [sig->param_count];
2948 else
2949 entry_func = entry_funcs_instance_ret [sig->param_count];
2950 } else {
2951 if (sig->ret->type == MONO_TYPE_VOID)
2952 entry_func = entry_funcs_static [sig->param_count];
2953 else
2954 entry_func = entry_funcs_static_ret [sig->param_count];
2956 } else {
2957 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2958 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2959 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2960 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2961 #else
2962 mono_error_cleanup (error);
2963 error_init_reuse (error);
2964 if (!mono_native_to_interp_trampoline) {
2965 if (mono_aot_only) {
2966 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2967 } else {
2968 MonoTrampInfo *info;
2969 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2970 mono_tramp_info_register (info, NULL);
2973 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2974 /* We need the lmf wrapper only when being called from mixed mode */
2975 if (sig->pinvoke)
2976 entry_func = (gpointer)interp_entry_from_trampoline;
2977 else {
2978 static gpointer cached_func = NULL;
2979 if (!cached_func) {
2980 cached_func = mono_jit_compile_method_jit_only (mini_get_interp_lmf_wrapper ("mono_interp_entry_from_trampoline", (gpointer) mono_interp_entry_from_trampoline), error);
2981 mono_memory_barrier ();
2983 entry_func = cached_func;
2985 #endif
2988 g_assert (entry_func);
2989 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2990 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2991 ftndesc->addr = entry_func;
2992 ftndesc->arg = imethod;
2993 mono_error_assert_ok (error);
2996 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2997 * rgctx register using a trampoline.
3000 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
3002 info = domain_jit_info (domain);
3003 mono_domain_lock (domain);
3004 if (!info->interp_method_pointer_hash)
3005 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
3006 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
3007 mono_domain_unlock (domain);
3009 mono_memory_barrier ();
3010 imethod->jit_entry = addr;
3012 return addr;
3013 #endif
3016 static void
3017 interp_free_method (MonoDomain *domain, MonoMethod *method)
3019 MonoJitDomainInfo *info = domain_jit_info (domain);
3021 mono_domain_jit_code_hash_lock (domain);
3022 /* InterpMethod is allocated in the domain mempool. We might haven't
3023 * allocated an InterpMethod for this instance yet */
3024 mono_internal_hash_table_remove (&info->interp_code_hash, method);
3025 mono_domain_jit_code_hash_unlock (domain);
3028 #if COUNT_OPS
3029 static long opcode_counts[MINT_LASTOP];
3031 #define COUNT_OP(op) opcode_counts[op]++
3032 #else
3033 #define COUNT_OP(op)
3034 #endif
3036 #if DEBUG_INTERP
3037 #define DUMP_INSTR() \
3038 if (tracing > 1) { \
3039 char *ins; \
3040 if (sp > frame->stack) { \
3041 ins = dump_stack (frame->stack, sp); \
3042 } else { \
3043 ins = g_strdup (""); \
3045 sp->data.l = 0; \
3046 output_indent (); \
3047 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
3048 char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
3049 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
3050 g_free (mn); \
3051 g_free (ins); \
3052 g_free (disasm); \
3054 #else
3055 #define DUMP_INSTR()
3056 #endif
3058 #define INIT_VTABLE(vtable) do { \
3059 if (G_UNLIKELY (!(vtable)->initialized)) { \
3060 mono_runtime_class_init_full ((vtable), error); \
3061 if (!is_ok (error)) \
3062 goto throw_error_label; \
3064 } while (0);
3066 static MonoObject*
3067 mono_interp_new (MonoDomain* domain, MonoClass* klass)
3069 ERROR_DECL (error);
3070 MonoObject* const object = mono_object_new_checked (domain, klass, error);
3071 mono_error_cleanup (error); // FIXME: do not swallow the error
3072 return object;
3075 static void
3076 mono_interp_load_remote_field (
3077 InterpMethod* imethod,
3078 MonoObject* o,
3079 const guint16* ip,
3080 stackval* sp)
3082 g_assert (o); // Caller checks and throws exception properly.
3084 void* addr;
3085 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
3087 #ifndef DISABLE_REMOTING
3088 gpointer tmp;
3089 if (mono_object_is_transparent_proxy (o)) {
3090 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3091 ERROR_DECL (error);
3092 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3093 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3094 } else
3095 #endif
3096 addr = (char*)o + field->offset;
3097 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3100 static
3101 guchar* // Return new vt_sp instead of take-address.
3102 mono_interp_load_remote_field_vt (
3103 InterpMethod* imethod,
3104 MonoObject* o,
3105 const guint16* ip,
3106 stackval* sp,
3107 guchar* vt_sp)
3109 g_assert (o); // Caller checks and throws exception properly.
3111 void* addr;
3112 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
3113 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
3114 int const i32 = mono_class_value_size (klass, NULL);
3116 #ifndef DISABLE_REMOTING
3117 gpointer tmp;
3118 if (mono_object_is_transparent_proxy (o)) {
3119 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3120 ERROR_DECL (error);
3121 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3122 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3123 } else
3124 #endif
3125 addr = (char*)o + field->offset;
3126 sp [-1].data.p = vt_sp;
3127 memcpy (vt_sp, addr, i32);
3128 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3131 static gboolean
3132 mono_interp_isinst (MonoObject* object, MonoClass* klass)
3134 ERROR_DECL (error);
3135 gboolean isinst;
3136 MonoClass *obj_class = mono_object_class (object);
3137 // mono_class_is_assignable_from_checked can't handle remoting casts
3138 if (mono_class_is_transparent_proxy (obj_class))
3139 isinst = mono_object_isinst_checked (object, klass, error) != NULL;
3140 else
3141 mono_class_is_assignable_from_checked (klass, obj_class, &isinst, error);
3142 mono_error_cleanup (error); // FIXME: do not swallow the error
3143 return isinst;
3146 // Do not inline use of alloca.
3147 static MONO_NEVER_INLINE void
3148 mono_interp_calli_nat_dynamic_pinvoke (
3149 // Parameters are sorted by name.
3150 InterpFrame* child_frame,
3151 guchar* code,
3152 ThreadContext* context,
3153 MonoMethodSignature* csignature,
3154 MonoError* error)
3156 // Recompute to limit parameters, which can also contribute to caller stack.
3157 InterpMethod* const imethod = child_frame->parent->imethod;
3159 g_assert (imethod->method->dynamic && csignature->pinvoke);
3161 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3162 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
3163 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
3165 MonoMethodPInvoke iinfo;
3166 memset (&iinfo, 0, sizeof (iinfo));
3168 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
3170 for (int i = csignature->param_count; i >= 0; i--)
3171 if (mspecs [i])
3172 mono_metadata_free_marshal_spec (mspecs [i]);
3175 ERROR_DECL (error);
3176 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
3177 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3180 interp_exec_method (child_frame, context, error);
3183 static MonoException*
3184 mono_interp_leave (InterpFrame* child_frame)
3186 stackval tmp_sp;
3188 * We need for mono_thread_get_undeniable_exception to be able to unwind
3189 * to check the abort threshold. For this to work we use child_frame as a
3190 * dummy frame that is stored in the lmf and serves as the transition frame
3192 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3194 return (MonoException*)tmp_sp.data.p;
3197 static void
3198 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3200 guint64 a_val = 0, b_val = 0;
3202 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3203 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3204 sp->data.i = (a_val & b_val) == b_val;
3207 static int
3208 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3210 InterpMethod* const imethod = frame->imethod;
3211 MonoClass* const c = (MonoClass*)imethod->data_items [ip [1]];
3213 int const size = mono_class_value_size (c, NULL);
3215 guint16 offset = ip [2];
3216 guint16 pop_vt_sp = !ip [3];
3218 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3219 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3221 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3224 static int
3225 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp)
3227 InterpMethod* const imethod = frame->imethod;
3229 MonoObject* o; // See the comment about GC safety.
3230 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [ip [1]];
3231 MonoClass* const c = vtable->klass;
3233 int const size = mono_class_value_size (c, NULL);
3235 guint16 offset = ip [2];
3236 guint16 pop_vt_sp = !ip [3];
3238 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3239 mono_value_copy_internal (mono_object_get_data (o), sp [-1 - offset].data.p, c);
3241 sp [-1 - offset].data.p = o;
3242 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3245 static void
3246 mono_interp_box (InterpFrame* frame, const guint16* ip, stackval* sp)
3248 MonoObject *o; // See the comment about GC safety.
3249 MonoVTable * const vtable = (MonoVTable*)frame->imethod->data_items [ip [1]];
3251 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3253 guint16 const offset = ip [2];
3255 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (o), FALSE);
3257 sp [-1 - offset].data.p = o;
3260 static int
3261 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3263 InterpMethod* const imethod = frame->imethod;
3264 MonoClassField *field;
3266 MonoObject* const o = sp [-2].data.o;
3268 field = (MonoClassField*)imethod->data_items[ip [1]];
3269 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3270 int const i32 = mono_class_value_size (klass, NULL);
3272 #ifndef DISABLE_REMOTING
3273 if (mono_object_is_transparent_proxy (o)) {
3274 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3275 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3276 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3277 } else
3278 #endif
3279 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3281 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3284 // varargs in wasm consumes extra linear stack per call-site.
3285 // These g_warning/g_error wrappers fix that. It is not the
3286 // small wasm stack, but conserving it is still desirable.
3287 static void
3288 g_warning_d (const char *format, int d)
3290 g_warning (format, d);
3293 static void
3294 g_warning_ds (const char *format, int d, const char *s)
3296 g_warning (format, d, s);
3299 #if !USE_COMPUTED_GOTO
3300 static void
3301 g_error_xsx (const char *format, int x1, const char *s, int x2)
3303 g_error (format, x1, s, x2);
3305 #endif
3307 static MONO_ALWAYS_INLINE gboolean
3308 method_entry (ThreadContext *context, InterpFrame *frame,
3309 #if DEBUG_INTERP
3310 int *out_tracing,
3311 #endif
3312 MonoException **out_ex, FrameClauseArgs *clause_args)
3314 gboolean slow = FALSE;
3316 #if DEBUG_INTERP
3317 debug_enter (frame, out_tracing);
3318 #endif
3320 *out_ex = NULL;
3321 if (!G_UNLIKELY (frame->imethod->transformed)) {
3322 slow = TRUE;
3323 #if DEBUG_INTERP
3324 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
3325 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3326 g_free (mn);
3327 #endif
3328 frame->ip = NULL;
3329 MonoException *ex = do_transform_method (frame, context);
3330 if (ex) {
3331 *out_ex = ex;
3332 return slow;
3336 if (!clause_args || clause_args->base_frame)
3337 alloc_stack_data (context, frame, frame->imethod->alloca_size);
3339 return slow;
3342 /* Save the state of the interpeter main loop into FRAME */
3343 #define SAVE_INTERP_STATE(frame) do { \
3344 frame->state.ip = ip; \
3345 frame->state.sp = sp; \
3346 frame->state.vt_sp = vt_sp; \
3347 frame->state.is_void = is_void; \
3348 frame->state.finally_ips = finally_ips; \
3349 frame->state.clause_args = clause_args; \
3350 } while (0)
3352 /* Load and clear state from FRAME */
3353 #define LOAD_INTERP_STATE(frame) do { \
3354 ip = frame->state.ip; \
3355 sp = frame->state.sp; \
3356 is_void = frame->state.is_void; \
3357 vt_sp = frame->state.vt_sp; \
3358 finally_ips = frame->state.finally_ips; \
3359 clause_args = frame->state.clause_args; \
3360 locals = (unsigned char *)frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size; \
3361 frame->state.ip = NULL; \
3362 } while (0)
3364 /* Initialize interpreter state for executing FRAME */
3365 #define INIT_INTERP_STATE(frame, _clause_args) do { \
3366 ip = _clause_args ? (_clause_args)->start_with_ip : (frame)->imethod->code; \
3367 sp = (frame)->stack; \
3368 vt_sp = (unsigned char *) sp + (frame)->imethod->stack_size; \
3369 locals = (unsigned char *) vt_sp + (frame)->imethod->vt_stack_size; \
3370 finally_ips = NULL; \
3371 } while (0)
3374 * If CLAUSE_ARGS is non-null, start executing from it.
3375 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3376 * to return error information.
3377 * FRAME is only valid until the next call to alloc_frame ().
3379 static MONO_NEVER_INLINE void
3380 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3382 InterpMethod *cmethod;
3383 MonoException *ex;
3384 gboolean is_void;
3385 stackval *retval;
3387 /* Interpreter main loop state (InterpState) */
3388 const guint16 *ip = NULL;
3389 stackval *sp;
3390 unsigned char *vt_sp;
3391 unsigned char *locals = NULL;
3392 GSList *finally_ips = NULL;
3394 #if DEBUG_INTERP
3395 int tracing = global_tracing;
3396 unsigned char *vtalloc;
3397 #endif
3398 #if USE_COMPUTED_GOTO
3399 static void * const in_labels[] = {
3400 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3401 #include "mintops.def"
3403 #endif
3405 if (method_entry (context, frame,
3406 #if DEBUG_INTERP
3407 &tracing,
3408 #endif
3409 &ex, clause_args)) {
3410 if (ex)
3411 THROW_EX (ex, NULL);
3412 EXCEPTION_CHECKPOINT;
3415 if (clause_args && clause_args->base_frame)
3416 memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size);
3418 INIT_INTERP_STATE (frame, clause_args);
3420 #if DEBUG_INTERP
3421 vtalloc = vt_sp;
3422 #endif
3424 if (clause_args && clause_args->filter_exception) {
3425 sp->data.p = clause_args->filter_exception;
3426 sp++;
3429 #ifdef ENABLE_EXPERIMENT_TIERED
3430 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0);
3431 #endif
3432 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3434 #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND)
3435 mono_threads_safepoint ();
3436 #endif
3438 * using while (ip < end) may result in a 15% performance drop,
3439 * but it may be useful for debug
3441 while (1) {
3442 MintOpcode opcode;
3443 main_loop:
3444 /* g_assert (sp >= frame->stack); */
3445 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3446 DUMP_INSTR();
3447 MINT_IN_SWITCH (*ip) {
3448 MINT_IN_CASE(MINT_INITLOCALS)
3449 memset (locals, 0, frame->imethod->locals_size);
3450 ++ip;
3451 MINT_IN_BREAK;
3452 MINT_IN_CASE(MINT_NOP)
3453 MINT_IN_CASE(MINT_NIY)
3454 g_assert_not_reached ();
3455 MINT_IN_BREAK;
3456 MINT_IN_CASE(MINT_BREAK)
3457 ++ip;
3458 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3459 MINT_IN_BREAK;
3460 MINT_IN_CASE(MINT_BREAKPOINT)
3461 ++ip;
3462 mono_break ();
3463 MINT_IN_BREAK;
3464 MINT_IN_CASE(MINT_LDNULL)
3465 sp->data.p = NULL;
3466 ++ip;
3467 ++sp;
3468 MINT_IN_BREAK;
3469 MINT_IN_CASE(MINT_ARGLIST)
3470 sp->data.p = vt_sp;
3471 *(gpointer*)sp->data.p = ((gpointer*)frame->retval->data.p) [-1];
3472 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3473 ++ip;
3474 ++sp;
3475 MINT_IN_BREAK;
3476 MINT_IN_CASE(MINT_VTRESULT) {
3477 int ret_size = ip [1];
3478 unsigned char *ret_vt_sp = vt_sp;
3479 vt_sp -= READ32(ip + 2);
3480 if (ret_size > 0) {
3481 memmove (vt_sp, ret_vt_sp, ret_size);
3482 sp [-1].data.p = vt_sp;
3483 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3485 ip += 4;
3486 MINT_IN_BREAK;
3488 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3489 MINT_IN_CASE(MINT_LDC_I4_M1)
3490 LDC(-1);
3491 MINT_IN_BREAK;
3492 MINT_IN_CASE(MINT_LDC_I4_0)
3493 LDC(0);
3494 MINT_IN_BREAK;
3495 MINT_IN_CASE(MINT_LDC_I4_1)
3496 LDC(1);
3497 MINT_IN_BREAK;
3498 MINT_IN_CASE(MINT_LDC_I4_2)
3499 LDC(2);
3500 MINT_IN_BREAK;
3501 MINT_IN_CASE(MINT_LDC_I4_3)
3502 LDC(3);
3503 MINT_IN_BREAK;
3504 MINT_IN_CASE(MINT_LDC_I4_4)
3505 LDC(4);
3506 MINT_IN_BREAK;
3507 MINT_IN_CASE(MINT_LDC_I4_5)
3508 LDC(5);
3509 MINT_IN_BREAK;
3510 MINT_IN_CASE(MINT_LDC_I4_6)
3511 LDC(6);
3512 MINT_IN_BREAK;
3513 MINT_IN_CASE(MINT_LDC_I4_7)
3514 LDC(7);
3515 MINT_IN_BREAK;
3516 MINT_IN_CASE(MINT_LDC_I4_8)
3517 LDC(8);
3518 MINT_IN_BREAK;
3519 MINT_IN_CASE(MINT_LDC_I4_S)
3520 sp->data.i = (short)ip [1];
3521 ip += 2;
3522 ++sp;
3523 MINT_IN_BREAK;
3524 MINT_IN_CASE(MINT_LDC_I4)
3525 ++ip;
3526 sp->data.i = READ32 (ip);
3527 ip += 2;
3528 ++sp;
3529 MINT_IN_BREAK;
3530 MINT_IN_CASE(MINT_LDC_I8)
3531 ++ip;
3532 sp->data.l = READ64 (ip);
3533 ip += 4;
3534 ++sp;
3535 MINT_IN_BREAK;
3536 MINT_IN_CASE(MINT_LDC_I8_S)
3537 sp->data.l = (short)ip [1];
3538 ip += 2;
3539 ++sp;
3540 MINT_IN_BREAK;
3541 MINT_IN_CASE(MINT_LDC_R4) {
3542 guint32 val;
3543 ++ip;
3544 val = READ32(ip);
3545 sp->data.f_r4 = * (float *)&val;
3546 ip += 2;
3547 ++sp;
3548 MINT_IN_BREAK;
3550 MINT_IN_CASE(MINT_LDC_R8)
3551 sp->data.l = READ64 (ip + 1); /* note union usage */
3552 ip += 5;
3553 ++sp;
3554 MINT_IN_BREAK;
3555 MINT_IN_CASE(MINT_DUP)
3556 sp [0] = sp[-1];
3557 ++sp;
3558 ++ip;
3559 MINT_IN_BREAK;
3560 MINT_IN_CASE(MINT_DUP_VT) {
3561 int const i32 = READ32 (ip + 1);
3562 sp->data.p = vt_sp;
3563 memcpy(sp->data.p, sp [-1].data.p, i32);
3564 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3565 ++sp;
3566 ip += 3;
3567 MINT_IN_BREAK;
3569 MINT_IN_CASE(MINT_POP) {
3570 sp--;
3571 ip++;
3572 MINT_IN_BREAK;
3574 MINT_IN_CASE(MINT_POP1) {
3575 sp [-2] = sp [-1];
3576 sp--;
3577 ip++;
3578 MINT_IN_BREAK;
3580 MINT_IN_CASE(MINT_JMP) {
3581 g_assert (sp == frame->stack);
3582 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [ip [1]];
3584 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3585 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3587 if (!new_method->transformed) {
3588 error_init_reuse (error);
3590 frame->ip = ip;
3591 mono_interp_transform_method (new_method, context, error);
3592 MonoException *ex = mono_error_convert_to_exception (error);
3593 if (ex)
3594 THROW_EX (ex, ip);
3596 ip += 2;
3597 const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
3598 frame->imethod = new_method;
3600 * We allocate the stack frame from scratch and store the arguments in the
3601 * locals again since it's possible for the caller stack frame to be smaller
3602 * than the callee stack frame (at the interp level)
3604 if (realloc_frame) {
3605 alloc_stack_data (context, frame, frame->imethod->alloca_size);
3606 memset (frame->stack, 0, frame->imethod->alloca_size);
3607 sp = frame->stack;
3609 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3610 #if DEBUG_INTERP
3611 vtalloc = vt_sp;
3612 #endif
3613 locals = vt_sp + frame->imethod->vt_stack_size;
3614 ip = frame->imethod->code;
3615 MINT_IN_BREAK;
3617 MINT_IN_CASE(MINT_CALLI) {
3618 MonoMethodSignature *csignature;
3620 frame->ip = ip;
3622 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3623 ip += 2;
3624 --sp;
3626 cmethod = (InterpMethod*)sp->data.p;
3627 if (cmethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3628 cmethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (cmethod->method, FALSE, FALSE), error);
3629 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3632 is_void = csignature->ret->type == MONO_TYPE_VOID;
3633 retval = is_void ? NULL : sp;
3635 sp->data.p = vt_sp;
3636 /* decrement by the actual number of args */
3637 sp -= csignature->param_count;
3638 if (csignature->hasthis)
3639 --sp;
3641 if (csignature->hasthis) {
3642 MonoObject *this_arg = (MonoObject*)sp->data.p;
3644 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3645 gpointer unboxed = mono_object_unbox_internal (this_arg);
3646 sp [0].data.p = unboxed;
3650 goto call;
3652 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3653 gpointer target_ip = sp [-1].data.p;
3654 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3655 int opcode = ip [2];
3656 gboolean save_last_error = ip [3];
3658 sp--;
3659 frame->ip = ip;
3661 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3662 EXCEPTION_CHECKPOINT_GC_UNSAFE;
3663 CHECK_RESUME_STATE (context);
3664 ip += 4;
3665 MINT_IN_BREAK;
3667 MINT_IN_CASE(MINT_CALLI_NAT) {
3668 MonoMethodSignature* csignature;
3670 frame->ip = ip;
3672 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3674 ip += 3;
3675 --sp;
3676 guchar* const code = (guchar*)sp->data.p;
3677 retval = sp;
3679 sp->data.p = vt_sp;
3680 /* decrement by the actual number of args */
3681 sp -= csignature->param_count;
3682 if (csignature->hasthis)
3683 --sp;
3685 // FIXME Free this frame earlier?
3686 InterpFrame* const child_frame = alloc_frame (context, &retval, frame, NULL, sp, retval);
3688 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3689 mono_interp_calli_nat_dynamic_pinvoke (child_frame, code, context, csignature, error);
3690 } else {
3691 const gboolean save_last_error = ip [-3 + 2];
3692 ves_pinvoke_method (child_frame, csignature, (MonoFuncV) code, context, save_last_error);
3694 CHECK_RESUME_STATE (context);
3696 if (csignature->ret->type != MONO_TYPE_VOID) {
3697 *sp = *retval;
3698 sp++;
3700 MINT_IN_BREAK;
3702 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3703 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3704 MonoObject *this_arg;
3705 is_void = *ip == MINT_VCALLVIRT_FAST;
3706 int slot;
3708 frame->ip = ip;
3710 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3711 slot = (gint16)ip [2];
3712 ip += 3;
3713 sp->data.p = vt_sp;
3715 retval = is_void ? NULL : sp;
3717 /* decrement by the actual number of args */
3718 sp -= cmethod->param_count + cmethod->hasthis;
3720 this_arg = (MonoObject*)sp->data.p;
3722 cmethod = get_virtual_method_fast (cmethod, this_arg->vtable, slot);
3723 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) {
3724 /* unbox */
3725 gpointer unboxed = mono_object_unbox_internal (this_arg);
3726 sp [0].data.p = unboxed;
3729 InterpMethodCodeType code_type = cmethod->code_type;
3731 g_assert (code_type == IMETHOD_CODE_UNKNOWN ||
3732 code_type == IMETHOD_CODE_INTERP ||
3733 code_type == IMETHOD_CODE_COMPILED);
3735 if (G_UNLIKELY (code_type == IMETHOD_CODE_UNKNOWN)) {
3736 MonoMethodSignature *sig = mono_method_signature_internal (cmethod->method);
3737 if (mono_interp_jit_call_supported (cmethod->method, sig))
3738 code_type = IMETHOD_CODE_COMPILED;
3739 else
3740 code_type = IMETHOD_CODE_INTERP;
3741 cmethod->code_type = code_type;
3744 if (code_type == IMETHOD_CODE_INTERP) {
3746 goto call;
3748 } else if (code_type == IMETHOD_CODE_COMPILED) {
3749 error_init_reuse (error);
3750 do_jit_call (sp, vt_sp, context, frame, cmethod, error);
3751 if (!is_ok (error)) {
3752 MonoException *ex = mono_error_convert_to_exception (error);
3753 THROW_EX (ex, ip);
3756 CHECK_RESUME_STATE (context);
3758 if (cmethod->rtype->type != MONO_TYPE_VOID)
3759 sp++;
3762 MINT_IN_BREAK;
3764 MINT_IN_CASE(MINT_CALL_VARARG) {
3765 MonoMethodSignature *csig;
3767 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3769 /* The real signature for vararg calls */
3770 csig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3772 frame->ip = ip;
3774 // Retval must be set unconditionally due to MINT_ARGLIST.
3775 // is_void guides exit_frame instead of retval nullness.
3776 retval = sp;
3777 is_void = csig->ret->type == MONO_TYPE_VOID;
3779 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3780 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3782 ip += 3;
3783 sp->data.p = vt_sp;
3785 /* decrement by the actual number of args */
3786 // FIXME This seems excessive: frame and csig param_count.
3787 sp -= cmethod->param_count + cmethod->hasthis + csig->param_count - csig->sentinelpos;
3789 goto call;
3791 MINT_IN_CASE(MINT_VCALL)
3792 MINT_IN_CASE(MINT_CALL)
3793 MINT_IN_CASE(MINT_CALLVIRT)
3794 MINT_IN_CASE(MINT_VCALLVIRT) {
3795 // FIXME CALLVIRT opcodes are not used on netcore. We should kill them.
3796 // FIXME braces from here until call: label.
3797 is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3798 gboolean is_virtual;
3799 is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3801 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3802 sp->data.p = vt_sp;
3803 retval = is_void ? NULL : sp;
3805 /* decrement by the actual number of args */
3806 sp -= ip [2];
3808 if (is_virtual) {
3809 MonoObject *this_arg = (MonoObject*)sp->data.p;
3811 cmethod = get_virtual_method (cmethod, this_arg->vtable);
3812 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) {
3813 /* unbox */
3814 gpointer unboxed = mono_object_unbox_internal (this_arg);
3815 sp [0].data.p = unboxed;
3819 frame->ip = ip;
3820 #ifdef ENABLE_EXPERIMENT_TIERED
3821 ip += 5;
3822 #else
3823 ip += 3;
3824 #endif
3825 call:;
3826 // FIXME This assumes a grow-down stack.
3827 gpointer native_stack_addr = frame->native_stack_addr ? (gpointer)((guint8*)frame->native_stack_addr - 1) : (gpointer)&retval;
3830 * Make a non-recursive call by loading the new interpreter state based on child frame,
3831 * and going back to the main loop.
3833 SAVE_INTERP_STATE (frame);
3835 frame = alloc_frame (context, native_stack_addr, frame, cmethod, sp, retval);
3837 #if DEBUG_INTERP
3838 int tracing;
3839 #endif
3840 if (method_entry (context, frame,
3841 #if DEBUG_INTERP
3842 &tracing,
3843 #endif
3844 &ex, NULL)) {
3845 if (ex)
3846 THROW_EX (ex, NULL);
3847 EXCEPTION_CHECKPOINT;
3850 clause_args = NULL;
3851 INIT_INTERP_STATE (frame, clause_args);
3853 MINT_IN_BREAK;
3855 MINT_IN_CASE(MINT_JIT_CALL) {
3856 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3857 error_init_reuse (error);
3858 frame->ip = ip;
3859 sp -= rmethod->param_count + rmethod->hasthis;
3860 do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3861 if (!is_ok (error)) {
3862 MonoException *ex = mono_error_convert_to_exception (error);
3863 THROW_EX (ex, ip);
3865 ip += 2;
3867 CHECK_RESUME_STATE (context);
3869 if (rmethod->rtype->type != MONO_TYPE_VOID)
3870 sp++;
3872 MINT_IN_BREAK;
3874 MINT_IN_CASE(MINT_JIT_CALL2) {
3875 #ifdef ENABLE_EXPERIMENT_TIERED
3876 InterpMethod *rmethod = (InterpMethod *) READ64 (ip + 1);
3878 error_init_reuse (error);
3879 frame->ip = ip;
3881 sp -= rmethod->param_count + rmethod->hasthis;
3882 do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3883 if (!is_ok (error)) {
3884 MonoException *ex = mono_error_convert_to_exception (error);
3885 THROW_EX (ex, ip);
3887 ip += 5;
3889 CHECK_RESUME_STATE (context);
3891 if (rmethod->rtype->type != MONO_TYPE_VOID)
3892 sp++;
3893 #else
3894 g_error ("MINT_JIT_ICALL2 shouldn't be used");
3895 #endif
3896 MINT_IN_BREAK;
3898 MINT_IN_CASE(MINT_CALLRUN) {
3899 #ifndef ENABLE_NETCORE
3900 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [1]];
3901 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3903 sp->data.p = vt_sp;
3904 retval = sp;
3906 sp -= sig->param_count;
3907 if (sig->hasthis)
3908 sp--;
3910 MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval);
3911 if (ex)
3912 THROW_EX (ex, ip);
3914 if (sig->ret->type != MONO_TYPE_VOID) {
3915 *sp = *retval;
3916 sp++;
3918 ip += 3;
3919 #else
3920 g_assert_not_reached ();
3921 #endif
3922 MINT_IN_BREAK;
3924 MINT_IN_CASE(MINT_RET)
3925 --sp;
3926 *frame->retval = *sp;
3927 if (sp > frame->stack)
3928 g_warning_d ("ret: more values on stack: %d", sp - frame->stack);
3929 goto exit_frame;
3930 MINT_IN_CASE(MINT_RET_VOID)
3931 if (sp > frame->stack)
3932 g_warning_ds ("ret.void: more values on stack: %d %s", sp - frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3933 goto exit_frame;
3934 MINT_IN_CASE(MINT_RET_VT) {
3935 int const i32 = READ32 (ip + 1);
3936 --sp;
3937 memcpy(frame->retval->data.p, sp->data.p, i32);
3938 if (sp > frame->stack)
3939 g_warning_d ("ret.vt: more values on stack: %d", sp - frame->stack);
3940 goto exit_frame;
3943 #ifdef ENABLE_EXPERIMENT_TIERED
3944 #define BACK_BRANCH_PROFILE(offset) do { \
3945 if (offset < 0) \
3946 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0); \
3947 } while (0);
3948 #else
3949 #define BACK_BRANCH_PROFILE(offset)
3950 #endif
3952 MINT_IN_CASE(MINT_BR_S) {
3953 short br_offset = (short) *(ip + 1);
3954 BACK_BRANCH_PROFILE (br_offset);
3955 ip += br_offset;
3956 MINT_IN_BREAK;
3958 MINT_IN_CASE(MINT_BR) {
3959 gint32 br_offset = (gint32) READ32(ip + 1);
3960 BACK_BRANCH_PROFILE (br_offset);
3961 ip += br_offset;
3962 MINT_IN_BREAK;
3965 #define ZEROP_S(datamem, op) \
3966 --sp; \
3967 if (sp->data.datamem op 0) { \
3968 gint16 br_offset = (gint16) ip [1]; \
3969 BACK_BRANCH_PROFILE (br_offset); \
3970 ip += br_offset; \
3971 } else \
3972 ip += 2;
3974 #define ZEROP(datamem, op) \
3975 --sp; \
3976 if (sp->data.datamem op 0) { \
3977 gint32 br_offset = (gint32)READ32(ip + 1); \
3978 BACK_BRANCH_PROFILE (br_offset); \
3979 ip += br_offset; \
3980 } else \
3981 ip += 3;
3983 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3984 ZEROP_S(i, ==);
3985 MINT_IN_BREAK;
3986 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3987 ZEROP_S(l, ==);
3988 MINT_IN_BREAK;
3989 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3990 ZEROP_S(f_r4, ==);
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3993 ZEROP_S(f, ==);
3994 MINT_IN_BREAK;
3995 MINT_IN_CASE(MINT_BRFALSE_I4)
3996 ZEROP(i, ==);
3997 MINT_IN_BREAK;
3998 MINT_IN_CASE(MINT_BRFALSE_I8)
3999 ZEROP(l, ==);
4000 MINT_IN_BREAK;
4001 MINT_IN_CASE(MINT_BRFALSE_R4)
4002 ZEROP_S(f_r4, ==);
4003 MINT_IN_BREAK;
4004 MINT_IN_CASE(MINT_BRFALSE_R8)
4005 ZEROP_S(f, ==);
4006 MINT_IN_BREAK;
4007 MINT_IN_CASE(MINT_BRTRUE_I4_S)
4008 ZEROP_S(i, !=);
4009 MINT_IN_BREAK;
4010 MINT_IN_CASE(MINT_BRTRUE_I8_S)
4011 ZEROP_S(l, !=);
4012 MINT_IN_BREAK;
4013 MINT_IN_CASE(MINT_BRTRUE_R4_S)
4014 ZEROP_S(f_r4, !=);
4015 MINT_IN_BREAK;
4016 MINT_IN_CASE(MINT_BRTRUE_R8_S)
4017 ZEROP_S(f, !=);
4018 MINT_IN_BREAK;
4019 MINT_IN_CASE(MINT_BRTRUE_I4)
4020 ZEROP(i, !=);
4021 MINT_IN_BREAK;
4022 MINT_IN_CASE(MINT_BRTRUE_I8)
4023 ZEROP(l, !=);
4024 MINT_IN_BREAK;
4025 MINT_IN_CASE(MINT_BRTRUE_R4)
4026 ZEROP(f_r4, !=);
4027 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_BRTRUE_R8)
4029 ZEROP(f, !=);
4030 MINT_IN_BREAK;
4031 #define CONDBR_S(cond) \
4032 sp -= 2; \
4033 if (cond) { \
4034 gint16 br_offset = (gint16) ip [1]; \
4035 BACK_BRANCH_PROFILE (br_offset); \
4036 ip += br_offset; \
4037 } else \
4038 ip += 2;
4039 #define BRELOP_S(datamem, op) \
4040 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
4042 #define CONDBR(cond) \
4043 sp -= 2; \
4044 if (cond) { \
4045 gint32 br_offset = (gint32) READ32 (ip + 1); \
4046 BACK_BRANCH_PROFILE (br_offset); \
4047 ip += br_offset; \
4048 } else \
4049 ip += 3;
4051 #define BRELOP(datamem, op) \
4052 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
4054 MINT_IN_CASE(MINT_BEQ_I4_S)
4055 BRELOP_S(i, ==)
4056 MINT_IN_BREAK;
4057 MINT_IN_CASE(MINT_BEQ_I8_S)
4058 BRELOP_S(l, ==)
4059 MINT_IN_BREAK;
4060 MINT_IN_CASE(MINT_BEQ_R4_S)
4061 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
4062 MINT_IN_BREAK;
4063 MINT_IN_CASE(MINT_BEQ_R8_S)
4064 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
4065 MINT_IN_BREAK;
4066 MINT_IN_CASE(MINT_BEQ_I4)
4067 BRELOP(i, ==)
4068 MINT_IN_BREAK;
4069 MINT_IN_CASE(MINT_BEQ_I8)
4070 BRELOP(l, ==)
4071 MINT_IN_BREAK;
4072 MINT_IN_CASE(MINT_BEQ_R4)
4073 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
4074 MINT_IN_BREAK;
4075 MINT_IN_CASE(MINT_BEQ_R8)
4076 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
4077 MINT_IN_BREAK;
4078 MINT_IN_CASE(MINT_BGE_I4_S)
4079 BRELOP_S(i, >=)
4080 MINT_IN_BREAK;
4081 MINT_IN_CASE(MINT_BGE_I8_S)
4082 BRELOP_S(l, >=)
4083 MINT_IN_BREAK;
4084 MINT_IN_CASE(MINT_BGE_R4_S)
4085 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
4086 MINT_IN_BREAK;
4087 MINT_IN_CASE(MINT_BGE_R8_S)
4088 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
4089 MINT_IN_BREAK;
4090 MINT_IN_CASE(MINT_BGE_I4)
4091 BRELOP(i, >=)
4092 MINT_IN_BREAK;
4093 MINT_IN_CASE(MINT_BGE_I8)
4094 BRELOP(l, >=)
4095 MINT_IN_BREAK;
4096 MINT_IN_CASE(MINT_BGE_R4)
4097 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
4098 MINT_IN_BREAK;
4099 MINT_IN_CASE(MINT_BGE_R8)
4100 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
4101 MINT_IN_BREAK;
4102 MINT_IN_CASE(MINT_BGT_I4_S)
4103 BRELOP_S(i, >)
4104 MINT_IN_BREAK;
4105 MINT_IN_CASE(MINT_BGT_I8_S)
4106 BRELOP_S(l, >)
4107 MINT_IN_BREAK;
4108 MINT_IN_CASE(MINT_BGT_R4_S)
4109 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
4110 MINT_IN_BREAK;
4111 MINT_IN_CASE(MINT_BGT_R8_S)
4112 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
4113 MINT_IN_BREAK;
4114 MINT_IN_CASE(MINT_BGT_I4)
4115 BRELOP(i, >)
4116 MINT_IN_BREAK;
4117 MINT_IN_CASE(MINT_BGT_I8)
4118 BRELOP(l, >)
4119 MINT_IN_BREAK;
4120 MINT_IN_CASE(MINT_BGT_R4)
4121 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
4122 MINT_IN_BREAK;
4123 MINT_IN_CASE(MINT_BGT_R8)
4124 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
4125 MINT_IN_BREAK;
4126 MINT_IN_CASE(MINT_BLT_I4_S)
4127 BRELOP_S(i, <)
4128 MINT_IN_BREAK;
4129 MINT_IN_CASE(MINT_BLT_I8_S)
4130 BRELOP_S(l, <)
4131 MINT_IN_BREAK;
4132 MINT_IN_CASE(MINT_BLT_R4_S)
4133 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
4134 MINT_IN_BREAK;
4135 MINT_IN_CASE(MINT_BLT_R8_S)
4136 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
4137 MINT_IN_BREAK;
4138 MINT_IN_CASE(MINT_BLT_I4)
4139 BRELOP(i, <)
4140 MINT_IN_BREAK;
4141 MINT_IN_CASE(MINT_BLT_I8)
4142 BRELOP(l, <)
4143 MINT_IN_BREAK;
4144 MINT_IN_CASE(MINT_BLT_R4)
4145 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
4146 MINT_IN_BREAK;
4147 MINT_IN_CASE(MINT_BLT_R8)
4148 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
4149 MINT_IN_BREAK;
4150 MINT_IN_CASE(MINT_BLE_I4_S)
4151 BRELOP_S(i, <=)
4152 MINT_IN_BREAK;
4153 MINT_IN_CASE(MINT_BLE_I8_S)
4154 BRELOP_S(l, <=)
4155 MINT_IN_BREAK;
4156 MINT_IN_CASE(MINT_BLE_R4_S)
4157 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
4158 MINT_IN_BREAK;
4159 MINT_IN_CASE(MINT_BLE_R8_S)
4160 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
4161 MINT_IN_BREAK;
4162 MINT_IN_CASE(MINT_BLE_I4)
4163 BRELOP(i, <=)
4164 MINT_IN_BREAK;
4165 MINT_IN_CASE(MINT_BLE_I8)
4166 BRELOP(l, <=)
4167 MINT_IN_BREAK;
4168 MINT_IN_CASE(MINT_BLE_R4)
4169 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
4170 MINT_IN_BREAK;
4171 MINT_IN_CASE(MINT_BLE_R8)
4172 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
4173 MINT_IN_BREAK;
4174 MINT_IN_CASE(MINT_BNE_UN_I4_S)
4175 BRELOP_S(i, !=)
4176 MINT_IN_BREAK;
4177 MINT_IN_CASE(MINT_BNE_UN_I8_S)
4178 BRELOP_S(l, !=)
4179 MINT_IN_BREAK;
4180 MINT_IN_CASE(MINT_BNE_UN_R4_S)
4181 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
4182 MINT_IN_BREAK;
4183 MINT_IN_CASE(MINT_BNE_UN_R8_S)
4184 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
4185 MINT_IN_BREAK;
4186 MINT_IN_CASE(MINT_BNE_UN_I4)
4187 BRELOP(i, !=)
4188 MINT_IN_BREAK;
4189 MINT_IN_CASE(MINT_BNE_UN_I8)
4190 BRELOP(l, !=)
4191 MINT_IN_BREAK;
4192 MINT_IN_CASE(MINT_BNE_UN_R4)
4193 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
4194 MINT_IN_BREAK;
4195 MINT_IN_CASE(MINT_BNE_UN_R8)
4196 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
4197 MINT_IN_BREAK;
4199 #define BRELOP_S_CAST(datamem, op, type) \
4200 sp -= 2; \
4201 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4202 gint16 br_offset = (gint16) ip [1]; \
4203 BACK_BRANCH_PROFILE (br_offset); \
4204 ip += br_offset; \
4205 } else \
4206 ip += 2;
4208 #define BRELOP_CAST(datamem, op, type) \
4209 sp -= 2; \
4210 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4211 gint32 br_offset = (gint32) ip [1]; \
4212 BACK_BRANCH_PROFILE (br_offset); \
4213 ip += br_offset; \
4214 } else \
4215 ip += 3;
4217 MINT_IN_CASE(MINT_BGE_UN_I4_S)
4218 BRELOP_S_CAST(i, >=, guint32);
4219 MINT_IN_BREAK;
4220 MINT_IN_CASE(MINT_BGE_UN_I8_S)
4221 BRELOP_S_CAST(l, >=, guint64);
4222 MINT_IN_BREAK;
4223 MINT_IN_CASE(MINT_BGE_UN_R4_S)
4224 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4225 MINT_IN_BREAK;
4226 MINT_IN_CASE(MINT_BGE_UN_R8_S)
4227 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4228 MINT_IN_BREAK;
4229 MINT_IN_CASE(MINT_BGE_UN_I4)
4230 BRELOP_CAST(i, >=, guint32);
4231 MINT_IN_BREAK;
4232 MINT_IN_CASE(MINT_BGE_UN_I8)
4233 BRELOP_CAST(l, >=, guint64);
4234 MINT_IN_BREAK;
4235 MINT_IN_CASE(MINT_BGE_UN_R4)
4236 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4237 MINT_IN_BREAK;
4238 MINT_IN_CASE(MINT_BGE_UN_R8)
4239 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4240 MINT_IN_BREAK;
4241 MINT_IN_CASE(MINT_BGT_UN_I4_S)
4242 BRELOP_S_CAST(i, >, guint32);
4243 MINT_IN_BREAK;
4244 MINT_IN_CASE(MINT_BGT_UN_I8_S)
4245 BRELOP_S_CAST(l, >, guint64);
4246 MINT_IN_BREAK;
4247 MINT_IN_CASE(MINT_BGT_UN_R4_S)
4248 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4249 MINT_IN_BREAK;
4250 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4251 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4252 MINT_IN_BREAK;
4253 MINT_IN_CASE(MINT_BGT_UN_I4)
4254 BRELOP_CAST(i, >, guint32);
4255 MINT_IN_BREAK;
4256 MINT_IN_CASE(MINT_BGT_UN_I8)
4257 BRELOP_CAST(l, >, guint64);
4258 MINT_IN_BREAK;
4259 MINT_IN_CASE(MINT_BGT_UN_R4)
4260 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4261 MINT_IN_BREAK;
4262 MINT_IN_CASE(MINT_BGT_UN_R8)
4263 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4264 MINT_IN_BREAK;
4265 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4266 BRELOP_S_CAST(i, <=, guint32);
4267 MINT_IN_BREAK;
4268 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4269 BRELOP_S_CAST(l, <=, guint64);
4270 MINT_IN_BREAK;
4271 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4272 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4273 MINT_IN_BREAK;
4274 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4275 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4276 MINT_IN_BREAK;
4277 MINT_IN_CASE(MINT_BLE_UN_I4)
4278 BRELOP_CAST(i, <=, guint32);
4279 MINT_IN_BREAK;
4280 MINT_IN_CASE(MINT_BLE_UN_I8)
4281 BRELOP_CAST(l, <=, guint64);
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_BLE_UN_R4)
4284 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_BLE_UN_R8)
4287 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4288 MINT_IN_BREAK;
4289 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4290 BRELOP_S_CAST(i, <, guint32);
4291 MINT_IN_BREAK;
4292 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4293 BRELOP_S_CAST(l, <, guint64);
4294 MINT_IN_BREAK;
4295 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4296 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4297 MINT_IN_BREAK;
4298 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4299 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4300 MINT_IN_BREAK;
4301 MINT_IN_CASE(MINT_BLT_UN_I4)
4302 BRELOP_CAST(i, <, guint32);
4303 MINT_IN_BREAK;
4304 MINT_IN_CASE(MINT_BLT_UN_I8)
4305 BRELOP_CAST(l, <, guint64);
4306 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_BLT_UN_R4)
4308 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4309 MINT_IN_BREAK;
4310 MINT_IN_CASE(MINT_BLT_UN_R8)
4311 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4312 MINT_IN_BREAK;
4313 MINT_IN_CASE(MINT_SWITCH) {
4314 guint32 n;
4315 const unsigned short *st;
4316 ++ip;
4317 n = READ32 (ip);
4318 ip += 2;
4319 st = ip + 2 * n;
4320 --sp;
4321 if ((guint32)sp->data.i < n) {
4322 gint offset;
4323 ip += 2 * (guint32)sp->data.i;
4324 offset = READ32 (ip);
4325 ip = ip + offset;
4326 } else {
4327 ip = st;
4329 MINT_IN_BREAK;
4331 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4332 NULL_CHECK (sp [-1].data.p);
4333 ++ip;
4334 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4335 MINT_IN_BREAK;
4336 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4337 NULL_CHECK (sp [-1].data.p);
4338 ++ip;
4339 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4340 MINT_IN_BREAK;
4341 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4342 NULL_CHECK (sp [-1].data.p);
4343 ++ip;
4344 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4345 MINT_IN_BREAK;
4346 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4347 NULL_CHECK (sp [-1].data.p);
4348 ++ip;
4349 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4350 MINT_IN_BREAK;
4351 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4352 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4353 NULL_CHECK (sp [-1].data.p);
4354 ++ip;
4355 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4356 MINT_IN_BREAK;
4357 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4358 NULL_CHECK (sp [-1].data.p);
4359 ++ip;
4360 #ifdef NO_UNALIGNED_ACCESS
4361 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4362 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4363 else
4364 #endif
4365 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4366 MINT_IN_BREAK;
4367 MINT_IN_CASE(MINT_LDIND_I) {
4368 guint16 offset = ip [1];
4369 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4370 ip += 2;
4371 MINT_IN_BREAK;
4373 MINT_IN_CASE(MINT_LDIND_I8) {
4374 guint16 offset = ip [1];
4375 #ifdef NO_UNALIGNED_ACCESS
4376 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4377 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4378 else
4379 #endif
4380 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4381 ip += 2;
4382 MINT_IN_BREAK;
4384 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4385 NULL_CHECK (sp [-1].data.p);
4386 ++ip;
4387 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4388 MINT_IN_BREAK;
4389 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4390 NULL_CHECK (sp [-1].data.p);
4391 ++ip;
4392 #ifdef NO_UNALIGNED_ACCESS
4393 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4394 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4395 else
4396 #endif
4397 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4398 MINT_IN_BREAK;
4399 MINT_IN_CASE(MINT_LDIND_REF)
4400 ++ip;
4401 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4402 MINT_IN_BREAK;
4403 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4404 NULL_CHECK (sp [-1].data.p);
4405 ++ip;
4406 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4407 MINT_IN_BREAK;
4409 MINT_IN_CASE(MINT_STIND_REF)
4410 ++ip;
4411 sp -= 2;
4412 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4413 MINT_IN_BREAK;
4414 MINT_IN_CASE(MINT_STIND_I1)
4415 ++ip;
4416 sp -= 2;
4417 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4418 MINT_IN_BREAK;
4419 MINT_IN_CASE(MINT_STIND_I2)
4420 ++ip;
4421 sp -= 2;
4422 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4423 MINT_IN_BREAK;
4424 MINT_IN_CASE(MINT_STIND_I4)
4425 ++ip;
4426 sp -= 2;
4427 * (gint32 *) sp->data.p = sp[1].data.i;
4428 MINT_IN_BREAK;
4429 MINT_IN_CASE(MINT_STIND_I)
4430 ++ip;
4431 sp -= 2;
4432 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4433 MINT_IN_BREAK;
4434 MINT_IN_CASE(MINT_STIND_I8)
4435 ++ip;
4436 sp -= 2;
4437 #ifdef NO_UNALIGNED_ACCESS
4438 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4439 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4440 else
4441 #endif
4442 * (gint64 *) sp->data.p = sp[1].data.l;
4443 MINT_IN_BREAK;
4444 MINT_IN_CASE(MINT_STIND_R4)
4445 ++ip;
4446 sp -= 2;
4447 * (float *) sp->data.p = sp[1].data.f_r4;
4448 MINT_IN_BREAK;
4449 MINT_IN_CASE(MINT_STIND_R8)
4450 ++ip;
4451 sp -= 2;
4452 #ifdef NO_UNALIGNED_ACCESS
4453 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4454 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4455 else
4456 #endif
4457 * (double *) sp->data.p = sp[1].data.f;
4458 MINT_IN_BREAK;
4459 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4460 ++ip;
4461 sp -= 2;
4462 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4463 MINT_IN_BREAK;
4464 #define BINOP(datamem, op) \
4465 --sp; \
4466 sp [-1].data.datamem op ## = sp [0].data.datamem; \
4467 ++ip;
4468 MINT_IN_CASE(MINT_ADD_I4)
4469 BINOP(i, +);
4470 MINT_IN_BREAK;
4471 MINT_IN_CASE(MINT_ADD_I8)
4472 BINOP(l, +);
4473 MINT_IN_BREAK;
4474 MINT_IN_CASE(MINT_ADD_R4)
4475 BINOP(f_r4, +);
4476 MINT_IN_BREAK;
4477 MINT_IN_CASE(MINT_ADD_R8)
4478 BINOP(f, +);
4479 MINT_IN_BREAK;
4480 MINT_IN_CASE(MINT_ADD1_I4)
4481 ++sp [-1].data.i;
4482 ++ip;
4483 MINT_IN_BREAK;
4484 MINT_IN_CASE(MINT_ADD1_I8)
4485 ++sp [-1].data.l;
4486 ++ip;
4487 MINT_IN_BREAK;
4488 MINT_IN_CASE(MINT_LOCADD1_I4)
4489 *(gint32*)(locals + ip [1]) += 1;
4490 ip += 2;
4491 MINT_IN_BREAK;
4492 MINT_IN_CASE(MINT_LOCADD1_I8)
4493 *(gint64*)(locals + ip [1]) += 1;
4494 ip += 2;
4495 MINT_IN_BREAK;
4496 MINT_IN_CASE(MINT_SUB_I4)
4497 BINOP(i, -);
4498 MINT_IN_BREAK;
4499 MINT_IN_CASE(MINT_SUB_I8)
4500 BINOP(l, -);
4501 MINT_IN_BREAK;
4502 MINT_IN_CASE(MINT_SUB_R4)
4503 BINOP(f_r4, -);
4504 MINT_IN_BREAK;
4505 MINT_IN_CASE(MINT_SUB_R8)
4506 BINOP(f, -);
4507 MINT_IN_BREAK;
4508 MINT_IN_CASE(MINT_SUB1_I4)
4509 --sp [-1].data.i;
4510 ++ip;
4511 MINT_IN_BREAK;
4512 MINT_IN_CASE(MINT_SUB1_I8)
4513 --sp [-1].data.l;
4514 ++ip;
4515 MINT_IN_BREAK;
4516 MINT_IN_CASE(MINT_LOCSUB1_I4)
4517 *(gint32*)(locals + ip [1]) -= 1;
4518 ip += 2;
4519 MINT_IN_BREAK;
4520 MINT_IN_CASE(MINT_LOCSUB1_I8)
4521 *(gint64*)(locals + ip [1]) -= 1;
4522 MINT_IN_BREAK;
4523 MINT_IN_CASE(MINT_MUL_I4)
4524 BINOP(i, *);
4525 MINT_IN_BREAK;
4526 MINT_IN_CASE(MINT_MUL_I8)
4527 BINOP(l, *);
4528 MINT_IN_BREAK;
4529 MINT_IN_CASE(MINT_MUL_R4)
4530 BINOP(f_r4, *);
4531 MINT_IN_BREAK;
4532 MINT_IN_CASE(MINT_MUL_R8)
4533 BINOP(f, *);
4534 MINT_IN_BREAK;
4535 MINT_IN_CASE(MINT_DIV_I4)
4536 if (sp [-1].data.i == 0)
4537 goto div_zero_label;
4538 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4539 goto overflow_label;
4540 BINOP(i, /);
4541 MINT_IN_BREAK;
4542 MINT_IN_CASE(MINT_DIV_I8)
4543 if (sp [-1].data.l == 0)
4544 goto div_zero_label;
4545 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4546 goto overflow_label;
4547 BINOP(l, /);
4548 MINT_IN_BREAK;
4549 MINT_IN_CASE(MINT_DIV_R4)
4550 BINOP(f_r4, /);
4551 MINT_IN_BREAK;
4552 MINT_IN_CASE(MINT_DIV_R8)
4553 BINOP(f, /);
4554 MINT_IN_BREAK;
4556 #define BINOP_CAST(datamem, op, type) \
4557 --sp; \
4558 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4559 ++ip;
4560 MINT_IN_CASE(MINT_DIV_UN_I4)
4561 if (sp [-1].data.i == 0)
4562 goto div_zero_label;
4563 BINOP_CAST(i, /, guint32);
4564 MINT_IN_BREAK;
4565 MINT_IN_CASE(MINT_DIV_UN_I8)
4566 if (sp [-1].data.l == 0)
4567 goto div_zero_label;
4568 BINOP_CAST(l, /, guint64);
4569 MINT_IN_BREAK;
4570 MINT_IN_CASE(MINT_REM_I4)
4571 if (sp [-1].data.i == 0)
4572 goto div_zero_label;
4573 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4574 goto overflow_label;
4575 BINOP(i, %);
4576 MINT_IN_BREAK;
4577 MINT_IN_CASE(MINT_REM_I8)
4578 if (sp [-1].data.l == 0)
4579 goto div_zero_label;
4580 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4581 goto overflow_label;
4582 BINOP(l, %);
4583 MINT_IN_BREAK;
4584 MINT_IN_CASE(MINT_REM_R4)
4585 /* FIXME: what do we actually do here? */
4586 --sp;
4587 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4588 ++ip;
4589 MINT_IN_BREAK;
4590 MINT_IN_CASE(MINT_REM_R8)
4591 /* FIXME: what do we actually do here? */
4592 --sp;
4593 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4594 ++ip;
4595 MINT_IN_BREAK;
4596 MINT_IN_CASE(MINT_REM_UN_I4)
4597 if (sp [-1].data.i == 0)
4598 goto div_zero_label;
4599 BINOP_CAST(i, %, guint32);
4600 MINT_IN_BREAK;
4601 MINT_IN_CASE(MINT_REM_UN_I8)
4602 if (sp [-1].data.l == 0)
4603 goto div_zero_label;
4604 BINOP_CAST(l, %, guint64);
4605 MINT_IN_BREAK;
4606 MINT_IN_CASE(MINT_AND_I4)
4607 BINOP(i, &);
4608 MINT_IN_BREAK;
4609 MINT_IN_CASE(MINT_AND_I8)
4610 BINOP(l, &);
4611 MINT_IN_BREAK;
4612 MINT_IN_CASE(MINT_OR_I4)
4613 BINOP(i, |);
4614 MINT_IN_BREAK;
4615 MINT_IN_CASE(MINT_OR_I8)
4616 BINOP(l, |);
4617 MINT_IN_BREAK;
4618 MINT_IN_CASE(MINT_XOR_I4)
4619 BINOP(i, ^);
4620 MINT_IN_BREAK;
4621 MINT_IN_CASE(MINT_XOR_I8)
4622 BINOP(l, ^);
4623 MINT_IN_BREAK;
4625 #define SHIFTOP(datamem, op) \
4626 --sp; \
4627 sp [-1].data.datamem op ## = sp [0].data.i; \
4628 ++ip;
4630 MINT_IN_CASE(MINT_SHL_I4)
4631 SHIFTOP(i, <<);
4632 MINT_IN_BREAK;
4633 MINT_IN_CASE(MINT_SHL_I8)
4634 SHIFTOP(l, <<);
4635 MINT_IN_BREAK;
4636 MINT_IN_CASE(MINT_SHR_I4)
4637 SHIFTOP(i, >>);
4638 MINT_IN_BREAK;
4639 MINT_IN_CASE(MINT_SHR_I8)
4640 SHIFTOP(l, >>);
4641 MINT_IN_BREAK;
4642 MINT_IN_CASE(MINT_SHR_UN_I4)
4643 --sp;
4644 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4645 ++ip;
4646 MINT_IN_BREAK;
4647 MINT_IN_CASE(MINT_SHR_UN_I8)
4648 --sp;
4649 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4650 ++ip;
4651 MINT_IN_BREAK;
4652 MINT_IN_CASE(MINT_NEG_I4)
4653 sp [-1].data.i = - sp [-1].data.i;
4654 ++ip;
4655 MINT_IN_BREAK;
4656 MINT_IN_CASE(MINT_NEG_I8)
4657 sp [-1].data.l = - sp [-1].data.l;
4658 ++ip;
4659 MINT_IN_BREAK;
4660 MINT_IN_CASE(MINT_NEG_R4)
4661 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4662 ++ip;
4663 MINT_IN_BREAK;
4664 MINT_IN_CASE(MINT_NEG_R8)
4665 sp [-1].data.f = - sp [-1].data.f;
4666 ++ip;
4667 MINT_IN_BREAK;
4668 MINT_IN_CASE(MINT_NOT_I4)
4669 sp [-1].data.i = ~ sp [-1].data.i;
4670 ++ip;
4671 MINT_IN_BREAK;
4672 MINT_IN_CASE(MINT_NOT_I8)
4673 sp [-1].data.l = ~ sp [-1].data.l;
4674 ++ip;
4675 MINT_IN_BREAK;
4676 MINT_IN_CASE(MINT_CONV_I1_I4)
4677 sp [-1].data.i = (gint8)sp [-1].data.i;
4678 ++ip;
4679 MINT_IN_BREAK;
4680 MINT_IN_CASE(MINT_CONV_I1_I8)
4681 sp [-1].data.i = (gint8)sp [-1].data.l;
4682 ++ip;
4683 MINT_IN_BREAK;
4684 MINT_IN_CASE(MINT_CONV_I1_R4)
4685 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4686 ++ip;
4687 MINT_IN_BREAK;
4688 MINT_IN_CASE(MINT_CONV_I1_R8)
4689 /* without gint32 cast, C compiler is allowed to use undefined
4690 * behaviour if data.f is bigger than >255. See conv.fpint section
4691 * in C standard:
4692 * > The conversion truncates; that is, the fractional part
4693 * > is discarded. The behavior is undefined if the truncated
4694 * > value cannot be represented in the destination type.
4695 * */
4696 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4697 ++ip;
4698 MINT_IN_BREAK;
4699 MINT_IN_CASE(MINT_CONV_U1_I4)
4700 sp [-1].data.i = (guint8)sp [-1].data.i;
4701 ++ip;
4702 MINT_IN_BREAK;
4703 MINT_IN_CASE(MINT_CONV_U1_I8)
4704 sp [-1].data.i = (guint8)sp [-1].data.l;
4705 ++ip;
4706 MINT_IN_BREAK;
4707 MINT_IN_CASE(MINT_CONV_U1_R4)
4708 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4709 ++ip;
4710 MINT_IN_BREAK;
4711 MINT_IN_CASE(MINT_CONV_U1_R8)
4712 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4713 ++ip;
4714 MINT_IN_BREAK;
4715 MINT_IN_CASE(MINT_CONV_I2_I4)
4716 sp [-1].data.i = (gint16)sp [-1].data.i;
4717 ++ip;
4718 MINT_IN_BREAK;
4719 MINT_IN_CASE(MINT_CONV_I2_I8)
4720 sp [-1].data.i = (gint16)sp [-1].data.l;
4721 ++ip;
4722 MINT_IN_BREAK;
4723 MINT_IN_CASE(MINT_CONV_I2_R4)
4724 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4725 ++ip;
4726 MINT_IN_BREAK;
4727 MINT_IN_CASE(MINT_CONV_I2_R8)
4728 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4729 ++ip;
4730 MINT_IN_BREAK;
4731 MINT_IN_CASE(MINT_CONV_U2_I4)
4732 sp [-1].data.i = (guint16)sp [-1].data.i;
4733 ++ip;
4734 MINT_IN_BREAK;
4735 MINT_IN_CASE(MINT_CONV_U2_I8)
4736 sp [-1].data.i = (guint16)sp [-1].data.l;
4737 ++ip;
4738 MINT_IN_BREAK;
4739 MINT_IN_CASE(MINT_CONV_U2_R4)
4740 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4741 ++ip;
4742 MINT_IN_BREAK;
4743 MINT_IN_CASE(MINT_CONV_U2_R8)
4744 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4745 ++ip;
4746 MINT_IN_BREAK;
4747 MINT_IN_CASE(MINT_CONV_I4_R4)
4748 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4749 ++ip;
4750 MINT_IN_BREAK;
4751 MINT_IN_CASE(MINT_CONV_I4_R8)
4752 sp [-1].data.i = (gint32)sp [-1].data.f;
4753 ++ip;
4754 MINT_IN_BREAK;
4755 MINT_IN_CASE(MINT_CONV_U4_I8)
4756 MINT_IN_CASE(MINT_CONV_I4_I8)
4757 sp [-1].data.i = (gint32)sp [-1].data.l;
4758 ++ip;
4759 MINT_IN_BREAK;
4760 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4761 sp [-2].data.i = (gint32)sp [-2].data.l;
4762 ++ip;
4763 MINT_IN_BREAK;
4764 MINT_IN_CASE(MINT_CONV_U4_R4)
4765 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4766 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4767 #else
4768 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4769 #endif
4770 ++ip;
4771 MINT_IN_BREAK;
4772 MINT_IN_CASE(MINT_CONV_U4_R8)
4773 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4774 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4775 #else
4776 sp [-1].data.i = (guint32) sp [-1].data.f;
4777 #endif
4778 ++ip;
4779 MINT_IN_BREAK;
4780 MINT_IN_CASE(MINT_CONV_I8_I4)
4781 sp [-1].data.l = sp [-1].data.i;
4782 ++ip;
4783 MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4785 sp [-2].data.l = sp [-2].data.i;
4786 ++ip;
4787 MINT_IN_BREAK;
4788 MINT_IN_CASE(MINT_CONV_I8_U4)
4789 sp [-1].data.l = (guint32)sp [-1].data.i;
4790 ++ip;
4791 MINT_IN_BREAK;
4792 MINT_IN_CASE(MINT_CONV_I8_R4)
4793 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4794 ++ip;
4795 MINT_IN_BREAK;
4796 MINT_IN_CASE(MINT_CONV_I8_R8)
4797 sp [-1].data.l = (gint64)sp [-1].data.f;
4798 ++ip;
4799 MINT_IN_BREAK;
4800 MINT_IN_CASE(MINT_CONV_R4_I4)
4801 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4802 ++ip;
4803 MINT_IN_BREAK;
4804 MINT_IN_CASE(MINT_CONV_R4_I8)
4805 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4806 ++ip;
4807 MINT_IN_BREAK;
4808 MINT_IN_CASE(MINT_CONV_R4_R8)
4809 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4810 ++ip;
4811 MINT_IN_BREAK;
4812 MINT_IN_CASE(MINT_CONV_R8_I4)
4813 sp [-1].data.f = (double)sp [-1].data.i;
4814 ++ip;
4815 MINT_IN_BREAK;
4816 MINT_IN_CASE(MINT_CONV_R8_I8)
4817 sp [-1].data.f = (double)sp [-1].data.l;
4818 ++ip;
4819 MINT_IN_BREAK;
4820 MINT_IN_CASE(MINT_CONV_R8_R4)
4821 sp [-1].data.f = (double) sp [-1].data.f_r4;
4822 ++ip;
4823 MINT_IN_BREAK;
4824 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4825 sp [-2].data.f = (double) sp [-2].data.f_r4;
4826 ++ip;
4827 MINT_IN_BREAK;
4828 MINT_IN_CASE(MINT_CONV_U8_R4)
4829 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4830 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4831 #else
4832 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4833 #endif
4834 ++ip;
4835 MINT_IN_BREAK;
4836 MINT_IN_CASE(MINT_CONV_U8_R8)
4837 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4838 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4839 #else
4840 sp [-1].data.l = (guint64)sp [-1].data.f;
4841 #endif
4842 ++ip;
4843 MINT_IN_BREAK;
4844 MINT_IN_CASE(MINT_CPOBJ) {
4845 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4846 g_assert (m_class_is_valuetype (c));
4847 /* if this assertion fails, we need to add a write barrier */
4848 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4849 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4850 ip += 2;
4851 sp -= 2;
4852 MINT_IN_BREAK;
4854 MINT_IN_CASE(MINT_CPOBJ_VT) {
4855 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4856 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4857 ip += 2;
4858 sp -= 2;
4859 MINT_IN_BREAK;
4861 MINT_IN_CASE(MINT_LDOBJ_VT) {
4862 int size = READ32(ip + 1);
4863 ip += 3;
4864 memcpy (vt_sp, sp [-1].data.p, size);
4865 sp [-1].data.p = vt_sp;
4866 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4867 MINT_IN_BREAK;
4869 MINT_IN_CASE(MINT_LDSTR)
4870 sp->data.p = frame->imethod->data_items [ip [1]];
4871 ++sp;
4872 ip += 2;
4873 MINT_IN_BREAK;
4874 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4875 MonoString *s = NULL;
4876 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [1]];
4878 MonoMethod *method = frame->imethod->method;
4879 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4880 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4881 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4882 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4883 } else {
4884 g_assert_not_reached ();
4886 sp->data.p = s;
4887 ++sp;
4888 ip += 2;
4889 MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4892 MonoClass *newobj_class;
4893 guint32 token = ip [1];
4894 guint16 param_count = ip [2];
4896 newobj_class = (MonoClass*) frame->imethod->data_items [token];
4898 sp -= param_count;
4899 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
4900 if (!is_ok (error))
4901 goto throw_error_label;
4903 ++sp;
4904 ip += 3;
4905 MINT_IN_BREAK;
4907 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4908 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]];
4909 INIT_VTABLE (vtable);
4910 MonoObject *o; // See the comment about GC safety.
4911 guint16 param_count;
4912 guint16 imethod_index = ip [1];
4914 const gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG;
4916 param_count = ip [2];
4918 // Make room for two copies of o -- this parameter and return value.
4919 if (param_count || !is_inlined) {
4920 sp -= param_count;
4921 memmove (sp + 2, sp, param_count * sizeof (stackval));
4924 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4925 if (G_UNLIKELY (!o)) {
4926 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4927 goto throw_error_label;
4930 // Store o next to and before the parameters on the stack so GC will see it,
4931 // and where it is needed when the call returns.
4932 sp [0].data.o = o;
4933 sp [1].data.o = o;
4934 ip += 4;
4935 if (is_inlined) {
4936 sp += param_count + 2;
4937 } else {
4938 cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index];
4939 frame->ip = ip - 4;
4940 goto call_newobj;
4943 MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4947 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4949 frame->ip = ip;
4950 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
4951 guint16 const param_count = ip [2];
4953 // Make room for extra parameter and result.
4954 if (param_count) {
4955 sp -= param_count;
4956 memmove (sp + 2, sp, param_count * sizeof (stackval));
4959 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4960 if (vtst) {
4961 memset (vt_sp, 0, ip [3]);
4962 ip += 4;
4963 // Put extra parameter and result on stack, before other parameters,
4964 // and point stack to extra parameter, after result.
4965 // This pattern occurs for newobj_vt_fast and newobj_fast.
4966 sp [1].data.p = vt_sp;
4967 sp [0].data.p = vt_sp;
4968 } else {
4969 ip += 3;
4970 // Like newobj_fast, add valuetype_this parameter
4971 // and result and point stack to this after result.
4972 memset (sp, 0, sizeof (*sp));
4973 sp [1].data.p = &sp [0].data; // valuetype_this == result
4976 // call_newobj captures the pattern where the return value is placed
4977 // on the stack before the call, instead of the call forming it.
4978 call_newobj:
4979 ++sp; // Point sp at added extra param, after return value.
4980 is_void = TRUE;
4981 retval = NULL;
4982 goto call;
4984 MINT_IN_CASE(MINT_NEWOBJ) {
4986 frame->ip = ip;
4988 guint32 const token = ip [1];
4989 ip += 2; // FIXME: Do this after throw?
4991 cmethod = (InterpMethod*)frame->imethod->data_items [token];
4993 MonoMethodSignature* const csig = mono_method_signature_internal (cmethod->method);
4995 g_assert (csig->hasthis);
4997 // Make room for first parameter and return value.
4998 const int param_count = csig->param_count;
4999 if (param_count) {
5000 sp -= param_count;
5001 memmove (sp + 2, sp, param_count * sizeof (stackval));
5004 InterpMethod* const imethod = frame->imethod;
5006 MonoClass * const newobj_class = cmethod->method->klass;
5008 /*if (profiling_classes) {
5009 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
5010 count++;
5011 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
5015 * First arg is the object.
5016 * a constructor returns void, but we need to return the object we created
5018 if (m_class_is_valuetype (newobj_class)) {
5019 MonoType *t = m_class_get_byval_arg (newobj_class);
5020 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
5021 sp [0].data.p = vt_sp; // return value
5022 sp [1].data.p = vt_sp; // first parameter
5023 } else {
5024 memset (sp, 0, sizeof (*sp));
5025 sp [1].data.p = &sp [0].data; // first parameter is return value
5027 } else {
5028 if (newobj_class != mono_defaults.string_class) {
5029 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
5030 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
5031 MonoException *exc = mono_error_convert_to_exception (error);
5032 g_assert (exc);
5033 THROW_EX (exc, ip);
5035 error_init_reuse (error);
5036 MonoObject* o = NULL; // See the comment about GC safety.
5037 OBJREF (o) = mono_object_new_checked (imethod->domain, newobj_class, error);
5038 mono_error_cleanup (error); // FIXME: do not swallow the error
5039 error_init_reuse (error);
5040 EXCEPTION_CHECKPOINT;
5041 sp [0].data.o = o; // return value
5042 sp [1].data.o = o; // first parameter
5043 #ifndef DISABLE_REMOTING
5044 if (mono_object_is_transparent_proxy (o)) {
5045 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (cmethod->method, error);
5046 mono_error_assert_ok (error);
5047 cmethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
5048 mono_error_assert_ok (error);
5050 #endif
5051 } else {
5052 retval = sp;
5053 ++sp;
5054 sp->data.p = NULL; // first parameter
5055 is_void = TRUE;
5056 goto call;
5059 goto call_newobj;
5061 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
5062 frame->ip = ip;
5063 ip += 2;
5065 MINT_IN_BREAK;
5067 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
5068 MonoMethodSignature *csig;
5069 guint32 token;
5071 frame->ip = ip;
5072 token = ip [1];
5073 ip += 2;
5075 InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token];
5076 csig = mono_method_signature_internal (cmethod->method);
5078 g_assert (csig->hasthis);
5079 sp -= csig->param_count;
5081 gpointer arg0 = sp [0].data.p;
5083 gpointer *byreference_this = (gpointer*)vt_sp;
5084 *byreference_this = arg0;
5086 /* Followed by a VTRESULT opcode which will push the result on the stack */
5087 ++sp;
5088 MINT_IN_BREAK;
5090 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
5091 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
5092 sp [-1].data.p = *byreference_this;
5093 ++ip;
5094 MINT_IN_BREAK;
5096 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
5097 sp -= 2;
5098 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
5099 sp ++;
5100 ++ip;
5101 MINT_IN_BREAK;
5103 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
5104 sp -= 2;
5105 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
5106 sp ++;
5107 ++ip;
5108 MINT_IN_BREAK;
5110 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
5111 MonoObject *obj = sp [-1].data.o;
5112 sp [-1].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
5113 ++ip;
5114 MINT_IN_BREAK;
5116 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
5117 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
5118 MonoObject* const o = sp [-1].data.o;
5119 if (o) {
5120 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5121 gboolean isinst;
5122 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
5123 isinst = TRUE;
5124 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
5125 /* slow path */
5126 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
5127 } else {
5128 isinst = FALSE;
5131 if (!isinst) {
5132 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
5133 if (isinst_instr)
5134 sp [-1].data.p = NULL;
5135 else
5136 goto invalid_cast_label;
5139 ip += 2;
5140 MINT_IN_BREAK;
5142 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
5143 MINT_IN_CASE(MINT_ISINST_COMMON) {
5144 MonoObject* const o = sp [-1].data.o;
5145 if (o) {
5146 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5147 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
5149 if (!isinst) {
5150 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
5151 if (isinst_instr)
5152 sp [-1].data.p = NULL;
5153 else
5154 goto invalid_cast_label;
5157 ip += 2;
5158 MINT_IN_BREAK;
5160 MINT_IN_CASE(MINT_CASTCLASS)
5161 MINT_IN_CASE(MINT_ISINST) {
5162 MonoObject* const o = sp [-1].data.o;
5163 if (o) {
5164 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5165 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
5166 gboolean const isinst_instr = *ip == MINT_ISINST;
5167 if (isinst_instr)
5168 sp [-1].data.p = NULL;
5169 else
5170 goto invalid_cast_label;
5173 ip += 2;
5174 MINT_IN_BREAK;
5176 MINT_IN_CASE(MINT_CONV_R_UN_I4)
5177 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
5178 ++ip;
5179 MINT_IN_BREAK;
5180 MINT_IN_CASE(MINT_CONV_R_UN_I8)
5181 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
5182 ++ip;
5183 MINT_IN_BREAK;
5184 MINT_IN_CASE(MINT_UNBOX) {
5185 MonoObject* const o = sp [-1].data.o;
5186 NULL_CHECK (o);
5187 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5189 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
5190 goto invalid_cast_label;
5192 sp [-1].data.p = mono_object_unbox_internal (o);
5193 ip += 2;
5194 MINT_IN_BREAK;
5196 MINT_IN_CASE(MINT_THROW)
5197 --sp;
5198 if (!sp->data.p)
5199 sp->data.p = mono_get_exception_null_reference ();
5201 THROW_EX ((MonoException *)sp->data.p, ip);
5202 MINT_IN_BREAK;
5203 MINT_IN_CASE(MINT_CHECKPOINT)
5204 /* Do synchronous checking of abort requests */
5205 EXCEPTION_CHECKPOINT;
5206 ++ip;
5207 MINT_IN_BREAK;
5208 MINT_IN_CASE(MINT_SAFEPOINT)
5209 /* Do synchronous checking of abort requests */
5210 EXCEPTION_CHECKPOINT;
5211 /* Poll safepoint */
5212 mono_threads_safepoint ();
5213 ++ip;
5214 MINT_IN_BREAK;
5215 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
5216 sp[-1].data.p = (char*)sp [-1].data.o + ip [1];
5217 ip += 2;
5218 MINT_IN_BREAK;
5220 MINT_IN_CASE(MINT_LDFLDA) {
5221 MonoObject* const o = sp [-1].data.o;
5222 NULL_CHECK (o);
5223 sp[-1].data.p = (char *)o + ip [1];
5224 ip += 2;
5225 MINT_IN_BREAK;
5227 MINT_IN_CASE(MINT_CKNULL_N) {
5228 /* Same as CKNULL, but further down the stack */
5229 int const n = ip [1];
5230 MonoObject* const o = sp [-n].data.o;
5231 NULL_CHECK (o);
5232 ip += 2;
5233 MINT_IN_BREAK;
5236 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5237 MonoObject* const o = sp [-1].data.o; \
5238 NULL_CHECK (o); \
5239 if (unaligned) \
5240 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
5241 else \
5242 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
5243 ip += 2; \
5244 } while (0)
5246 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
5248 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
5249 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
5250 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
5251 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
5252 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
5253 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
5254 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
5255 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
5256 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
5257 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
5258 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5259 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5261 MINT_IN_CASE(MINT_LDFLD_VT) {
5262 MonoObject* const o = sp [-1].data.o;
5263 NULL_CHECK (o);
5265 int size = READ32(ip + 2);
5266 sp [-1].data.p = vt_sp;
5267 memcpy (sp [-1].data.p, (char *)o + ip [1], size);
5268 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5269 ip += 4;
5270 MINT_IN_BREAK;
5273 MINT_IN_CASE(MINT_LDRMFLD) {
5274 MonoObject* const o = sp [-1].data.o;
5275 NULL_CHECK (o);
5276 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
5277 ip += 2;
5278 MINT_IN_BREAK;
5280 MINT_IN_CASE(MINT_LDRMFLD_VT) {
5281 MonoObject* const o = sp [-1].data.o;
5282 NULL_CHECK (o);
5283 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
5284 ip += 2;
5285 MINT_IN_BREAK;
5289 #define LDARGFLD(datamem, fieldtype) do { \
5290 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5291 NULL_CHECK (o); \
5292 sp [0].data.datamem = *(fieldtype *)((char *)o + ip [2]) ; \
5293 sp++; \
5294 ip += 3; \
5295 } while (0)
5296 MINT_IN_CASE(MINT_LDARGFLD_I1) LDARGFLD(i, gint8); MINT_IN_BREAK;
5297 MINT_IN_CASE(MINT_LDARGFLD_U1) LDARGFLD(i, guint8); MINT_IN_BREAK;
5298 MINT_IN_CASE(MINT_LDARGFLD_I2) LDARGFLD(i, gint16); MINT_IN_BREAK;
5299 MINT_IN_CASE(MINT_LDARGFLD_U2) LDARGFLD(i, guint16); MINT_IN_BREAK;
5300 MINT_IN_CASE(MINT_LDARGFLD_I4) LDARGFLD(i, gint32); MINT_IN_BREAK;
5301 MINT_IN_CASE(MINT_LDARGFLD_I8) LDARGFLD(l, gint64); MINT_IN_BREAK;
5302 MINT_IN_CASE(MINT_LDARGFLD_R4) LDARGFLD(f_r4, float); MINT_IN_BREAK;
5303 MINT_IN_CASE(MINT_LDARGFLD_R8) LDARGFLD(f, double); MINT_IN_BREAK;
5304 MINT_IN_CASE(MINT_LDARGFLD_O) LDARGFLD(p, gpointer); MINT_IN_BREAK;
5305 MINT_IN_CASE(MINT_LDARGFLD_P) LDARGFLD(p, gpointer); MINT_IN_BREAK;
5307 #define LDLOCFLD(datamem, fieldtype) do { \
5308 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5309 NULL_CHECK (o); \
5310 sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \
5311 sp++; \
5312 ip += 3; \
5313 } while (0)
5314 MINT_IN_CASE(MINT_LDLOCFLD_I1) LDLOCFLD(i, gint8); MINT_IN_BREAK;
5315 MINT_IN_CASE(MINT_LDLOCFLD_U1) LDLOCFLD(i, guint8); MINT_IN_BREAK;
5316 MINT_IN_CASE(MINT_LDLOCFLD_I2) LDLOCFLD(i, gint16); MINT_IN_BREAK;
5317 MINT_IN_CASE(MINT_LDLOCFLD_U2) LDLOCFLD(i, guint16); MINT_IN_BREAK;
5318 MINT_IN_CASE(MINT_LDLOCFLD_I4) LDLOCFLD(i, gint32); MINT_IN_BREAK;
5319 MINT_IN_CASE(MINT_LDLOCFLD_I8) LDLOCFLD(l, gint64); MINT_IN_BREAK;
5320 MINT_IN_CASE(MINT_LDLOCFLD_R4) LDLOCFLD(f_r4, float); MINT_IN_BREAK;
5321 MINT_IN_CASE(MINT_LDLOCFLD_R8) LDLOCFLD(f, double); MINT_IN_BREAK;
5322 MINT_IN_CASE(MINT_LDLOCFLD_O) LDLOCFLD(p, gpointer); MINT_IN_BREAK;
5323 MINT_IN_CASE(MINT_LDLOCFLD_P) LDLOCFLD(p, gpointer); MINT_IN_BREAK;
5325 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5326 MonoObject* const o = sp [-2].data.o; \
5327 NULL_CHECK (o); \
5328 sp -= 2; \
5329 if (unaligned) \
5330 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
5331 else \
5332 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
5333 ip += 2; \
5334 } while (0)
5336 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5338 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
5339 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
5340 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
5341 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
5342 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5343 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5344 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5345 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5346 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
5347 MINT_IN_CASE(MINT_STFLD_O) {
5348 MonoObject* const o = sp [-2].data.o;
5349 NULL_CHECK (o);
5350 sp -= 2;
5351 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [1], sp [1].data.o);
5352 ip += 2;
5353 MINT_IN_BREAK;
5355 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5356 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5358 MINT_IN_CASE(MINT_STFLD_VT) {
5359 MonoObject* const o = sp [-2].data.o;
5360 NULL_CHECK (o);
5361 sp -= 2;
5363 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [2]];
5364 int const i32 = mono_class_value_size (klass, NULL);
5366 guint16 offset = ip [1];
5367 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5369 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5370 ip += 3;
5371 MINT_IN_BREAK;
5373 MINT_IN_CASE(MINT_STRMFLD) {
5374 MonoClassField *field;
5376 MonoObject* const o = sp [-2].data.o;
5377 NULL_CHECK (o);
5379 field = (MonoClassField*)frame->imethod->data_items[ip [1]];
5380 ip += 2;
5382 #ifndef DISABLE_REMOTING
5383 if (mono_object_is_transparent_proxy (o)) {
5384 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5385 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5386 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5387 } else
5388 #endif
5389 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5391 sp -= 2;
5392 MINT_IN_BREAK;
5394 MINT_IN_CASE(MINT_STRMFLD_VT)
5396 NULL_CHECK (sp [-2].data.o);
5397 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5398 ip += 2;
5399 sp -= 2;
5400 MINT_IN_BREAK;
5402 #define STARGFLD(datamem, fieldtype) do { \
5403 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5404 NULL_CHECK (o); \
5405 sp--; \
5406 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5407 ip += 3; \
5408 } while (0)
5409 MINT_IN_CASE(MINT_STARGFLD_I1) STARGFLD(i, gint8); MINT_IN_BREAK;
5410 MINT_IN_CASE(MINT_STARGFLD_U1) STARGFLD(i, guint8); MINT_IN_BREAK;
5411 MINT_IN_CASE(MINT_STARGFLD_I2) STARGFLD(i, gint16); MINT_IN_BREAK;
5412 MINT_IN_CASE(MINT_STARGFLD_U2) STARGFLD(i, guint16); MINT_IN_BREAK;
5413 MINT_IN_CASE(MINT_STARGFLD_I4) STARGFLD(i, gint32); MINT_IN_BREAK;
5414 MINT_IN_CASE(MINT_STARGFLD_I8) STARGFLD(l, gint64); MINT_IN_BREAK;
5415 MINT_IN_CASE(MINT_STARGFLD_R4) STARGFLD(f_r4, float); MINT_IN_BREAK;
5416 MINT_IN_CASE(MINT_STARGFLD_R8) STARGFLD(f, double); MINT_IN_BREAK;
5417 MINT_IN_CASE(MINT_STARGFLD_P) STARGFLD(p, gpointer); MINT_IN_BREAK;
5418 MINT_IN_CASE(MINT_STARGFLD_O) {
5419 MonoObject *o = frame->stack_args [ip [1]].data.o;
5420 NULL_CHECK (o);
5421 sp--;
5422 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o);
5423 ip += 3;
5424 MINT_IN_BREAK;
5427 #define STLOCFLD(datamem, fieldtype) do { \
5428 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5429 NULL_CHECK (o); \
5430 sp--; \
5431 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5432 ip += 3; \
5433 } while (0)
5434 MINT_IN_CASE(MINT_STLOCFLD_I1) STLOCFLD(i, gint8); MINT_IN_BREAK;
5435 MINT_IN_CASE(MINT_STLOCFLD_U1) STLOCFLD(i, guint8); MINT_IN_BREAK;
5436 MINT_IN_CASE(MINT_STLOCFLD_I2) STLOCFLD(i, gint16); MINT_IN_BREAK;
5437 MINT_IN_CASE(MINT_STLOCFLD_U2) STLOCFLD(i, guint16); MINT_IN_BREAK;
5438 MINT_IN_CASE(MINT_STLOCFLD_I4) STLOCFLD(i, gint32); MINT_IN_BREAK;
5439 MINT_IN_CASE(MINT_STLOCFLD_I8) STLOCFLD(l, gint64); MINT_IN_BREAK;
5440 MINT_IN_CASE(MINT_STLOCFLD_R4) STLOCFLD(f_r4, float); MINT_IN_BREAK;
5441 MINT_IN_CASE(MINT_STLOCFLD_R8) STLOCFLD(f, double); MINT_IN_BREAK;
5442 MINT_IN_CASE(MINT_STLOCFLD_P) STLOCFLD(p, gpointer); MINT_IN_BREAK;
5443 MINT_IN_CASE(MINT_STLOCFLD_O) {
5444 MonoObject *o = *(MonoObject**)(locals + ip [1]);
5445 NULL_CHECK (o);
5446 sp--;
5447 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o);
5448 ip += 3;
5449 MINT_IN_BREAK;
5452 MINT_IN_CASE(MINT_LDSFLDA) {
5453 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5454 INIT_VTABLE (vtable);
5455 sp->data.p = frame->imethod->data_items [ip [2]];
5456 ip += 3;
5457 ++sp;
5458 MINT_IN_BREAK;
5461 MINT_IN_CASE(MINT_LDSSFLDA) {
5462 guint32 offset = READ32(ip + 1);
5463 sp->data.p = mono_get_special_static_data (offset);
5464 ip += 3;
5465 ++sp;
5466 MINT_IN_BREAK;
5469 /* We init class here to preserve cctor order */
5470 #define LDSFLD(datamem, fieldtype) { \
5471 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5472 INIT_VTABLE (vtable); \
5473 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5474 ip += 3; \
5475 sp++; \
5478 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5479 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5480 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5481 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5482 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5483 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5484 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5485 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5486 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5487 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5489 MINT_IN_CASE(MINT_LDSFLD_VT) {
5490 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5491 INIT_VTABLE (vtable);
5492 sp->data.p = vt_sp;
5494 gpointer addr = frame->imethod->data_items [ip [2]];
5495 int const i32 = READ32 (ip + 3);
5496 memcpy (vt_sp, addr, i32);
5497 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5498 ip += 5;
5499 ++sp;
5500 MINT_IN_BREAK;
5503 #define LDTSFLD(datamem, fieldtype) { \
5504 MonoInternalThread *thread = mono_thread_internal_current (); \
5505 guint32 offset = READ32 (ip + 1); \
5506 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5507 sp[0].data.datamem = *(fieldtype*)addr; \
5508 ip += 3; \
5509 ++sp; \
5511 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5512 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5513 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5514 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5515 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5516 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5517 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5518 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5519 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5520 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5522 MINT_IN_CASE(MINT_LDSSFLD) {
5523 guint32 offset = READ32(ip + 2);
5524 gpointer addr = mono_get_special_static_data (offset);
5525 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5526 stackval_from_data (field->type, sp, addr, FALSE);
5527 ip += 4;
5528 ++sp;
5529 MINT_IN_BREAK;
5531 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5532 guint32 offset = READ32(ip + 1);
5533 gpointer addr = mono_get_special_static_data (offset);
5535 int size = READ32 (ip + 3);
5536 memcpy (vt_sp, addr, size);
5537 sp->data.p = vt_sp;
5538 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5539 ip += 5;
5540 ++sp;
5541 MINT_IN_BREAK;
5543 #define STSFLD(datamem, fieldtype) { \
5544 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5545 INIT_VTABLE (vtable); \
5546 sp --; \
5547 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5548 ip += 3; \
5551 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5552 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5553 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5554 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5555 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5556 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5557 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5558 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5559 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5560 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5562 MINT_IN_CASE(MINT_STSFLD_VT) {
5563 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5564 INIT_VTABLE (vtable);
5565 int const i32 = READ32 (ip + 3);
5566 gpointer addr = frame->imethod->data_items [ip [2]];
5568 memcpy (addr, sp [-1].data.vt, i32);
5569 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5570 ip += 5;
5571 --sp;
5572 MINT_IN_BREAK;
5575 #define STTSFLD(datamem, fieldtype) { \
5576 MonoInternalThread *thread = mono_thread_internal_current (); \
5577 guint32 offset = READ32 (ip + 1); \
5578 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5579 sp--; \
5580 *(fieldtype*)addr = sp[0].data.datamem; \
5581 ip += 3; \
5584 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5585 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5586 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5587 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5588 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5589 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5590 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5591 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5592 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5593 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5595 MINT_IN_CASE(MINT_STSSFLD) {
5596 guint32 offset = READ32(ip + 2);
5597 gpointer addr = mono_get_special_static_data (offset);
5598 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5599 --sp;
5600 stackval_to_data (field->type, sp, addr, FALSE);
5601 ip += 4;
5602 MINT_IN_BREAK;
5604 MINT_IN_CASE(MINT_STSSFLD_VT) {
5605 guint32 offset = READ32(ip + 1);
5606 gpointer addr = mono_get_special_static_data (offset);
5607 --sp;
5608 int size = READ32 (ip + 3);
5609 memcpy (addr, sp->data.vt, size);
5610 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5611 ip += 5;
5612 MINT_IN_BREAK;
5615 MINT_IN_CASE(MINT_STOBJ_VT) {
5616 int size;
5617 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5618 ip += 2;
5619 size = mono_class_value_size (c, NULL);
5620 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5621 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5622 sp -= 2;
5623 MINT_IN_BREAK;
5625 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5626 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5627 goto overflow_label;
5628 sp [-1].data.i = (gint32)sp [-1].data.f;
5629 ++ip;
5630 MINT_IN_BREAK;
5631 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5632 if (sp [-1].data.i < 0)
5633 goto overflow_label;
5634 sp [-1].data.l = sp [-1].data.i;
5635 ++ip;
5636 MINT_IN_BREAK;
5637 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5638 if (sp [-1].data.l < 0)
5639 goto overflow_label;
5640 ++ip;
5641 MINT_IN_BREAK;
5642 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5643 if ((guint64) sp [-1].data.l > G_MAXINT64)
5644 goto overflow_label;
5645 ++ip;
5646 MINT_IN_BREAK;
5647 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5648 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5649 goto overflow_label;
5650 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5651 ++ip;
5652 MINT_IN_BREAK;
5653 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5654 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5655 goto overflow_label;
5656 sp [-1].data.l = (guint64)sp [-1].data.f;
5657 ++ip;
5658 MINT_IN_BREAK;
5659 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5660 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5661 goto overflow_label;
5662 sp [-1].data.l = (gint64)sp [-1].data.f;
5663 ++ip;
5664 MINT_IN_BREAK;
5665 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5666 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5667 goto overflow_label;
5668 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5669 ++ip;
5670 MINT_IN_BREAK;
5671 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5672 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5673 goto overflow_label;
5674 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5675 ++ip;
5676 MINT_IN_BREAK;
5677 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5678 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5679 goto overflow_label;
5680 sp [-1].data.l = (gint64)sp [-1].data.f;
5681 ++ip;
5682 MINT_IN_BREAK;
5683 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5684 if ((guint64)sp [-1].data.l > G_MAXINT32)
5685 goto overflow_label;
5686 sp [-1].data.i = (gint32)sp [-1].data.l;
5687 ++ip;
5688 MINT_IN_BREAK;
5689 MINT_IN_CASE(MINT_BOX) {
5690 mono_interp_box (frame, ip, sp);
5691 ip += 3;
5692 MINT_IN_BREAK;
5694 MINT_IN_CASE(MINT_BOX_VT) {
5695 vt_sp -= mono_interp_box_vt (frame, ip, sp);
5696 ip += 4;
5697 MINT_IN_BREAK;
5699 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5700 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5701 ip += 4;
5702 MINT_IN_BREAK;
5704 MINT_IN_CASE(MINT_NEWARR) {
5705 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]];
5706 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5707 if (!is_ok (error)) {
5708 goto throw_error_label;
5710 ip += 2;
5711 /*if (profiling_classes) {
5712 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5713 count++;
5714 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5717 MINT_IN_BREAK;
5719 MINT_IN_CASE(MINT_LDLEN) {
5720 MonoObject* const o = sp [-1].data.o;
5721 NULL_CHECK (o);
5722 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5723 ++ip;
5724 MINT_IN_BREAK;
5726 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5727 MonoObject* const o = sp [-1].data.o;
5728 NULL_CHECK (o);
5729 gsize offset_length = (gsize)(gint16)ip [1];
5730 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5731 ip += 2;
5732 MINT_IN_BREAK;
5734 MINT_IN_CASE(MINT_GETCHR) {
5735 MonoString *s;
5736 s = (MonoString*)sp [-2].data.p;
5737 NULL_CHECK (s);
5738 int const i32 = sp [-1].data.i;
5739 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5740 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5741 --sp;
5742 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5743 ++ip;
5744 MINT_IN_BREAK;
5746 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5747 guint8 * const span = (guint8 *) sp [-2].data.p;
5748 const int index = sp [-1].data.i;
5749 sp--;
5751 NULL_CHECK (span);
5753 const gsize offset_length = (gsize)(gint16)ip [2];
5755 const gint32 length = *(gint32 *) (span + offset_length);
5756 if (index < 0 || index >= length)
5757 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5759 const gsize element_size = (gsize)(gint16)ip [1];
5760 const gsize offset_pointer = (gsize)(gint16)ip [3];
5762 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5763 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5765 ip += 4;
5766 MINT_IN_BREAK;
5768 MINT_IN_CASE(MINT_STRLEN) {
5769 ++ip;
5770 MonoObject* const o = sp [-1].data.o;
5771 NULL_CHECK (o);
5772 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5773 MINT_IN_BREAK;
5775 MINT_IN_CASE(MINT_ARRAY_RANK) {
5776 MonoObject* const o = sp [-1].data.o;
5777 NULL_CHECK (o);
5778 sp [-1].data.i = m_class_get_rank (mono_object_class (o));
5779 ip++;
5780 MINT_IN_BREAK;
5782 MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE) {
5783 MonoObject* const o = sp [-1].data.o;
5784 NULL_CHECK (o);
5785 sp [-1].data.i = mono_array_element_size (mono_object_class (o));
5786 ip++;
5787 MINT_IN_BREAK;
5789 MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE) {
5790 MonoObject* const o = sp [-1].data.o;
5791 NULL_CHECK (o);
5792 sp [-1].data.i = m_class_is_primitive (m_class_get_element_class (mono_object_class (o)));
5793 ip++;
5794 MINT_IN_BREAK;
5796 MINT_IN_CASE(MINT_LDELEMA1) {
5797 /* No bounds, one direction */
5798 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5799 NULL_CHECK (ao);
5800 gint32 const index = sp [-1].data.i;
5801 if (index >= ao->max_length)
5802 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5803 gint32 const size = READ32 (ip + 1);
5804 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5805 ip += 3;
5806 sp --;
5808 MINT_IN_BREAK;
5810 MINT_IN_CASE(MINT_LDELEMA) {
5811 guint16 rank = ip [1];
5812 gint32 const esize = READ32 (ip + 2);
5813 ip += 4;
5814 sp -= rank;
5816 MonoArray* const ao = (MonoArray*) sp [-1].data.o;
5817 NULL_CHECK (ao);
5819 g_assert (ao->bounds);
5820 guint32 pos = 0;
5821 for (int i = 0; i < rank; i++) {
5822 guint32 idx = sp [i].data.i;
5823 guint32 lower = ao->bounds [i].lower_bound;
5824 guint32 len = ao->bounds [i].length;
5825 if (idx < lower || (idx - lower) >= len)
5826 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5827 pos = (pos * len) + idx - lower;
5830 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
5831 MINT_IN_BREAK;
5833 MINT_IN_CASE(MINT_LDELEMA_TC) {
5834 guint16 rank = ip [1];
5835 ip += 3;
5836 sp -= rank;
5838 MonoObject* const o = sp [-1].data.o;
5839 NULL_CHECK (o);
5841 MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [-3 + 2]];
5842 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5843 MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, sp, needs_typecheck);
5844 if (ex)
5845 THROW_EX (ex, ip);
5846 MINT_IN_BREAK;
5849 #define LDELEM(datamem,elemtype) do { \
5850 sp--; \
5851 MonoArray *o = (MonoArray*)sp [-1].data.p; \
5852 NULL_CHECK (o); \
5853 gint32 aindex = sp [0].data.i; \
5854 if (aindex >= mono_array_length_internal (o)) \
5855 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5856 sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \
5857 ip++; \
5858 } while (0)
5859 MINT_IN_CASE(MINT_LDELEM_I1) LDELEM(i, gint8); MINT_IN_BREAK;
5860 MINT_IN_CASE(MINT_LDELEM_U1) LDELEM(i, guint8); MINT_IN_BREAK;
5861 MINT_IN_CASE(MINT_LDELEM_I2) LDELEM(i, gint16); MINT_IN_BREAK;
5862 MINT_IN_CASE(MINT_LDELEM_U2) LDELEM(i, guint16); MINT_IN_BREAK;
5863 MINT_IN_CASE(MINT_LDELEM_I4) LDELEM(i, gint32); MINT_IN_BREAK;
5864 MINT_IN_CASE(MINT_LDELEM_U4) LDELEM(i, guint32); MINT_IN_BREAK;
5865 MINT_IN_CASE(MINT_LDELEM_I8) LDELEM(l, guint64); MINT_IN_BREAK;
5866 MINT_IN_CASE(MINT_LDELEM_I) LDELEM(nati, mono_i); MINT_IN_BREAK;
5867 MINT_IN_CASE(MINT_LDELEM_R4) LDELEM(f_r4, float); MINT_IN_BREAK;
5868 MINT_IN_CASE(MINT_LDELEM_R8) LDELEM(f, double); MINT_IN_BREAK;
5869 MINT_IN_CASE(MINT_LDELEM_REF) LDELEM(p, gpointer); MINT_IN_BREAK;
5870 MINT_IN_CASE(MINT_LDELEM_VT) {
5871 sp--;
5872 MonoArray *o = (MonoArray*)sp [-1].data.p;
5873 NULL_CHECK (o);
5874 mono_u aindex = sp [0].data.i;
5875 if (aindex >= mono_array_length_internal (o))
5876 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5878 int i32 = READ32 (ip + 1);
5879 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5880 sp [-1].data.vt = vt_sp;
5881 // Copying to vtstack. No wbarrier needed
5882 memcpy (sp [-1].data.vt, src_addr, i32);
5883 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5885 ip += 3;
5886 MINT_IN_BREAK;
5888 #define STELEM_PROLOG(o, aindex) do { \
5889 sp -= 3; \
5890 o = (MonoArray*)sp [0].data.p; \
5891 NULL_CHECK (o); \
5892 aindex = sp [1].data.i; \
5893 if (aindex >= mono_array_length_internal (o)) \
5894 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5895 } while (0)
5897 #define STELEM(datamem,elemtype) do { \
5898 MonoArray *o; \
5899 gint32 aindex; \
5900 STELEM_PROLOG(o, aindex); \
5901 mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \
5902 ip++; \
5903 } while (0)
5904 MINT_IN_CASE(MINT_STELEM_I1) STELEM(i, gint8); MINT_IN_BREAK;
5905 MINT_IN_CASE(MINT_STELEM_U1) STELEM(i, guint8); MINT_IN_BREAK;
5906 MINT_IN_CASE(MINT_STELEM_I2) STELEM(i, gint16); MINT_IN_BREAK;
5907 MINT_IN_CASE(MINT_STELEM_U2) STELEM(i, guint16); MINT_IN_BREAK;
5908 MINT_IN_CASE(MINT_STELEM_I4) STELEM(i, gint32); MINT_IN_BREAK;
5909 MINT_IN_CASE(MINT_STELEM_I8) STELEM(l, gint64); MINT_IN_BREAK;
5910 MINT_IN_CASE(MINT_STELEM_I) STELEM(nati, mono_i); MINT_IN_BREAK;
5911 MINT_IN_CASE(MINT_STELEM_R4) STELEM(f_r4, float); MINT_IN_BREAK;
5912 MINT_IN_CASE(MINT_STELEM_R8) STELEM(f, double); MINT_IN_BREAK;
5913 MINT_IN_CASE(MINT_STELEM_REF) {
5914 MonoArray *o;
5915 gint32 aindex;
5916 STELEM_PROLOG(o, aindex);
5918 if (sp [2].data.o) {
5919 gboolean isinst = mono_interp_isinst (sp [2].data.o, m_class_get_element_class (mono_object_class (o)));
5920 if (!isinst)
5921 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5923 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5924 ip++;
5925 MINT_IN_BREAK;
5928 MINT_IN_CASE(MINT_STELEM_VT) {
5929 MonoArray *o;
5930 gint32 aindex;
5931 STELEM_PROLOG(o, aindex);
5933 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [1]];
5934 int const i32 = READ32 (ip + 2);
5935 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5937 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5938 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5939 ip += 4;
5940 MINT_IN_BREAK;
5942 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5943 if (sp [-1].data.i < 0)
5944 goto overflow_label;
5945 ++ip;
5946 MINT_IN_BREAK;
5947 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5948 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5949 goto overflow_label;
5950 sp [-1].data.i = (gint32) sp [-1].data.l;
5951 ++ip;
5952 MINT_IN_BREAK;
5953 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5954 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5955 goto overflow_label;
5956 sp [-1].data.i = (gint32) sp [-1].data.l;
5957 ++ip;
5958 MINT_IN_BREAK;
5959 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5960 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32 || isnan (sp [-1].data.f_r4))
5961 goto overflow_label;
5962 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5963 ++ip;
5964 MINT_IN_BREAK;
5965 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5966 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32 || isnan (sp [-1].data.f))
5967 goto overflow_label;
5968 sp [-1].data.i = (gint32) sp [-1].data.f;
5969 ++ip;
5970 MINT_IN_BREAK;
5971 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5972 if (sp [-1].data.i < 0)
5973 goto overflow_label;
5974 ++ip;
5975 MINT_IN_BREAK;
5976 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5977 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5978 goto overflow_label;
5979 sp [-1].data.i = (guint32) sp [-1].data.l;
5980 ++ip;
5981 MINT_IN_BREAK;
5982 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5983 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32 || isnan (sp [-1].data.f_r4))
5984 goto overflow_label;
5985 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5986 ++ip;
5987 MINT_IN_BREAK;
5988 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5989 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32 || isnan (sp [-1].data.f))
5990 goto overflow_label;
5991 sp [-1].data.i = (guint32) sp [-1].data.f;
5992 ++ip;
5993 MINT_IN_BREAK;
5994 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5995 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5996 goto overflow_label;
5997 ++ip;
5998 MINT_IN_BREAK;
5999 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
6000 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
6001 goto overflow_label;
6002 ++ip;
6003 MINT_IN_BREAK;
6004 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
6005 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
6006 goto overflow_label;
6007 sp [-1].data.i = (gint16) sp [-1].data.l;
6008 ++ip;
6009 MINT_IN_BREAK;
6010 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
6011 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
6012 goto overflow_label;
6013 sp [-1].data.i = (gint16) sp [-1].data.l;
6014 ++ip;
6015 MINT_IN_BREAK;
6016 MINT_IN_CASE(MINT_CONV_OVF_I2_R4)
6017 if (sp [-1].data.f_r4 < G_MININT16 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4))
6018 goto overflow_label;
6019 sp [-1].data.i = (gint16) sp [-1].data.f_r4;
6020 ++ip;
6021 MINT_IN_BREAK;
6022 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
6023 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f))
6024 goto overflow_label;
6025 sp [-1].data.i = (gint16) sp [-1].data.f;
6026 ++ip;
6027 MINT_IN_BREAK;
6028 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4)
6029 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4))
6030 goto overflow_label;
6031 sp [-1].data.i = (gint16) sp [-1].data.f_r4;
6032 ++ip;
6033 MINT_IN_BREAK;
6034 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
6035 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f))
6036 goto overflow_label;
6037 sp [-1].data.i = (gint16) sp [-1].data.f;
6038 ++ip;
6039 MINT_IN_BREAK;
6040 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
6041 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
6042 goto overflow_label;
6043 ++ip;
6044 MINT_IN_BREAK;
6045 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
6046 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
6047 goto overflow_label;
6048 sp [-1].data.i = (guint16) sp [-1].data.l;
6049 ++ip;
6050 MINT_IN_BREAK;
6051 MINT_IN_CASE(MINT_CONV_OVF_U2_R4)
6052 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT16 || isnan (sp [-1].data.f_r4))
6053 goto overflow_label;
6054 sp [-1].data.i = (guint16) sp [-1].data.f_r4;
6055 ++ip;
6056 MINT_IN_BREAK;
6057 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
6058 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16 || isnan (sp [-1].data.f))
6059 goto overflow_label;
6060 sp [-1].data.i = (guint16) sp [-1].data.f;
6061 ++ip;
6062 MINT_IN_BREAK;
6063 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
6064 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
6065 goto overflow_label;
6066 ++ip;
6067 MINT_IN_BREAK;
6068 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
6069 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
6070 goto overflow_label;
6071 ++ip;
6072 MINT_IN_BREAK;
6073 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
6074 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
6075 goto overflow_label;
6076 sp [-1].data.i = (gint8) sp [-1].data.l;
6077 ++ip;
6078 MINT_IN_BREAK;
6079 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
6080 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
6081 goto overflow_label;
6082 sp [-1].data.i = (gint8) sp [-1].data.l;
6083 ++ip;
6084 MINT_IN_BREAK;
6085 MINT_IN_CASE(MINT_CONV_OVF_I1_R4)
6086 if (sp [-1].data.f_r4 < G_MININT8 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4))
6087 goto overflow_label;
6088 sp [-1].data.i = (gint8) sp [-1].data.f_r4;
6089 ++ip;
6090 MINT_IN_BREAK;
6091 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
6092 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f))
6093 goto overflow_label;
6094 sp [-1].data.i = (gint8) sp [-1].data.f;
6095 ++ip;
6096 MINT_IN_BREAK;
6097 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4)
6098 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4))
6099 goto overflow_label;
6100 sp [-1].data.i = (gint8) sp [-1].data.f_r4;
6101 ++ip;
6102 MINT_IN_BREAK;
6103 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
6104 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f))
6105 goto overflow_label;
6106 sp [-1].data.i = (gint8) sp [-1].data.f;
6107 ++ip;
6108 MINT_IN_BREAK;
6109 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
6110 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
6111 goto overflow_label;
6112 ++ip;
6113 MINT_IN_BREAK;
6114 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
6115 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
6116 goto overflow_label;
6117 sp [-1].data.i = (guint8) sp [-1].data.l;
6118 ++ip;
6119 MINT_IN_BREAK;
6120 MINT_IN_CASE(MINT_CONV_OVF_U1_R4)
6121 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT8 || isnan (sp [-1].data.f_r4))
6122 goto overflow_label;
6123 sp [-1].data.i = (guint8) sp [-1].data.f_r4;
6124 ++ip;
6125 MINT_IN_BREAK;
6126 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
6127 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8 || isnan (sp [-1].data.f))
6128 goto overflow_label;
6129 sp [-1].data.i = (guint8) sp [-1].data.f;
6130 ++ip;
6131 MINT_IN_BREAK;
6132 MINT_IN_CASE(MINT_CKFINITE)
6133 if (!mono_isfinite (sp [-1].data.f))
6134 THROW_EX (mono_get_exception_arithmetic (), ip);
6135 ++ip;
6136 MINT_IN_BREAK;
6137 MINT_IN_CASE(MINT_MKREFANY) {
6138 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
6140 /* The value address is on the stack */
6141 gpointer addr = sp [-1].data.p;
6142 /* Push the typedref value on the stack */
6143 sp [-1].data.p = vt_sp;
6144 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6146 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6147 tref->klass = c;
6148 tref->type = m_class_get_byval_arg (c);
6149 tref->value = addr;
6151 ip += 2;
6152 MINT_IN_BREAK;
6154 MINT_IN_CASE(MINT_REFANYTYPE) {
6155 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6156 MonoType *type = tref->type;
6158 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6159 sp [-1].data.p = vt_sp;
6160 vt_sp += 8;
6161 *(gpointer*)sp [-1].data.p = type;
6162 ip ++;
6163 MINT_IN_BREAK;
6165 MINT_IN_CASE(MINT_REFANYVAL) {
6166 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6167 gpointer addr = tref->value;
6169 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
6170 if (c != tref->klass)
6171 goto invalid_cast_label;
6173 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6175 sp [-1].data.p = addr;
6176 ip += 2;
6177 MINT_IN_BREAK;
6179 MINT_IN_CASE(MINT_LDTOKEN)
6180 sp->data.p = vt_sp;
6181 vt_sp += 8;
6182 * (gpointer *)sp->data.p = frame->imethod->data_items[ip [1]];
6183 ip += 2;
6184 ++sp;
6185 MINT_IN_BREAK;
6186 MINT_IN_CASE(MINT_ADD_OVF_I4)
6187 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6188 goto overflow_label;
6189 BINOP(i, +);
6190 MINT_IN_BREAK;
6191 MINT_IN_CASE(MINT_ADD_OVF_I8)
6192 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6193 goto overflow_label;
6194 BINOP(l, +);
6195 MINT_IN_BREAK;
6196 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
6197 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6198 goto overflow_label;
6199 BINOP_CAST(i, +, guint32);
6200 MINT_IN_BREAK;
6201 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
6202 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6203 goto overflow_label;
6204 BINOP_CAST(l, +, guint64);
6205 MINT_IN_BREAK;
6206 MINT_IN_CASE(MINT_MUL_OVF_I4)
6207 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6208 goto overflow_label;
6209 BINOP(i, *);
6210 MINT_IN_BREAK;
6211 MINT_IN_CASE(MINT_MUL_OVF_I8)
6212 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6213 goto overflow_label;
6214 BINOP(l, *);
6215 MINT_IN_BREAK;
6216 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
6217 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6218 goto overflow_label;
6219 BINOP_CAST(i, *, guint32);
6220 MINT_IN_BREAK;
6221 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
6222 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6223 goto overflow_label;
6224 BINOP_CAST(l, *, guint64);
6225 MINT_IN_BREAK;
6226 MINT_IN_CASE(MINT_SUB_OVF_I4)
6227 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6228 goto overflow_label;
6229 BINOP(i, -);
6230 MINT_IN_BREAK;
6231 MINT_IN_CASE(MINT_SUB_OVF_I8)
6232 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6233 goto overflow_label;
6234 BINOP(l, -);
6235 MINT_IN_BREAK;
6236 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
6237 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6238 goto overflow_label;
6239 BINOP_CAST(i, -, guint32);
6240 MINT_IN_BREAK;
6241 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
6242 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6243 goto overflow_label;
6244 BINOP_CAST(l, -, guint64);
6245 MINT_IN_BREAK;
6246 MINT_IN_CASE(MINT_START_ABORT_PROT)
6247 mono_threads_begin_abort_protected_block ();
6248 ip ++;
6249 MINT_IN_BREAK;
6250 MINT_IN_CASE(MINT_ENDFINALLY) {
6251 gboolean pending_abort = mono_threads_end_abort_protected_block ();
6252 ip ++;
6254 // After mono_threads_end_abort_protected_block to conserve stack.
6255 const int clause_index = *ip;
6257 if (clause_args && clause_index == clause_args->exit_clause)
6258 goto exit_frame;
6260 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
6261 g_assert (sp >= frame->stack);
6262 #endif
6263 sp = frame->stack;
6265 if (finally_ips) {
6266 ip = (const guint16*)finally_ips->data;
6267 finally_ips = g_slist_remove (finally_ips, ip);
6268 /* Throw abort after the last finally block to avoid confusing EH */
6269 if (pending_abort && !finally_ips)
6270 EXCEPTION_CHECKPOINT;
6271 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6272 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6273 goto main_loop;
6275 ves_abort();
6276 MINT_IN_BREAK;
6279 MINT_IN_CASE(MINT_LEAVE)
6280 MINT_IN_CASE(MINT_LEAVE_S)
6281 MINT_IN_CASE(MINT_LEAVE_CHECK)
6282 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
6283 int dummy;
6284 // Leave is split into pieces in order to consume less stack,
6285 // but not have to change how exception handling macros access labels and locals.
6287 g_assert (sp >= frame->stack);
6288 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
6290 frame->ip = ip;
6292 int opcode = *ip;
6293 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
6295 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
6296 // FIXME Free this frame earlier?
6297 InterpFrame* const child_frame = alloc_frame (context, &dummy, frame, NULL, NULL, NULL);
6298 MonoException *abort_exc = mono_interp_leave (child_frame);
6299 if (abort_exc)
6300 THROW_EX (abort_exc, frame->ip);
6303 opcode = *ip; // Refetch to avoid register/stack pressure.
6304 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
6305 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
6306 const guint16 *endfinally_ip = ip;
6307 GSList *old_list = finally_ips;
6308 MonoMethod *method = frame->imethod->method;
6309 #if DEBUG_INTERP
6310 if (tracing)
6311 g_print ("* Handle finally IL_%04x\n", endfinally_ip - frame->imethod->code);
6312 #endif
6313 // FIXME Null check for frame->imethod follows deref.
6314 if (frame->imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6315 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
6316 goto exit_frame;
6317 guint32 const ip_offset = frame->ip - frame->imethod->code;
6319 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
6321 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
6322 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
6323 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code))) {
6324 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6325 ip = frame->imethod->code + clause->handler_offset;
6326 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6327 #if DEBUG_INTERP
6328 if (tracing)
6329 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, context->has_resume_state ? "yes": "no");
6330 #endif
6335 if (old_list != finally_ips && finally_ips) {
6336 ip = (const guint16*)finally_ips->data;
6337 finally_ips = g_slist_remove (finally_ips, ip);
6338 // we set vt_sp later here so we relieve stack pressure
6339 vt_sp = (unsigned char*)sp + frame->imethod->stack_size;
6340 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6341 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6342 goto main_loop;
6345 ves_abort();
6346 MINT_IN_BREAK;
6348 MINT_IN_CASE(MINT_ICALL_V_V)
6349 MINT_IN_CASE(MINT_ICALL_V_P)
6350 MINT_IN_CASE(MINT_ICALL_P_V)
6351 MINT_IN_CASE(MINT_ICALL_P_P)
6352 MINT_IN_CASE(MINT_ICALL_PP_V)
6353 MINT_IN_CASE(MINT_ICALL_PP_P)
6354 MINT_IN_CASE(MINT_ICALL_PPP_V)
6355 MINT_IN_CASE(MINT_ICALL_PPP_P)
6356 MINT_IN_CASE(MINT_ICALL_PPPP_V)
6357 MINT_IN_CASE(MINT_ICALL_PPPP_P)
6358 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
6359 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
6360 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
6361 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
6362 frame->ip = ip;
6363 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [ip [1]], FALSE);
6364 EXCEPTION_CHECKPOINT_GC_UNSAFE;
6365 CHECK_RESUME_STATE (context);
6366 ip += 2;
6367 MINT_IN_BREAK;
6368 MINT_IN_CASE(MINT_MONO_LDPTR)
6369 sp->data.p = frame->imethod->data_items [ip [1]];
6370 ip += 2;
6371 ++sp;
6372 MINT_IN_BREAK;
6373 MINT_IN_CASE(MINT_MONO_NEWOBJ)
6374 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [1]]); // FIXME: do not swallow the error
6375 ip += 2;
6376 sp++;
6377 MINT_IN_BREAK;
6378 MINT_IN_CASE(MINT_MONO_RETOBJ)
6379 ++ip;
6380 sp--;
6381 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
6382 mono_method_signature_internal (frame->imethod->method)->pinvoke);
6383 if (sp > frame->stack)
6384 g_warning_d ("retobj: more values on stack: %d", sp - frame->stack);
6385 goto exit_frame;
6386 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
6387 sp->data.p = mono_tls_get_sgen_thread_info ();
6388 sp++;
6389 ++ip;
6390 MINT_IN_BREAK;
6391 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
6392 ++ip;
6393 mono_memory_barrier ();
6394 MINT_IN_BREAK;
6396 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
6397 sp->data.p = mono_domain_get ();
6398 ++sp;
6399 ++ip;
6400 MINT_IN_BREAK;
6401 MINT_IN_CASE(MINT_MONO_GET_SP)
6402 sp->data.p = &frame;
6403 ++sp;
6404 ++ip;
6405 MINT_IN_BREAK;
6406 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6407 if (G_UNLIKELY (ss_enabled)) {
6408 typedef void (*T) (void);
6409 static T ss_tramp;
6411 if (!ss_tramp) {
6412 void *tramp = mini_get_single_step_trampoline ();
6413 mono_memory_barrier ();
6414 ss_tramp = (T)tramp;
6418 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6419 * the address of that instruction is stored as the seq point address.
6421 frame->ip = ip + 1;
6424 * Use the same trampoline as the JIT. This ensures that
6425 * the debugger has the context for the last interpreter
6426 * native frame.
6428 do_debugger_tramp (ss_tramp, frame);
6430 CHECK_RESUME_STATE (context);
6432 ++ip;
6433 MINT_IN_BREAK;
6434 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6435 /* Just a placeholder for a breakpoint */
6436 ++ip;
6437 MINT_IN_BREAK;
6438 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6439 typedef void (*T) (void);
6440 static T bp_tramp;
6441 if (!bp_tramp) {
6442 void *tramp = mini_get_breakpoint_trampoline ();
6443 mono_memory_barrier ();
6444 bp_tramp = (T)tramp;
6447 frame->ip = ip;
6449 /* Use the same trampoline as the JIT */
6450 do_debugger_tramp (bp_tramp, frame);
6452 CHECK_RESUME_STATE (context);
6454 ++ip;
6455 MINT_IN_BREAK;
6458 #define RELOP(datamem, op) \
6459 --sp; \
6460 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6461 ++ip;
6463 #define RELOP_FP(datamem, op, noorder) \
6464 --sp; \
6465 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6466 sp [-1].data.i = noorder; \
6467 else \
6468 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6469 ++ip;
6471 MINT_IN_CASE(MINT_CEQ_I4)
6472 RELOP(i, ==);
6473 MINT_IN_BREAK;
6474 MINT_IN_CASE(MINT_CEQ0_I4)
6475 sp [-1].data.i = (sp [-1].data.i == 0);
6476 ++ip;
6477 MINT_IN_BREAK;
6478 MINT_IN_CASE(MINT_CEQ_I8)
6479 RELOP(l, ==);
6480 MINT_IN_BREAK;
6481 MINT_IN_CASE(MINT_CEQ_R4)
6482 RELOP_FP(f_r4, ==, 0);
6483 MINT_IN_BREAK;
6484 MINT_IN_CASE(MINT_CEQ_R8)
6485 RELOP_FP(f, ==, 0);
6486 MINT_IN_BREAK;
6487 MINT_IN_CASE(MINT_CNE_I4)
6488 RELOP(i, !=);
6489 MINT_IN_BREAK;
6490 MINT_IN_CASE(MINT_CNE_I8)
6491 RELOP(l, !=);
6492 MINT_IN_BREAK;
6493 MINT_IN_CASE(MINT_CNE_R4)
6494 RELOP_FP(f_r4, !=, 1);
6495 MINT_IN_BREAK;
6496 MINT_IN_CASE(MINT_CNE_R8)
6497 RELOP_FP(f, !=, 1);
6498 MINT_IN_BREAK;
6499 MINT_IN_CASE(MINT_CGT_I4)
6500 RELOP(i, >);
6501 MINT_IN_BREAK;
6502 MINT_IN_CASE(MINT_CGT_I8)
6503 RELOP(l, >);
6504 MINT_IN_BREAK;
6505 MINT_IN_CASE(MINT_CGT_R4)
6506 RELOP_FP(f_r4, >, 0);
6507 MINT_IN_BREAK;
6508 MINT_IN_CASE(MINT_CGT_R8)
6509 RELOP_FP(f, >, 0);
6510 MINT_IN_BREAK;
6511 MINT_IN_CASE(MINT_CGE_I4)
6512 RELOP(i, >=);
6513 MINT_IN_BREAK;
6514 MINT_IN_CASE(MINT_CGE_I8)
6515 RELOP(l, >=);
6516 MINT_IN_BREAK;
6517 MINT_IN_CASE(MINT_CGE_R4)
6518 RELOP_FP(f_r4, >=, 0);
6519 MINT_IN_BREAK;
6520 MINT_IN_CASE(MINT_CGE_R8)
6521 RELOP_FP(f, >=, 0);
6522 MINT_IN_BREAK;
6524 #define RELOP_CAST(datamem, op, type) \
6525 --sp; \
6526 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6527 ++ip;
6529 MINT_IN_CASE(MINT_CGE_UN_I4)
6530 RELOP_CAST(l, >=, guint32);
6531 MINT_IN_BREAK;
6532 MINT_IN_CASE(MINT_CGE_UN_I8)
6533 RELOP_CAST(l, >=, guint64);
6534 MINT_IN_BREAK;
6536 MINT_IN_CASE(MINT_CGT_UN_I4)
6537 RELOP_CAST(i, >, guint32);
6538 MINT_IN_BREAK;
6539 MINT_IN_CASE(MINT_CGT_UN_I8)
6540 RELOP_CAST(l, >, guint64);
6541 MINT_IN_BREAK;
6542 MINT_IN_CASE(MINT_CGT_UN_R4)
6543 RELOP_FP(f_r4, >, 1);
6544 MINT_IN_BREAK;
6545 MINT_IN_CASE(MINT_CGT_UN_R8)
6546 RELOP_FP(f, >, 1);
6547 MINT_IN_BREAK;
6548 MINT_IN_CASE(MINT_CLT_I4)
6549 RELOP(i, <);
6550 MINT_IN_BREAK;
6551 MINT_IN_CASE(MINT_CLT_I8)
6552 RELOP(l, <);
6553 MINT_IN_BREAK;
6554 MINT_IN_CASE(MINT_CLT_R4)
6555 RELOP_FP(f_r4, <, 0);
6556 MINT_IN_BREAK;
6557 MINT_IN_CASE(MINT_CLT_R8)
6558 RELOP_FP(f, <, 0);
6559 MINT_IN_BREAK;
6560 MINT_IN_CASE(MINT_CLT_UN_I4)
6561 RELOP_CAST(i, <, guint32);
6562 MINT_IN_BREAK;
6563 MINT_IN_CASE(MINT_CLT_UN_I8)
6564 RELOP_CAST(l, <, guint64);
6565 MINT_IN_BREAK;
6566 MINT_IN_CASE(MINT_CLT_UN_R4)
6567 RELOP_FP(f_r4, <, 1);
6568 MINT_IN_BREAK;
6569 MINT_IN_CASE(MINT_CLT_UN_R8)
6570 RELOP_FP(f, <, 1);
6571 MINT_IN_BREAK;
6572 MINT_IN_CASE(MINT_CLE_I4)
6573 RELOP(i, <=);
6574 MINT_IN_BREAK;
6575 MINT_IN_CASE(MINT_CLE_I8)
6576 RELOP(l, <=);
6577 MINT_IN_BREAK;
6578 MINT_IN_CASE(MINT_CLE_UN_I4)
6579 RELOP_CAST(l, <=, guint32);
6580 MINT_IN_BREAK;
6581 MINT_IN_CASE(MINT_CLE_UN_I8)
6582 RELOP_CAST(l, <=, guint64);
6583 MINT_IN_BREAK;
6584 MINT_IN_CASE(MINT_CLE_R4)
6585 RELOP_FP(f_r4, <=, 0);
6586 MINT_IN_BREAK;
6587 MINT_IN_CASE(MINT_CLE_R8)
6588 RELOP_FP(f, <=, 0);
6589 MINT_IN_BREAK;
6591 #undef RELOP
6592 #undef RELOP_FP
6593 #undef RELOP_CAST
6595 MINT_IN_CASE(MINT_LDFTN) {
6596 sp->data.p = frame->imethod->data_items [ip [1]];
6597 ++sp;
6598 ip += 2;
6599 MINT_IN_BREAK;
6601 MINT_IN_CASE(MINT_LDVIRTFTN) {
6602 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [1]];
6603 --sp;
6604 NULL_CHECK (sp->data.p);
6606 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6607 ip += 2;
6608 ++sp;
6609 MINT_IN_BREAK;
6611 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6612 error_init_reuse (error);
6613 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6614 mono_error_assert_ok (error);
6615 sp [-1].data.p = m;
6616 ip++;
6617 MINT_IN_BREAK;
6620 #define LDARG(datamem, argtype) \
6621 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6622 ip += 2; \
6623 ++sp;
6625 #define LDARGn(datamem, argtype, n) \
6626 sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \
6627 ++ip; \
6628 ++sp;
6630 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6631 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6632 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6633 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6634 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6635 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6636 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6637 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6638 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6639 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6641 MINT_IN_CASE(MINT_LDARG_P0) LDARGn(p, gpointer, 0); MINT_IN_BREAK;
6643 MINT_IN_CASE(MINT_LDARG_VT) {
6644 sp->data.p = vt_sp;
6645 int const i32 = READ32 (ip + 2);
6646 memcpy(sp->data.p, frame->stack_args [ip [1]].data.p, i32);
6647 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6648 ip += 4;
6649 ++sp;
6650 MINT_IN_BREAK;
6653 #define STARG(datamem, argtype) \
6654 --sp; \
6655 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6656 ip += 2; \
6658 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6659 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6660 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6661 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6662 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6663 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6664 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6665 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6666 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6667 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6669 MINT_IN_CASE(MINT_STARG_VT) {
6670 int const i32 = READ32 (ip + 2);
6671 --sp;
6672 memcpy(frame->stack_args [ip [1]].data.p, sp->data.p, i32);
6673 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6674 ip += 4;
6675 MINT_IN_BREAK;
6678 MINT_IN_CASE(MINT_PROF_ENTER) {
6679 guint16 flag = ip [1];
6680 ip += 2;
6682 if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter) &&
6683 (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT))) {
6684 MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6685 prof_ctx->interp_frame = frame;
6686 prof_ctx->method = frame->imethod->method;
6687 if (flag & TRACING_FLAG)
6688 mono_trace_enter_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx);
6689 if (flag & PROFILING_FLAG)
6690 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6691 g_free (prof_ctx);
6692 } else if ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter)) {
6693 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, NULL));
6695 MINT_IN_BREAK;
6698 MINT_IN_CASE(MINT_PROF_EXIT)
6699 MINT_IN_CASE(MINT_PROF_EXIT_VOID) {
6700 guint16 flag = ip [1];
6701 // Set retval
6702 int const i32 = READ32 (ip + 2);
6703 if (i32 == -1) {
6704 } else if (i32) {
6705 sp--;
6706 memcpy(frame->retval->data.p, sp->data.p, i32);
6707 } else {
6708 sp--;
6709 *frame->retval = *sp;
6712 if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_leave) &&
6713 (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT))) {
6714 MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6715 prof_ctx->interp_frame = frame;
6716 prof_ctx->method = frame->imethod->method;
6717 if (i32 != -1) {
6718 if (i32)
6719 prof_ctx->return_value = frame->retval->data.p;
6720 else
6721 prof_ctx->return_value = frame->retval;
6723 if (flag & TRACING_FLAG)
6724 mono_trace_leave_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx);
6725 if (flag & PROFILING_FLAG)
6726 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6727 g_free (prof_ctx);
6728 } else if ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter)) {
6729 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, NULL));
6732 ip += 4;
6733 goto exit_frame;
6736 MINT_IN_CASE(MINT_LDARGA)
6737 sp->data.p = &frame->stack_args [ip [1]];
6738 ip += 2;
6739 ++sp;
6740 MINT_IN_BREAK;
6742 MINT_IN_CASE(MINT_LDARGA_VT)
6743 sp->data.p = frame->stack_args [ip [1]].data.p;
6744 ip += 2;
6745 ++sp;
6746 MINT_IN_BREAK;
6748 #define LDLOC(datamem, argtype) \
6749 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6750 ip += 2; \
6751 ++sp;
6753 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6754 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6755 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6756 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6757 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6758 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6759 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6760 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6761 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6762 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6764 MINT_IN_CASE(MINT_LDLOC_VT) {
6765 sp->data.p = vt_sp;
6766 int const i32 = READ32 (ip + 2);
6767 memcpy(sp->data.p, locals + ip [1], i32);
6768 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6769 ip += 4;
6770 ++sp;
6771 MINT_IN_BREAK;
6773 MINT_IN_CASE(MINT_LDLOCA_S)
6774 sp->data.p = locals + ip [1];
6775 ip += 2;
6776 ++sp;
6777 MINT_IN_BREAK;
6779 #define STLOC(datamem, argtype) \
6780 --sp; \
6781 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6782 ip += 2;
6784 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6785 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6786 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6787 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6788 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6789 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6790 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6791 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6792 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6793 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6795 #define STLOC_NP(datamem, argtype) \
6796 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6797 ip += 2;
6799 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6800 MINT_IN_CASE(MINT_STLOC_NP_I8) STLOC_NP(l, gint64); MINT_IN_BREAK;
6801 MINT_IN_CASE(MINT_STLOC_NP_R4) STLOC_NP(f_r4, float); MINT_IN_BREAK;
6802 MINT_IN_CASE(MINT_STLOC_NP_R8) STLOC_NP(f, double); MINT_IN_BREAK;
6803 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6805 MINT_IN_CASE(MINT_STLOC_VT) {
6806 int const i32 = READ32 (ip + 2);
6807 --sp;
6808 memcpy(locals + ip [1], sp->data.p, i32);
6809 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6810 ip += 4;
6811 MINT_IN_BREAK;
6814 #define MOVLOC(argtype) \
6815 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6816 ip += 3;
6818 MINT_IN_CASE(MINT_MOVLOC_1) MOVLOC(guint8); MINT_IN_BREAK;
6819 MINT_IN_CASE(MINT_MOVLOC_2) MOVLOC(guint16); MINT_IN_BREAK;
6820 MINT_IN_CASE(MINT_MOVLOC_4) MOVLOC(guint32); MINT_IN_BREAK;
6821 MINT_IN_CASE(MINT_MOVLOC_8) MOVLOC(guint64); MINT_IN_BREAK;
6823 MINT_IN_CASE(MINT_MOVLOC_VT) {
6824 int const i32 = READ32(ip + 3);
6825 memcpy (locals + ip [2], locals + ip [1], i32);
6826 ip += 5;
6827 MINT_IN_BREAK;
6830 MINT_IN_CASE(MINT_LOCALLOC) {
6831 if (sp != frame->stack + 1) /*FIX?*/
6832 goto abort_label;
6834 int len = sp [-1].data.i;
6835 //sp [-1].data.p = alloca (len);
6836 sp [-1].data.p = alloc_extra_stack_data (context, ALIGN_TO (len, 8));
6838 if (frame->imethod->init_locals)
6839 memset (sp [-1].data.p, 0, len);
6840 ++ip;
6841 MINT_IN_BREAK;
6843 MINT_IN_CASE(MINT_ENDFILTER)
6844 /* top of stack is result of filter */
6845 frame->retval->data.i = sp [-1].data.i;
6846 goto exit_frame;
6847 MINT_IN_CASE(MINT_INITOBJ)
6848 --sp;
6849 memset (sp->data.vt, 0, READ32(ip + 1));
6850 ip += 3;
6851 MINT_IN_BREAK;
6852 MINT_IN_CASE(MINT_CPBLK)
6853 sp -= 3;
6854 if (!sp [0].data.p || !sp [1].data.p)
6855 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6856 ++ip;
6857 /* FIXME: value and size may be int64... */
6858 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6859 MINT_IN_BREAK;
6860 #if 0
6861 MINT_IN_CASE(MINT_CONSTRAINED_) {
6862 guint32 token;
6863 /* FIXME: implement */
6864 ++ip;
6865 token = READ32 (ip);
6866 ip += 2;
6867 MINT_IN_BREAK;
6869 #endif
6870 MINT_IN_CASE(MINT_INITBLK)
6871 sp -= 3;
6872 NULL_CHECK (sp [0].data.p);
6873 ++ip;
6874 /* FIXME: value and size may be int64... */
6875 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6876 MINT_IN_BREAK;
6877 #if 0
6878 MINT_IN_CASE(MINT_NO_)
6879 /* FIXME: implement */
6880 ip += 2;
6881 MINT_IN_BREAK;
6882 #endif
6883 MINT_IN_CASE(MINT_RETHROW) {
6884 int exvar_offset = ip [1];
6885 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6886 MINT_IN_BREAK;
6888 MINT_IN_CASE(MINT_MONO_RETHROW) {
6890 * need to clarify what this should actually do:
6892 * Takes an exception from the stack and rethrows it.
6893 * This is useful for wrappers that don't want to have to
6894 * use CEE_THROW and lose the exception stacktrace.
6897 --sp;
6898 if (!sp->data.p)
6899 sp->data.p = mono_get_exception_null_reference ();
6901 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6902 MINT_IN_BREAK;
6904 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6905 MonoDelegate *del;
6907 --sp;
6908 del = (MonoDelegate*)sp->data.p;
6909 if (!del->interp_method) {
6910 /* Not created from interpreted code */
6911 error_init_reuse (error);
6912 g_assert (del->method);
6913 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6914 mono_error_assert_ok (error);
6916 g_assert (del->interp_method);
6917 sp->data.p = del->interp_method;
6918 ++sp;
6919 ip += 1;
6920 MINT_IN_BREAK;
6922 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6923 MonoDelegate *del;
6924 int n = ip [1];
6925 del = (MonoDelegate*)sp [-n].data.p;
6926 if (!del->interp_invoke_impl) {
6928 * First time we are called. Set up the invoke wrapper. We might be able to do this
6929 * in ctor but we would need to handle AllocDelegateLike_internal separately
6931 error_init_reuse (error);
6932 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6933 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6934 mono_error_assert_ok (error);
6936 sp ++;
6937 sp [-1].data.p = del->interp_invoke_impl;
6938 ip += 2;
6939 MINT_IN_BREAK;
6942 #define MATH_UNOP(mathfunc) \
6943 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6944 ++ip;
6946 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6947 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6948 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6949 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6950 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6951 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6952 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6953 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6954 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6955 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6956 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6957 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6958 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6959 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6960 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6962 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6963 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]];
6964 mono_interp_enum_hasflag (sp, klass);
6965 sp--;
6966 ip += 2;
6967 MINT_IN_BREAK;
6969 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6970 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6971 ip++;
6972 MINT_IN_BREAK;
6974 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6975 NULL_CHECK (sp [-1].data.p);
6976 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6977 ip++;
6978 MINT_IN_BREAK;
6981 #if !USE_COMPUTED_GOTO
6982 default:
6983 g_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code);
6984 #endif
6988 g_assert_not_reached ();
6990 abort_label:
6991 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6992 null_label:
6993 THROW_EX (mono_get_exception_null_reference (), ip);
6994 div_zero_label:
6995 THROW_EX (mono_get_exception_divide_by_zero (), ip);
6996 overflow_label:
6997 THROW_EX (mono_get_exception_overflow (), ip);
6998 throw_error_label:
6999 THROW_EX (mono_error_convert_to_exception (error), ip);
7000 invalid_cast_label:
7001 THROW_EX (mono_get_exception_invalid_cast (), ip);
7002 resume:
7003 g_assert (context->has_resume_state);
7004 g_assert (frame->imethod);
7006 if (frame == context->handler_frame && (!clause_args || context->handler_ip < clause_args->end_at_ip)) {
7007 /* Set the current execution state to the resume state in context */
7009 ip = context->handler_ip;
7010 /* spec says stack should be empty at endfinally so it should be at the start too */
7011 sp = frame->stack;
7012 vt_sp = (guchar*)sp + frame->imethod->stack_size;
7013 g_assert (context->exc_gchandle);
7014 sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle);
7015 ++sp;
7017 finally_ips = clear_resume_state (context, finally_ips);
7018 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
7019 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
7020 goto main_loop;
7022 // fall through
7023 exit_frame:
7024 error_init_reuse (error);
7026 g_assert (frame->imethod);
7028 if (clause_args && clause_args->base_frame) {
7029 // We finished executing a filter. The execution stack of the base frame
7030 // should remain unmodified, but we need to update the local space.
7031 char *locals_base = (char*)clause_args->base_frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size;
7033 memcpy (locals_base, locals, frame->imethod->locals_size);
7036 if (!clause_args && frame->parent && frame->parent->state.ip) {
7037 /* Return to the main loop after a non-recursive interpreter call */
7038 //printf ("R: %s -> %s %p\n", mono_method_get_full_name (frame->imethod->method), mono_method_get_full_name (frame->parent->imethod->method), frame->parent->state.ip);
7039 stackval *retval = frame->retval;
7041 InterpFrame* const child_frame = frame;
7043 frame = frame->parent;
7044 LOAD_INTERP_STATE (frame);
7046 pop_frame (context, child_frame);
7048 CHECK_RESUME_STATE (context);
7050 if (!is_void) {
7051 *sp = *retval;
7052 sp ++;
7054 goto main_loop;
7057 if (!clause_args)
7058 pop_frame (context, frame);
7060 DEBUG_LEAVE ();
7063 static void
7064 interp_parse_options (const char *options)
7066 char **args, **ptr;
7068 if (!options)
7069 return;
7071 args = g_strsplit (options, ",", -1);
7072 for (ptr = args; ptr && *ptr; ptr ++) {
7073 char *arg = *ptr;
7075 if (strncmp (arg, "jit=", 4) == 0)
7076 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
7077 else if (strncmp (arg, "interp-only=", strlen ("interp-only=")) == 0)
7078 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
7079 else if (strncmp (arg, "-inline", 7) == 0)
7080 mono_interp_opt &= ~INTERP_OPT_INLINE;
7081 else if (strncmp (arg, "-cprop", 6) == 0)
7082 mono_interp_opt &= ~INTERP_OPT_CPROP;
7083 else if (strncmp (arg, "-super", 6) == 0)
7084 mono_interp_opt &= ~INTERP_OPT_SUPER_INSTRUCTIONS;
7085 else if (strncmp (arg, "-all", 4) == 0)
7086 mono_interp_opt = INTERP_OPT_NONE;
7091 * interp_set_resume_state:
7093 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
7095 static void
7096 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoObject *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
7098 ThreadContext *context;
7100 g_assert (jit_tls);
7101 context = (ThreadContext*)jit_tls->interp_context;
7102 g_assert (context);
7104 context->has_resume_state = TRUE;
7105 context->handler_frame = (InterpFrame*)interp_frame;
7106 context->handler_ei = ei;
7107 if (context->exc_gchandle)
7108 mono_gchandle_free_internal (context->exc_gchandle);
7109 context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
7110 /* Ditto */
7111 if (ei)
7112 *(MonoObject**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
7113 context->handler_ip = (const guint16*)handler_ip;
7116 static void
7117 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
7119 g_assert (jit_tls);
7120 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
7122 *has_resume_state = context ? context->has_resume_state : FALSE;
7123 if (!*has_resume_state)
7124 return;
7126 *interp_frame = context->handler_frame;
7127 *handler_ip = (gpointer)context->handler_ip;
7131 * interp_run_finally:
7133 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
7134 * frame->interp_frame.
7135 * Return TRUE if the finally clause threw an exception.
7137 static gboolean
7138 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
7140 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
7141 ThreadContext *context = get_context ();
7142 const unsigned short *old_ip = iframe->ip;
7143 FrameClauseArgs clause_args;
7144 const guint16 *saved_ip;
7146 memset (&clause_args, 0, sizeof (FrameClauseArgs));
7147 clause_args.start_with_ip = (const guint16*)handler_ip;
7148 clause_args.end_at_ip = (const guint16*)handler_ip_end;
7149 clause_args.exit_clause = clause_index;
7151 saved_ip = iframe->state.ip;
7152 iframe->state.ip = NULL;
7154 ERROR_DECL (error);
7155 interp_exec_method_full (iframe, context, &clause_args, error);
7156 iframe->state.ip = saved_ip;
7157 iframe->state.clause_args = NULL;
7158 if (context->has_resume_state) {
7159 return TRUE;
7160 } else {
7161 iframe->ip = old_ip;
7162 return FALSE;
7167 * interp_run_filter:
7169 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
7170 * frame->interp_frame.
7172 static gboolean
7173 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
7175 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
7176 ThreadContext *context = get_context ();
7177 InterpFrame *child_frame;
7178 stackval retval;
7179 FrameClauseArgs clause_args;
7182 * Have to run the clause in a new frame which is a copy of IFRAME, since
7183 * during debugging, there are two copies of the frame on the stack.
7185 child_frame = alloc_frame (context, &retval, iframe, iframe->imethod, iframe->stack_args, &retval);
7187 memset (&clause_args, 0, sizeof (FrameClauseArgs));
7188 clause_args.start_with_ip = (const guint16*)handler_ip;
7189 clause_args.end_at_ip = (const guint16*)handler_ip_end;
7190 clause_args.filter_exception = ex;
7191 clause_args.base_frame = iframe;
7193 ERROR_DECL (error);
7194 interp_exec_method_full (child_frame, context, &clause_args, error);
7195 /* ENDFILTER stores the result into child_frame->retval */
7196 return retval.data.i ? TRUE : FALSE;
7199 typedef struct {
7200 InterpFrame *current;
7201 } StackIter;
7204 * interp_frame_iter_init:
7206 * Initialize an iterator for iterating through interpreted frames.
7208 static void
7209 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
7211 StackIter *stack_iter = (StackIter*)iter;
7213 stack_iter->current = (InterpFrame*)interp_exit_data;
7217 * interp_frame_iter_next:
7219 * Fill out FRAME with date for the next interpreter frame.
7221 static gboolean
7222 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
7224 StackIter *stack_iter = (StackIter*)iter;
7225 InterpFrame *iframe = stack_iter->current;
7227 memset (frame, 0, sizeof (StackFrameInfo));
7228 /* pinvoke frames doesn't have imethod set */
7229 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
7230 iframe = iframe->parent;
7231 if (!iframe)
7232 return FALSE;
7234 MonoMethod *method = iframe->imethod->method;
7235 frame->domain = iframe->imethod->domain;
7236 frame->interp_frame = iframe;
7237 frame->method = method;
7238 frame->actual_method = method;
7239 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
7240 frame->native_offset = -1;
7241 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
7242 } else {
7243 frame->type = FRAME_TYPE_INTERP;
7244 /* This is the offset in the interpreter IR */
7245 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
7246 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
7247 frame->managed = TRUE;
7249 frame->ji = iframe->imethod->jinfo;
7250 frame->frame_addr = iframe->native_stack_addr;
7252 stack_iter->current = iframe->parent;
7254 return TRUE;
7257 static MonoJitInfo*
7258 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
7260 InterpMethod* imethod;
7262 imethod = lookup_imethod (domain, method);
7263 if (imethod)
7264 return imethod->jinfo;
7265 else
7266 return NULL;
7269 static void
7270 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
7272 guint16 *code = (guint16*)ip;
7273 g_assert (*code == MINT_SDB_SEQ_POINT);
7274 *code = MINT_SDB_BREAKPOINT;
7277 static void
7278 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
7280 guint16 *code = (guint16*)ip;
7281 g_assert (*code == MINT_SDB_BREAKPOINT);
7282 *code = MINT_SDB_SEQ_POINT;
7285 static MonoJitInfo*
7286 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
7288 InterpFrame *iframe = (InterpFrame*)frame;
7290 g_assert (iframe->imethod);
7291 return iframe->imethod->jinfo;
7294 static gpointer
7295 interp_frame_get_ip (MonoInterpFrameHandle frame)
7297 InterpFrame *iframe = (InterpFrame*)frame;
7299 g_assert (iframe->imethod);
7300 return (gpointer)iframe->ip;
7303 static gpointer
7304 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
7306 InterpFrame *iframe = (InterpFrame*)frame;
7307 MonoMethodSignature *sig;
7309 g_assert (iframe->imethod);
7311 sig = mono_method_signature_internal (iframe->imethod->method);
7312 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
7315 static gpointer
7316 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
7318 InterpFrame *iframe = (InterpFrame*)frame;
7320 g_assert (iframe->imethod);
7322 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
7325 static gpointer
7326 interp_frame_get_this (MonoInterpFrameHandle frame)
7328 InterpFrame *iframe = (InterpFrame*)frame;
7330 g_assert (iframe->imethod);
7331 g_assert (iframe->imethod->hasthis);
7332 return &iframe->stack_args [0].data.p;
7335 static MonoInterpFrameHandle
7336 interp_frame_get_parent (MonoInterpFrameHandle frame)
7338 InterpFrame *iframe = (InterpFrame*)frame;
7340 return iframe->parent;
7343 static gpointer
7344 interp_frame_get_res (MonoInterpFrameHandle frame)
7346 InterpFrame *iframe = (InterpFrame*)frame;
7347 MonoMethodSignature *sig;
7349 g_assert (iframe->imethod);
7350 sig = mono_method_signature_internal (iframe->imethod->method);
7351 if (sig->ret->type == MONO_TYPE_VOID)
7352 return NULL;
7353 else
7354 return stackval_to_data_addr (sig->ret, iframe->retval);
7357 static gpointer
7358 interp_frame_get_native_stack_addr (MonoInterpFrameHandle frame)
7360 InterpFrame *iframe = (InterpFrame*)frame;
7362 return iframe->native_stack_addr;
7365 static void
7366 interp_start_single_stepping (void)
7368 ss_enabled = TRUE;
7371 static void
7372 interp_stop_single_stepping (void)
7374 ss_enabled = FALSE;
7378 * interp_mark_stack:
7380 * Mark the interpreter stack frames for a thread.
7383 static void
7384 interp_mark_stack (gpointer thread_data, GcScanFunc func, gpointer gc_data, gboolean precise)
7386 MonoThreadInfo *info = (MonoThreadInfo*)thread_data;
7388 if (!mono_use_interpreter)
7389 return;
7390 if (precise)
7391 return;
7394 * We explicitly mark the frames instead of registering the stack fragments as GC roots, so
7395 * we have to process less data and avoid false pinning from data which is above 'pos'.
7397 * The stack frame handling code uses compiler write barriers only, but the calling code
7398 * in sgen-mono.c already did a mono_memory_barrier_process_wide () so we can
7399 * process these data structures normally.
7401 MonoJitTlsData *jit_tls = (MonoJitTlsData *)info->tls [TLS_KEY_JIT_TLS];
7402 if (!jit_tls)
7403 return;
7405 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
7406 if (!context || !context->data_stack.inited)
7407 return;
7409 StackFragment *frag;
7410 for (frag = context->data_stack.first; frag; frag = frag->next) {
7411 // FIXME: Scan the whole area with 1 call
7412 for (gpointer *p = (gpointer*)&frag->data; p < (gpointer*)frag->pos; ++p)
7413 func (p, gc_data);
7414 if (frag == context->data_stack.current)
7415 break;
7419 #if COUNT_OPS
7421 static int
7422 opcode_count_comparer (const void * pa, const void * pb)
7424 long counta = opcode_counts [*(int*)pa];
7425 long countb = opcode_counts [*(int*)pb];
7427 if (counta < countb)
7428 return 1;
7429 else if (counta > countb)
7430 return -1;
7431 else
7432 return 0;
7435 static void
7436 interp_print_op_count (void)
7438 int ordered_ops [MINT_LASTOP];
7439 int i;
7440 long total_ops = 0;
7442 for (i = 0; i < MINT_LASTOP; i++) {
7443 ordered_ops [i] = i;
7444 total_ops += opcode_counts [i];
7446 qsort (ordered_ops, MINT_LASTOP, sizeof (int), opcode_count_comparer);
7448 for (i = 0; i < MINT_LASTOP; i++) {
7449 long count = opcode_counts [ordered_ops [i]];
7450 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops [i]), count, (double)count / total_ops * 100);
7453 #endif
7455 static void
7456 interp_set_optimizations (guint32 opts)
7458 mono_interp_opt = opts;
7461 static void
7462 invalidate_transform (gpointer imethod_)
7464 InterpMethod *imethod = (InterpMethod *) imethod_;
7465 imethod->transformed = FALSE;
7468 static void
7469 interp_invalidate_transformed (MonoDomain *domain)
7471 MonoJitDomainInfo *info = domain_jit_info (domain);
7472 mono_domain_jit_code_hash_lock (domain);
7473 mono_internal_hash_table_apply (&info->interp_code_hash, invalidate_transform);
7474 mono_domain_jit_code_hash_unlock (domain);
7477 static void
7478 interp_cleanup (void)
7480 #if COUNT_OPS
7481 interp_print_op_count ();
7482 #endif
7485 static void
7486 register_interp_stats (void)
7488 mono_counters_init ();
7489 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
7490 mono_counters_register ("Methods transformed", MONO_COUNTER_INTERP | MONO_COUNTER_LONG, &mono_interp_stats.methods_transformed);
7491 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.cprop_time);
7492 mono_counters_register ("Total super instructions time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.super_instructions_time);
7493 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.stloc_nps);
7494 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.movlocs);
7495 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.copy_propagations);
7496 mono_counters_register ("Added pop count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.added_pop_count);
7497 mono_counters_register ("Constant folds", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.constant_folds);
7498 mono_counters_register ("Super instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.super_instructions);
7499 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.killed_instructions);
7500 mono_counters_register ("Emitted instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.emitted_instructions);
7501 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
7502 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
7505 #undef MONO_EE_CALLBACK
7506 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
7508 static const MonoEECallbacks mono_interp_callbacks = {
7509 MONO_EE_CALLBACKS
7512 void
7513 mono_ee_interp_init (const char *opts)
7515 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
7516 g_assert (!interp_init_done);
7517 interp_init_done = TRUE;
7519 mono_native_tls_alloc (&thread_context_id, NULL);
7520 set_context (NULL);
7522 interp_parse_options (opts);
7523 /* Don't do any optimizations if running under debugger */
7524 if (mini_get_debug_options ()->mdb_optimizations)
7525 mono_interp_opt = 0;
7526 mono_interp_transform_init ();
7528 mini_install_interp_callbacks (&mono_interp_callbacks);
7530 register_interp_stats ();