[interp] Make newobj_vt[st]_fast non-recursive. (#18902)
[mono-project.git] / mono / mini / interp / interp.c
blobd48451ff1bede8f08e40fad05d347cc4143ff099
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 MONO_ALWAYS_INLINE InterpFrame*
228 alloc_frame (ThreadContext *ctx, gpointer native_stack_addr, InterpFrame *parent, InterpMethod *imethod, stackval *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 = 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 MONO_NEVER_INLINE 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 MONO_NEVER_INLINE 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 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
1164 do { \
1165 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
1166 MonoException *exc = mono_thread_interruption_checkpoint (); \
1167 if (exc) \
1168 return exc; \
1170 } while (0)
1172 static MonoObject*
1173 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
1175 uintptr_t *lengths;
1176 intptr_t *lower_bounds;
1177 int i;
1179 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
1180 for (i = 0; i < param_count; ++i) {
1181 lengths [i] = values->data.i;
1182 values ++;
1184 if (m_class_get_rank (klass) == param_count) {
1185 /* Only lengths provided. */
1186 lower_bounds = NULL;
1187 } else {
1188 /* lower bounds are first. */
1189 lower_bounds = (intptr_t *) lengths;
1190 lengths += m_class_get_rank (klass);
1192 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
1195 static gint32
1196 ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
1198 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1200 guint32 pos = 0;
1201 if (ao->bounds) {
1202 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
1203 guint32 idx = sp [i].data.i;
1204 guint32 lower = ao->bounds [i].lower_bound;
1205 guint32 len = ao->bounds [i].length;
1206 if (safe && (idx < lower || (idx - lower) >= len))
1207 return -1;
1208 pos = (pos * len) + idx - lower;
1210 } else {
1211 pos = sp [0].data.i;
1212 if (safe && pos >= ao->max_length)
1213 return -1;
1215 return pos;
1218 static MonoException*
1219 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1221 MonoObject *o = sp->data.o;
1222 MonoArray *ao = (MonoArray *) o;
1223 MonoClass *ac = o->vtable->klass;
1225 g_assert (m_class_get_rank (ac) >= 1);
1227 gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
1228 if (pos == -1)
1229 return mono_get_exception_index_out_of_range ();
1231 gint32 esize = mono_array_element_size (ac);
1232 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1234 MonoType *mt = sig->ret;
1235 stackval_from_data (mt, retval, ea, FALSE);
1236 return NULL;
1239 static MONO_NEVER_INLINE MonoException*
1240 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1242 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1244 g_assert (m_class_get_rank (ac) >= 1);
1246 gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
1247 if (pos == -1)
1248 return mono_get_exception_index_out_of_range ();
1250 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
1251 return mono_get_exception_array_type_mismatch ();
1252 gint32 esize = mono_array_element_size (ac);
1253 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
1254 return NULL;
1257 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1258 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1259 #endif
1261 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1262 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1264 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1266 #ifdef TARGET_ARM
1267 g_assert (mono_arm_eabi_supported ());
1268 int i8_align = mono_arm_i8_align ();
1269 #endif
1271 #ifdef TARGET_WASM
1272 margs->sig = sig;
1273 #endif
1275 if (sig->hasthis)
1276 margs->ilen++;
1278 for (int i = 0; i < sig->param_count; i++) {
1279 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1280 switch (ptype) {
1281 case MONO_TYPE_BOOLEAN:
1282 case MONO_TYPE_CHAR:
1283 case MONO_TYPE_I1:
1284 case MONO_TYPE_U1:
1285 case MONO_TYPE_I2:
1286 case MONO_TYPE_U2:
1287 case MONO_TYPE_I4:
1288 case MONO_TYPE_U4:
1289 case MONO_TYPE_I:
1290 case MONO_TYPE_U:
1291 case MONO_TYPE_PTR:
1292 case MONO_TYPE_SZARRAY:
1293 case MONO_TYPE_CLASS:
1294 case MONO_TYPE_OBJECT:
1295 case MONO_TYPE_STRING:
1296 case MONO_TYPE_VALUETYPE:
1297 case MONO_TYPE_GENERICINST:
1298 #if SIZEOF_VOID_P == 8
1299 case MONO_TYPE_I8:
1300 case MONO_TYPE_U8:
1301 #endif
1302 margs->ilen++;
1303 break;
1304 #if SIZEOF_VOID_P == 4
1305 case MONO_TYPE_I8:
1306 case MONO_TYPE_U8:
1307 #ifdef TARGET_ARM
1308 /* pairs begin at even registers */
1309 if (i8_align == 8 && margs->ilen & 1)
1310 margs->ilen++;
1311 #endif
1312 margs->ilen += 2;
1313 break;
1314 #endif
1315 case MONO_TYPE_R4:
1316 #if SIZEOF_VOID_P == 8
1317 case MONO_TYPE_R8:
1318 #endif
1319 margs->flen++;
1320 break;
1321 #if SIZEOF_VOID_P == 4
1322 case MONO_TYPE_R8:
1323 margs->flen += 2;
1324 break;
1325 #endif
1326 default:
1327 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1331 if (margs->ilen > 0)
1332 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1334 if (margs->flen > 0)
1335 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1337 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1338 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1340 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1341 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1344 size_t int_i = 0;
1345 size_t int_f = 0;
1347 if (sig->hasthis) {
1348 margs->iargs [0] = frame->stack_args->data.p;
1349 int_i++;
1352 for (int i = 0; i < sig->param_count; i++) {
1353 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1354 switch (ptype) {
1355 case MONO_TYPE_BOOLEAN:
1356 case MONO_TYPE_CHAR:
1357 case MONO_TYPE_I1:
1358 case MONO_TYPE_U1:
1359 case MONO_TYPE_I2:
1360 case MONO_TYPE_U2:
1361 case MONO_TYPE_I4:
1362 case MONO_TYPE_U4:
1363 case MONO_TYPE_I:
1364 case MONO_TYPE_U:
1365 case MONO_TYPE_PTR:
1366 case MONO_TYPE_SZARRAY:
1367 case MONO_TYPE_CLASS:
1368 case MONO_TYPE_OBJECT:
1369 case MONO_TYPE_STRING:
1370 case MONO_TYPE_VALUETYPE:
1371 case MONO_TYPE_GENERICINST:
1372 #if SIZEOF_VOID_P == 8
1373 case MONO_TYPE_I8:
1374 case MONO_TYPE_U8:
1375 #endif
1376 margs->iargs [int_i] = frame->stack_args [i].data.p;
1377 #if DEBUG_INTERP
1378 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1379 #endif
1380 int_i++;
1381 break;
1382 #if SIZEOF_VOID_P == 4
1383 case MONO_TYPE_I8:
1384 case MONO_TYPE_U8: {
1385 stackval *sarg = &frame->stack_args [i];
1386 #ifdef TARGET_ARM
1387 /* pairs begin at even registers */
1388 if (i8_align == 8 && int_i & 1)
1389 int_i++;
1390 #endif
1391 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1392 int_i++;
1393 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1394 #if DEBUG_INTERP
1395 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);
1396 #endif
1397 int_i++;
1398 break;
1400 #endif
1401 case MONO_TYPE_R4:
1402 case MONO_TYPE_R8:
1403 if (ptype == MONO_TYPE_R4)
1404 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1405 else
1406 margs->fargs [int_f] = frame->stack_args [i].data.f;
1407 #if DEBUG_INTERP
1408 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);
1409 #endif
1410 #if SIZEOF_VOID_P == 4
1411 int_f += 2;
1412 #else
1413 int_f++;
1414 #endif
1415 break;
1416 default:
1417 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1421 switch (sig->ret->type) {
1422 case MONO_TYPE_BOOLEAN:
1423 case MONO_TYPE_CHAR:
1424 case MONO_TYPE_I1:
1425 case MONO_TYPE_U1:
1426 case MONO_TYPE_I2:
1427 case MONO_TYPE_U2:
1428 case MONO_TYPE_I4:
1429 case MONO_TYPE_U4:
1430 case MONO_TYPE_I:
1431 case MONO_TYPE_U:
1432 case MONO_TYPE_PTR:
1433 case MONO_TYPE_SZARRAY:
1434 case MONO_TYPE_CLASS:
1435 case MONO_TYPE_OBJECT:
1436 case MONO_TYPE_STRING:
1437 case MONO_TYPE_I8:
1438 case MONO_TYPE_U8:
1439 case MONO_TYPE_VALUETYPE:
1440 case MONO_TYPE_GENERICINST:
1441 margs->retval = &(frame->retval->data.p);
1442 margs->is_float_ret = 0;
1443 break;
1444 case MONO_TYPE_R4:
1445 case MONO_TYPE_R8:
1446 margs->retval = &(frame->retval->data.p);
1447 margs->is_float_ret = 1;
1448 break;
1449 case MONO_TYPE_VOID:
1450 margs->retval = NULL;
1451 break;
1452 default:
1453 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1456 return margs;
1458 #endif
1460 static void
1461 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1463 InterpFrame *iframe = (InterpFrame*)frame;
1465 if (index == -1)
1466 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1467 else
1468 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1471 static void
1472 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1474 InterpFrame *iframe = (InterpFrame*)frame;
1476 if (index == -1)
1477 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1478 else if (sig->hasthis && index == 0)
1479 iframe->stack_args [index].data.p = *(gpointer*)data;
1480 else
1481 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1484 static gpointer
1485 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1487 InterpFrame *iframe = (InterpFrame*)frame;
1489 if (index == -1)
1490 return stackval_to_data_addr (sig->ret, iframe->retval);
1491 else
1492 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1495 static void
1496 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1498 InterpFrame *iframe = (InterpFrame*)frame;
1499 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1500 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1502 switch (type->type) {
1503 case MONO_TYPE_GENERICINST:
1504 if (!MONO_TYPE_IS_REFERENCE (type))
1505 val->data.vt = storage;
1506 break;
1507 case MONO_TYPE_VALUETYPE:
1508 val->data.vt = storage;
1509 break;
1510 default:
1511 g_assert_not_reached ();
1515 static MonoPIFunc
1516 get_interp_to_native_trampoline (void)
1518 static MonoPIFunc trampoline = NULL;
1520 if (!trampoline) {
1521 if (mono_ee_features.use_aot_trampolines) {
1522 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1523 } else {
1524 MonoTrampInfo *info;
1525 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1526 mono_tramp_info_register (info, NULL);
1528 mono_memory_barrier ();
1530 return trampoline;
1533 static void
1534 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1536 get_interp_to_native_trampoline () (addr, ccontext);
1539 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1540 #ifdef _MSC_VER
1541 #pragma optimize ("", off)
1542 #endif
1543 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1544 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, ThreadContext *context, gboolean save_last_error)
1546 MonoLMFExt ext;
1547 gpointer args;
1549 g_assert (!frame->imethod);
1551 static MonoPIFunc entry_func = NULL;
1552 if (!entry_func) {
1553 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1554 ERROR_DECL (error);
1555 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);
1556 mono_error_assert_ok (error);
1557 #else
1558 entry_func = get_interp_to_native_trampoline ();
1559 #endif
1560 mono_memory_barrier ();
1563 #ifdef ENABLE_NETCORE
1564 if (save_last_error) {
1565 mono_marshal_clear_last_error ();
1567 #endif
1569 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1570 CallContext ccontext;
1571 MONO_ENTER_GC_UNSAFE;
1572 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1573 MONO_EXIT_GC_UNSAFE;
1574 args = &ccontext;
1575 #else
1576 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1577 args = margs;
1578 #endif
1580 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1581 entry_func ((gpointer) addr, args);
1582 if (save_last_error)
1583 mono_marshal_set_last_error ();
1584 interp_pop_lmf (&ext);
1586 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1587 if (!context->has_resume_state) {
1588 MONO_ENTER_GC_UNSAFE;
1589 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1590 MONO_EXIT_GC_UNSAFE;
1593 if (ccontext.stack != NULL)
1594 g_free (ccontext.stack);
1595 #else
1596 if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
1597 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1599 g_free (margs->iargs);
1600 g_free (margs->fargs);
1601 g_free (margs);
1602 #endif
1603 goto exit_pinvoke; // prevent unused label warning in some configurations
1604 exit_pinvoke:
1605 return;
1607 #ifdef _MSC_VER
1608 #pragma optimize ("", on)
1609 #endif
1612 * interp_init_delegate:
1614 * Initialize del->interp_method.
1616 static void
1617 interp_init_delegate (MonoDelegate *del, MonoError *error)
1619 MonoMethod *method;
1621 if (del->interp_method) {
1622 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1623 del->method = ((InterpMethod *)del->interp_method)->method;
1624 } else if (del->method) {
1625 /* Delegate created dynamically */
1626 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1627 } else {
1628 /* Created from JITted code */
1629 g_assert_not_reached ();
1632 method = ((InterpMethod*)del->interp_method)->method;
1633 if (del->target &&
1634 method &&
1635 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1636 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1637 mono_class_is_abstract (method->klass))
1638 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1640 method = ((InterpMethod*)del->interp_method)->method;
1641 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1642 const char *name = method->name;
1643 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1645 * When invoking the delegate interp_method is executed directly. If it's an
1646 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1648 * FIXME We should do this later, when we also know the delegate on which the
1649 * target method is called.
1651 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1652 mono_error_assert_ok (error);
1656 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1657 /* Return any errors from method compilation */
1658 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1659 return_if_nok (error);
1663 static void
1664 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1667 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1669 InterpMethod *imethod = (InterpMethod*)addr;
1671 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1672 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1673 /* virtual invoke delegates must not have null check */
1674 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1675 && MONO_HANDLE_IS_NULL (target)) {
1676 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1677 return;
1681 g_assert (imethod->method);
1682 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1683 return_if_nok (error);
1685 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1687 mono_delegate_ctor (this_obj, target, entry, error);
1691 * From the spec:
1692 * runtime specifies that the implementation of the method is automatically
1693 * provided by the runtime and is primarily used for the methods of delegates.
1695 #ifndef ENABLE_NETCORE
1696 static MONO_NEVER_INLINE MonoException*
1697 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1699 const char *name = method->name;
1700 mono_class_init_internal (method->klass);
1702 if (method->klass == mono_defaults.array_class) {
1703 if (!strcmp (name, "UnsafeMov")) {
1704 /* TODO: layout checks */
1705 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1706 return NULL;
1708 if (!strcmp (name, "UnsafeLoad"))
1709 return ves_array_get (frame, sp, retval, sig, FALSE);
1712 g_error ("Don't know how to exec runtime method %s.%s::%s",
1713 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1714 method->name);
1716 #endif
1718 #if DEBUG_INTERP
1719 static char*
1720 dump_stack (stackval *stack, stackval *sp)
1722 stackval *s = stack;
1723 GString *str = g_string_new ("");
1725 if (sp == stack)
1726 return g_string_free (str, FALSE);
1728 while (s < sp) {
1729 g_string_append_printf (str, "[%p (%" PRId64 ")] ", s->data.l, (gint64)s->data.l);
1730 ++s;
1732 return g_string_free (str, FALSE);
1735 static void
1736 dump_stackval (GString *str, stackval *s, MonoType *type)
1738 switch (type->type) {
1739 case MONO_TYPE_I1:
1740 case MONO_TYPE_U1:
1741 case MONO_TYPE_I2:
1742 case MONO_TYPE_U2:
1743 case MONO_TYPE_I4:
1744 case MONO_TYPE_U4:
1745 case MONO_TYPE_CHAR:
1746 case MONO_TYPE_BOOLEAN:
1747 g_string_append_printf (str, "[%d] ", s->data.i);
1748 break;
1749 case MONO_TYPE_STRING:
1750 case MONO_TYPE_SZARRAY:
1751 case MONO_TYPE_CLASS:
1752 case MONO_TYPE_OBJECT:
1753 case MONO_TYPE_ARRAY:
1754 case MONO_TYPE_PTR:
1755 case MONO_TYPE_I:
1756 case MONO_TYPE_U:
1757 g_string_append_printf (str, "[%p] ", s->data.p);
1758 break;
1759 case MONO_TYPE_VALUETYPE:
1760 if (m_class_is_enumtype (type->data.klass))
1761 g_string_append_printf (str, "[%d] ", s->data.i);
1762 else
1763 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1764 break;
1765 case MONO_TYPE_R4:
1766 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1767 break;
1768 case MONO_TYPE_R8:
1769 g_string_append_printf (str, "[%g] ", s->data.f);
1770 break;
1771 case MONO_TYPE_I8:
1772 case MONO_TYPE_U8:
1773 default: {
1774 GString *res = g_string_new ("");
1775 mono_type_get_desc (res, type, TRUE);
1776 g_string_append_printf (str, "[{%s} %" PRId64 "/0x%0" PRIx64 "] ", res->str, (gint64)s->data.l, (guint64)s->data.l);
1777 g_string_free (res, TRUE);
1778 break;
1783 static char*
1784 dump_retval (InterpFrame *inv)
1786 GString *str = g_string_new ("");
1787 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1789 if (ret->type != MONO_TYPE_VOID)
1790 dump_stackval (str, inv->retval, ret);
1792 return g_string_free (str, FALSE);
1795 static char*
1796 dump_args (InterpFrame *inv)
1798 GString *str = g_string_new ("");
1799 int i;
1800 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1802 if (signature->param_count == 0 && !signature->hasthis)
1803 return g_string_free (str, FALSE);
1805 if (signature->hasthis) {
1806 MonoMethod *method = inv->imethod->method;
1807 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1810 for (i = 0; i < signature->param_count; ++i)
1811 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1813 return g_string_free (str, FALSE);
1815 #endif
1817 #define CHECK_ADD_OVERFLOW(a,b) \
1818 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1819 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1821 #define CHECK_SUB_OVERFLOW(a,b) \
1822 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1823 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1825 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1826 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1828 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1829 (guint32)(a) < (guint32)(b) ? -1 : 0
1831 #define CHECK_ADD_OVERFLOW64(a,b) \
1832 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1833 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1835 #define CHECK_SUB_OVERFLOW64(a,b) \
1836 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1837 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1839 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1840 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1842 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1843 (guint64)(a) < (guint64)(b) ? -1 : 0
1845 #if SIZEOF_VOID_P == 4
1846 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1847 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1848 #else
1849 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1850 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1851 #endif
1853 /* Resolves to TRUE if the operands would overflow */
1854 #define CHECK_MUL_OVERFLOW(a,b) \
1855 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1856 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1857 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1858 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1859 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1860 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1861 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1863 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1864 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1865 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1867 #define CHECK_MUL_OVERFLOW64(a,b) \
1868 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1869 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1870 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1871 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1872 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1873 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1874 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1876 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1877 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1878 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1880 #if SIZEOF_VOID_P == 4
1881 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1882 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1883 #else
1884 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1885 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1886 #endif
1888 static MonoObject*
1889 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1891 InterpFrame *frame;
1892 ThreadContext *context = get_context ();
1893 MonoMethodSignature *sig = mono_method_signature_internal (method);
1894 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1895 stackval result;
1896 MonoMethod *target_method = method;
1898 error_init (error);
1899 if (exc)
1900 *exc = NULL;
1902 MonoDomain *domain = mono_domain_get ();
1904 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1905 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1906 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1908 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1910 result.data.vt = alloca (mono_class_instance_size (klass));
1911 stackval args [4];
1913 if (sig->hasthis)
1914 args [0].data.p = obj;
1915 else
1916 args [0].data.p = NULL;
1917 args [1].data.p = params;
1918 args [2].data.p = exc;
1919 args [3].data.p = target_method;
1921 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1922 mono_error_assert_ok (error);
1923 frame = alloc_frame (context, &result, NULL, imethod, args, &result);
1925 interp_exec_method (frame, context, error);
1927 if (context->has_resume_state) {
1928 // This can happen on wasm !?
1929 MonoException *thrown_exc = (MonoException*) mono_gchandle_get_target_internal (context->exc_gchandle);
1930 if (exc)
1931 *exc = (MonoObject*)thrown_exc;
1932 else
1933 mono_error_set_exception_instance (error, thrown_exc);
1934 return NULL;
1936 return (MonoObject*)result.data.p;
1939 typedef struct {
1940 InterpMethod *rmethod;
1941 gpointer this_arg;
1942 gpointer res;
1943 gpointer args [16];
1944 gpointer *many_args;
1945 } InterpEntryData;
1947 /* Main function for entering the interpreter from compiled code */
1948 static void
1949 interp_entry (InterpEntryData *data)
1951 InterpFrame *frame;
1952 InterpMethod *rmethod;
1953 ThreadContext *context;
1954 stackval result;
1955 stackval *args;
1956 stackval *retval;
1957 MonoMethod *method;
1958 MonoMethodSignature *sig;
1959 MonoType *type;
1960 gpointer orig_domain = NULL, attach_cookie;
1961 int i;
1963 if ((gsize)data->rmethod & 1) {
1964 /* Unbox */
1965 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1966 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1968 rmethod = data->rmethod;
1970 if (rmethod->needs_thread_attach)
1971 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1973 context = get_context ();
1975 method = rmethod->method;
1976 sig = mono_method_signature_internal (method);
1978 // FIXME: Optimize this
1980 //printf ("%s\n", mono_method_full_name (method, 1));
1982 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1983 if (sig->hasthis)
1984 args [0].data.p = data->this_arg;
1986 gpointer *params;
1987 if (data->many_args)
1988 params = data->many_args;
1989 else
1990 params = data->args;
1991 for (i = 0; i < sig->param_count; ++i) {
1992 int a_index = i + (sig->hasthis ? 1 : 0);
1993 if (sig->params [i]->byref) {
1994 args [a_index].data.p = params [i];
1995 continue;
1997 type = rmethod->param_types [i];
1998 switch (type->type) {
1999 case MONO_TYPE_VALUETYPE:
2000 args [a_index].data.p = params [i];
2001 break;
2002 case MONO_TYPE_GENERICINST:
2003 if (MONO_TYPE_IS_REFERENCE (type))
2004 args [a_index].data.p = *(gpointer*)params [i];
2005 else
2006 args [a_index].data.vt = params [i];
2007 break;
2008 default:
2009 stackval_from_data (type, &args [a_index], params [i], FALSE);
2010 break;
2014 memset (&result, 0, sizeof (result));
2015 retval = &result;
2016 frame = alloc_frame (context, &result, NULL, data->rmethod, args, retval);
2018 type = rmethod->rtype;
2019 switch (type->type) {
2020 case MONO_TYPE_GENERICINST:
2021 if (!MONO_TYPE_IS_REFERENCE (type))
2022 retval->data.vt = data->res;
2023 break;
2024 case MONO_TYPE_VALUETYPE:
2025 retval->data.vt = data->res;
2026 break;
2027 default:
2028 break;
2031 ERROR_DECL (error);
2032 interp_exec_method (frame, context, error);
2034 g_assert (!context->has_resume_state);
2036 if (rmethod->needs_thread_attach)
2037 mono_threads_detach_coop (orig_domain, &attach_cookie);
2039 if (mono_llvm_only) {
2040 if (context->has_resume_state)
2041 mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
2042 } else {
2043 g_assert (!context->has_resume_state);
2046 type = rmethod->rtype;
2047 switch (type->type) {
2048 case MONO_TYPE_VOID:
2049 break;
2050 case MONO_TYPE_OBJECT:
2051 /* No need for a write barrier */
2052 *(MonoObject**)data->res = (MonoObject*)retval->data.p;
2053 break;
2054 case MONO_TYPE_GENERICINST:
2055 if (MONO_TYPE_IS_REFERENCE (type)) {
2056 *(MonoObject**)data->res = (MonoObject*)retval->data.p;
2057 } else {
2058 /* Already set before the call */
2060 break;
2061 case MONO_TYPE_VALUETYPE:
2062 /* Already set before the call */
2063 break;
2064 default:
2065 stackval_to_data (type, retval, data->res, FALSE);
2066 break;
2070 static stackval *
2071 do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2073 #ifdef ENABLE_NETCORE
2074 if (save_last_error)
2075 mono_marshal_clear_last_error ();
2076 #endif
2078 switch (op) {
2079 case MINT_ICALL_V_V: {
2080 typedef void (*T)(void);
2081 T func = (T)ptr;
2082 func ();
2083 break;
2085 case MINT_ICALL_V_P: {
2086 typedef gpointer (*T)(void);
2087 T func = (T)ptr;
2088 sp++;
2089 sp [-1].data.p = func ();
2090 break;
2092 case MINT_ICALL_P_V: {
2093 typedef void (*T)(gpointer);
2094 T func = (T)ptr;
2095 func (sp [-1].data.p);
2096 sp --;
2097 break;
2099 case MINT_ICALL_P_P: {
2100 typedef gpointer (*T)(gpointer);
2101 T func = (T)ptr;
2102 sp [-1].data.p = func (sp [-1].data.p);
2103 break;
2105 case MINT_ICALL_PP_V: {
2106 typedef void (*T)(gpointer,gpointer);
2107 T func = (T)ptr;
2108 sp -= 2;
2109 func (sp [0].data.p, sp [1].data.p);
2110 break;
2112 case MINT_ICALL_PP_P: {
2113 typedef gpointer (*T)(gpointer,gpointer);
2114 T func = (T)ptr;
2115 --sp;
2116 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
2117 break;
2119 case MINT_ICALL_PPP_V: {
2120 typedef void (*T)(gpointer,gpointer,gpointer);
2121 T func = (T)ptr;
2122 sp -= 3;
2123 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
2124 break;
2126 case MINT_ICALL_PPP_P: {
2127 typedef gpointer (*T)(gpointer,gpointer,gpointer);
2128 T func = (T)ptr;
2129 sp -= 2;
2130 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
2131 break;
2133 case MINT_ICALL_PPPP_V: {
2134 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
2135 T func = (T)ptr;
2136 sp -= 4;
2137 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
2138 break;
2140 case MINT_ICALL_PPPP_P: {
2141 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
2142 T func = (T)ptr;
2143 sp -= 3;
2144 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
2145 break;
2147 case MINT_ICALL_PPPPP_V: {
2148 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2149 T func = (T)ptr;
2150 sp -= 5;
2151 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
2152 break;
2154 case MINT_ICALL_PPPPP_P: {
2155 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2156 T func = (T)ptr;
2157 sp -= 4;
2158 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);
2159 break;
2161 case MINT_ICALL_PPPPPP_V: {
2162 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2163 T func = (T)ptr;
2164 sp -= 6;
2165 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);
2166 break;
2168 case MINT_ICALL_PPPPPP_P: {
2169 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2170 T func = (T)ptr;
2171 sp -= 5;
2172 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);
2173 break;
2175 default:
2176 g_assert_not_reached ();
2179 if (save_last_error)
2180 mono_marshal_set_last_error ();
2182 /* convert the native representation to the stackval representation */
2183 if (sig)
2184 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2186 return sp;
2189 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2190 #ifdef _MSC_VER
2191 #pragma optimize ("", off)
2192 #endif
2193 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2194 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2196 MonoLMFExt ext;
2197 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2199 sp = do_icall (sig, op, sp, ptr, save_last_error);
2201 interp_pop_lmf (&ext);
2203 goto exit_icall; // prevent unused label warning in some configurations
2204 exit_icall:
2205 return sp;
2207 #ifdef _MSC_VER
2208 #pragma optimize ("", on)
2209 #endif
2211 typedef struct {
2212 int pindex;
2213 gpointer jit_wrapper;
2214 gpointer *args;
2215 MonoFtnDesc *ftndesc;
2216 } JitCallCbData;
2218 static void
2219 jit_call_cb (gpointer arg)
2221 JitCallCbData *cb_data = (JitCallCbData*)arg;
2222 gpointer jit_wrapper = cb_data->jit_wrapper;
2223 int pindex = cb_data->pindex;
2224 gpointer *args = cb_data->args;
2225 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2227 switch (pindex) {
2228 case 0: {
2229 typedef void (*T)(gpointer);
2230 T func = (T)jit_wrapper;
2232 func (&ftndesc);
2233 break;
2235 case 1: {
2236 typedef void (*T)(gpointer, gpointer);
2237 T func = (T)jit_wrapper;
2239 func (args [0], &ftndesc);
2240 break;
2242 case 2: {
2243 typedef void (*T)(gpointer, gpointer, gpointer);
2244 T func = (T)jit_wrapper;
2246 func (args [0], args [1], &ftndesc);
2247 break;
2249 case 3: {
2250 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2251 T func = (T)jit_wrapper;
2253 func (args [0], args [1], args [2], &ftndesc);
2254 break;
2256 case 4: {
2257 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2258 T func = (T)jit_wrapper;
2260 func (args [0], args [1], args [2], args [3], &ftndesc);
2261 break;
2263 case 5: {
2264 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2265 T func = (T)jit_wrapper;
2267 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2268 break;
2270 case 6: {
2271 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2272 T func = (T)jit_wrapper;
2274 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2275 break;
2277 case 7: {
2278 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2279 T func = (T)jit_wrapper;
2281 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2282 break;
2284 case 8: {
2285 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2286 T func = (T)jit_wrapper;
2288 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2289 break;
2291 default:
2292 g_assert_not_reached ();
2293 break;
2297 static MONO_NEVER_INLINE void
2298 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2300 MonoMethodSignature *sig;
2301 MonoFtnDesc ftndesc;
2302 guint8 res_buf [256];
2303 MonoType *type;
2304 MonoLMFExt ext;
2306 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2309 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2310 * by ref and return a return value using an explicit return value argument.
2312 if (G_UNLIKELY (!rmethod->jit_wrapper)) {
2313 MonoMethod *method = rmethod->method;
2315 sig = mono_method_signature_internal (method);
2316 g_assert (sig);
2318 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2319 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2321 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2322 mono_error_assert_ok (error);
2324 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2325 return_if_nok (error);
2326 g_assert (addr);
2328 rmethod->jit_addr = addr;
2329 rmethod->jit_sig = sig;
2330 mono_memory_barrier ();
2331 rmethod->jit_wrapper = jit_wrapper;
2333 } else {
2334 sig = rmethod->jit_sig;
2337 ftndesc.addr = rmethod->jit_addr;
2338 ftndesc.arg = NULL;
2340 // FIXME: Optimize this
2342 gpointer args [32];
2343 int pindex = 0;
2344 int stack_index = 0;
2345 if (rmethod->hasthis) {
2346 args [pindex ++] = sp [0].data.p;
2347 stack_index ++;
2349 type = rmethod->rtype;
2350 if (type->type != MONO_TYPE_VOID) {
2351 if (MONO_TYPE_ISSTRUCT (type))
2352 args [pindex ++] = vt_sp;
2353 else
2354 args [pindex ++] = res_buf;
2356 for (int i = 0; i < rmethod->param_count; ++i) {
2357 MonoType *t = rmethod->param_types [i];
2358 stackval *sval = &sp [stack_index + i];
2359 if (sig->params [i]->byref) {
2360 args [pindex ++] = sval->data.p;
2361 } else if (MONO_TYPE_ISSTRUCT (t)) {
2362 args [pindex ++] = sval->data.p;
2363 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2364 args [pindex ++] = &sval->data.p;
2365 } else {
2366 switch (t->type) {
2367 case MONO_TYPE_I1:
2368 case MONO_TYPE_U1:
2369 case MONO_TYPE_I2:
2370 case MONO_TYPE_U2:
2371 case MONO_TYPE_I4:
2372 case MONO_TYPE_U4:
2373 case MONO_TYPE_VALUETYPE:
2374 args [pindex ++] = &sval->data.i;
2375 break;
2376 case MONO_TYPE_PTR:
2377 case MONO_TYPE_FNPTR:
2378 case MONO_TYPE_I:
2379 case MONO_TYPE_U:
2380 case MONO_TYPE_OBJECT:
2381 args [pindex ++] = &sval->data.p;
2382 break;
2383 case MONO_TYPE_I8:
2384 case MONO_TYPE_U8:
2385 args [pindex ++] = &sval->data.l;
2386 break;
2387 case MONO_TYPE_R4:
2388 args [pindex ++] = &sval->data.f_r4;
2389 break;
2390 case MONO_TYPE_R8:
2391 args [pindex ++] = &sval->data.f;
2392 break;
2393 default:
2394 printf ("%s\n", mono_type_full_name (t));
2395 g_assert_not_reached ();
2400 interp_push_lmf (&ext, frame);
2402 JitCallCbData cb_data;
2403 memset (&cb_data, 0, sizeof (cb_data));
2404 cb_data.jit_wrapper = rmethod->jit_wrapper;
2405 cb_data.pindex = pindex;
2406 cb_data.args = args;
2407 cb_data.ftndesc = &ftndesc;
2409 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2410 /* Catch the exception thrown by the native code using a try-catch */
2411 gboolean thrown = FALSE;
2412 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2413 interp_pop_lmf (&ext);
2414 if (thrown) {
2415 MonoObject *obj = mono_llvm_load_exception ();
2416 g_assert (obj);
2417 mono_error_set_exception_instance (error, (MonoException*)obj);
2418 return;
2420 } else {
2421 jit_call_cb (&cb_data);
2422 interp_pop_lmf (&ext);
2425 MonoType *rtype = rmethod->rtype;
2426 switch (rtype->type) {
2427 case MONO_TYPE_VOID:
2428 case MONO_TYPE_OBJECT:
2429 case MONO_TYPE_STRING:
2430 case MONO_TYPE_CLASS:
2431 case MONO_TYPE_ARRAY:
2432 case MONO_TYPE_SZARRAY:
2433 case MONO_TYPE_I:
2434 case MONO_TYPE_U:
2435 case MONO_TYPE_PTR:
2436 sp->data.p = *(gpointer*)res_buf;
2437 break;
2438 case MONO_TYPE_I1:
2439 sp->data.i = *(gint8*)res_buf;
2440 break;
2441 case MONO_TYPE_U1:
2442 sp->data.i = *(guint8*)res_buf;
2443 break;
2444 case MONO_TYPE_I2:
2445 sp->data.i = *(gint16*)res_buf;
2446 break;
2447 case MONO_TYPE_U2:
2448 sp->data.i = *(guint16*)res_buf;
2449 break;
2450 case MONO_TYPE_I4:
2451 sp->data.i = *(gint32*)res_buf;
2452 break;
2453 case MONO_TYPE_U4:
2454 sp->data.i = *(guint32*)res_buf;
2455 break;
2456 case MONO_TYPE_I8:
2457 sp->data.l = *(gint64*)res_buf;
2458 break;
2459 case MONO_TYPE_U8:
2460 sp->data.l = *(guint64*)res_buf;
2461 break;
2462 case MONO_TYPE_R4:
2463 sp->data.f_r4 = *(float*)res_buf;
2464 break;
2465 case MONO_TYPE_R8:
2466 sp->data.f = *(double*)res_buf;
2467 break;
2468 case MONO_TYPE_TYPEDBYREF:
2469 case MONO_TYPE_VALUETYPE:
2470 /* The result was written to vt_sp */
2471 sp->data.p = vt_sp;
2472 break;
2473 case MONO_TYPE_GENERICINST:
2474 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2475 sp->data.p = *(gpointer*)res_buf;
2476 } else {
2477 /* The result was written to vt_sp */
2478 sp->data.p = vt_sp;
2480 break;
2481 default:
2482 g_print ("%s\n", mono_type_full_name (rtype));
2483 g_assert_not_reached ();
2484 break;
2488 static MONO_NEVER_INLINE void
2489 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2491 MonoLMFExt ext;
2492 interp_push_lmf (&ext, frame);
2493 tramp ();
2494 interp_pop_lmf (&ext);
2497 static MONO_NEVER_INLINE MonoException*
2498 do_transform_method (InterpFrame *frame, ThreadContext *context)
2500 MonoLMFExt ext;
2501 /* Don't push lmf if we have no interp data */
2502 gboolean push_lmf = frame->parent != NULL;
2503 ERROR_DECL (error);
2505 /* Use the parent frame as the current frame is not complete yet */
2506 if (push_lmf)
2507 interp_push_lmf (&ext, frame->parent);
2509 mono_interp_transform_method (frame->imethod, context, error);
2511 if (push_lmf)
2512 interp_pop_lmf (&ext);
2514 return mono_error_convert_to_exception (error);
2517 static MONO_NEVER_INLINE guchar*
2518 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start)
2520 stackval *first_arg = sp - csig->param_count;
2521 guchar *vt_sp = vt_sp_start;
2524 * We need to have the varargs linearly on the stack so the ArgIterator
2525 * can iterate over them. We pass the signature first and then copy them
2526 * one by one on the vtstack. At the end we pass the original vt_stack
2527 * so the callee (MINT_ARGLIST) can find the varargs space.
2529 *(gpointer*)vt_sp = csig;
2530 vt_sp += sizeof (gpointer);
2532 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2533 int align, arg_size;
2534 arg_size = mono_type_stack_size (csig->params [i], &align);
2535 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2537 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2538 vt_sp += arg_size;
2541 vt_sp += sizeof (gpointer);
2542 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2544 ((gpointer*)vt_sp) [-1] = vt_sp_start;
2546 return vt_sp;
2550 * These functions are the entry points into the interpreter from compiled code.
2551 * They are called by the interp_in wrappers. They have the following signature:
2552 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2553 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2554 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2555 * more wrappers then these functions.
2556 * this/static * ret/void * 16 arguments -> 64 functions.
2559 #define MAX_INTERP_ENTRY_ARGS 8
2561 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2562 InterpEntryData data; \
2563 (data).rmethod = (_method); \
2564 (data).res = (_res); \
2565 (data).this_arg = (_this_arg); \
2566 (data).many_args = NULL;
2568 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2569 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2570 interp_entry (&data); \
2572 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2573 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2574 (data).args [0] = arg1; \
2575 interp_entry (&data); \
2577 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2578 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2579 (data).args [0] = arg1; \
2580 (data).args [1] = arg2; \
2581 interp_entry (&data); \
2583 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2584 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2585 (data).args [0] = arg1; \
2586 (data).args [1] = arg2; \
2587 (data).args [2] = arg3; \
2588 interp_entry (&data); \
2590 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2591 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2592 (data).args [0] = arg1; \
2593 (data).args [1] = arg2; \
2594 (data).args [2] = arg3; \
2595 (data).args [3] = arg4; \
2596 interp_entry (&data); \
2598 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2599 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2600 (data).args [0] = arg1; \
2601 (data).args [1] = arg2; \
2602 (data).args [2] = arg3; \
2603 (data).args [3] = arg4; \
2604 (data).args [4] = arg5; \
2605 interp_entry (&data); \
2607 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2608 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2609 (data).args [0] = arg1; \
2610 (data).args [1] = arg2; \
2611 (data).args [2] = arg3; \
2612 (data).args [3] = arg4; \
2613 (data).args [4] = arg5; \
2614 (data).args [5] = arg6; \
2615 interp_entry (&data); \
2617 #define INTERP_ENTRY7(_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 interp_entry (&data); \
2628 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2629 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2630 (data).args [0] = arg1; \
2631 (data).args [1] = arg2; \
2632 (data).args [2] = arg3; \
2633 (data).args [3] = arg4; \
2634 (data).args [4] = arg5; \
2635 (data).args [5] = arg6; \
2636 (data).args [6] = arg7; \
2637 (data).args [7] = arg8; \
2638 interp_entry (&data); \
2641 #define ARGLIST0 InterpMethod *rmethod
2642 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2643 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2644 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2645 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2646 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2647 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2648 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2649 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2651 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2652 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2653 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2654 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2655 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2656 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2657 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2658 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2659 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2660 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2661 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2662 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2663 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2664 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2665 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2666 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2667 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2668 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2669 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2670 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2671 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2672 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2673 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2674 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2675 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2676 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2677 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2678 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2679 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2680 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2681 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2682 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2683 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2684 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2685 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2686 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2688 #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
2690 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2691 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2692 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2693 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2695 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2696 static void
2697 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2699 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2700 data.many_args = args;
2701 interp_entry (&data);
2704 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2706 // inline so we can alloc on stack
2707 #define alloc_storage_for_stackval(s, t, p) do { \
2708 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2709 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2710 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2711 if (p) \
2712 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2713 else \
2714 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2716 } while (0)
2718 static void
2719 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2721 InterpFrame *frame;
2722 ThreadContext *context;
2723 stackval result;
2724 stackval *args;
2725 MonoMethod *method;
2726 MonoMethodSignature *sig;
2727 CallContext *ccontext = (CallContext*) ccontext_untyped;
2728 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2729 gpointer orig_domain = NULL, attach_cookie;
2730 int i;
2732 if (rmethod->needs_thread_attach)
2733 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2735 context = get_context ();
2737 method = rmethod->method;
2738 sig = mono_method_signature_internal (method);
2739 if (method->string_ctor) {
2740 MonoMethodSignature *newsig = g_alloca (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
2741 memcpy (newsig, sig, mono_metadata_signature_size (sig));
2742 newsig->ret = m_class_get_byval_arg (mono_defaults.string_class);
2743 sig = newsig;
2746 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2748 frame = alloc_frame (context, &result, NULL, rmethod, args, &result);
2750 /* Allocate storage for value types */
2751 for (i = 0; i < sig->param_count; i++) {
2752 MonoType *type = sig->params [i];
2753 alloc_storage_for_stackval (&frame->stack_args [i + sig->hasthis], type, sig->pinvoke);
2756 if (sig->ret->type != MONO_TYPE_VOID)
2757 alloc_storage_for_stackval (frame->retval, sig->ret, sig->pinvoke);
2759 /* Copy the args saved in the trampoline to the frame stack */
2760 mono_arch_get_native_call_context_args (ccontext, frame, sig);
2762 ERROR_DECL (error);
2763 interp_exec_method (frame, context, error);
2765 g_assert (!context->has_resume_state);
2767 if (rmethod->needs_thread_attach)
2768 mono_threads_detach_coop (orig_domain, &attach_cookie);
2770 /* Write back the return value */
2771 /* 'frame' is still valid */
2772 mono_arch_set_native_call_context_ret (ccontext, frame, sig);
2775 #else
2777 static void
2778 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2780 g_assert_not_reached ();
2783 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2785 static InterpMethod*
2786 lookup_method_pointer (gpointer addr)
2788 MonoDomain *domain = mono_domain_get ();
2789 MonoJitDomainInfo *info = domain_jit_info (domain);
2790 InterpMethod *res = NULL;
2792 mono_domain_lock (domain);
2793 if (info->interp_method_pointer_hash)
2794 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2795 mono_domain_unlock (domain);
2797 return res;
2800 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2801 static void
2802 interp_no_native_to_managed (void)
2804 g_error ("interpreter: native-to-managed transition not available on this platform");
2806 #endif
2808 static void
2809 no_llvmonly_interp_method_pointer (void)
2811 g_assert_not_reached ();
2815 * interp_create_method_pointer_llvmonly:
2817 * Return an ftndesc for entering the interpreter and executing METHOD.
2819 static MonoFtnDesc*
2820 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2822 MonoDomain *domain = mono_domain_get ();
2823 gpointer addr, entry_func, entry_wrapper;
2824 MonoMethodSignature *sig;
2825 MonoMethod *wrapper;
2826 MonoJitDomainInfo *info;
2827 InterpMethod *imethod;
2829 imethod = mono_interp_get_imethod (domain, method, error);
2830 return_val_if_nok (error, NULL);
2832 if (unbox) {
2833 if (imethod->llvmonly_unbox_entry)
2834 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2835 } else {
2836 if (imethod->jit_entry)
2837 return (MonoFtnDesc*)imethod->jit_entry;
2840 sig = mono_method_signature_internal (method);
2843 * The entry functions need access to the method to call, so we have
2844 * to use a ftndesc. The caller uses a normal signature, while the
2845 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2846 * a gsharedvt_in_sig wrapper.
2848 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2850 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2851 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2852 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2853 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2855 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2856 g_assert_not_reached ();
2857 //entry_func = (gpointer)interp_entry_general;
2858 } else if (sig->hasthis) {
2859 if (sig->ret->type == MONO_TYPE_VOID)
2860 entry_func = entry_funcs_instance [sig->param_count];
2861 else
2862 entry_func = entry_funcs_instance_ret [sig->param_count];
2863 } else {
2864 if (sig->ret->type == MONO_TYPE_VOID)
2865 entry_func = entry_funcs_static [sig->param_count];
2866 else
2867 entry_func = entry_funcs_static_ret [sig->param_count];
2869 g_assert (entry_func);
2871 /* Encode unbox in the lower bit of imethod */
2872 gpointer entry_arg = imethod;
2873 if (unbox)
2874 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2875 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2877 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2879 info = domain_jit_info (domain);
2880 mono_domain_lock (domain);
2881 if (!info->interp_method_pointer_hash)
2882 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2883 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2884 mono_domain_unlock (domain);
2886 mono_memory_barrier ();
2887 if (unbox)
2888 imethod->llvmonly_unbox_entry = addr;
2889 else
2890 imethod->jit_entry = addr;
2892 return (MonoFtnDesc*)addr;
2896 * interp_create_method_pointer:
2898 * Return a function pointer which can be used to call METHOD using the
2899 * interpreter. Return NULL for methods which are not supported.
2901 static gpointer
2902 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2904 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2905 if (mono_llvm_only)
2906 return (gpointer)no_llvmonly_interp_method_pointer;
2907 return (gpointer)interp_no_native_to_managed;
2908 #else
2909 gpointer addr, entry_func, entry_wrapper = NULL;
2910 MonoDomain *domain = mono_domain_get ();
2911 MonoJitDomainInfo *info;
2912 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2914 if (mono_llvm_only)
2915 return (gpointer)no_llvmonly_interp_method_pointer;
2917 if (imethod->jit_entry)
2918 return imethod->jit_entry;
2920 if (compile && !imethod->transformed) {
2921 /* Return any errors from method compilation */
2922 mono_interp_transform_method (imethod, get_context (), error);
2923 return_val_if_nok (error, NULL);
2926 MonoMethodSignature *sig = mono_method_signature_internal (method);
2927 if (method->string_ctor) {
2928 MonoMethodSignature *newsig = g_alloca (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
2929 memcpy (newsig, sig, mono_metadata_signature_size (sig));
2930 newsig->ret = m_class_get_byval_arg (mono_defaults.string_class);
2931 sig = newsig;
2934 if (mono_llvm_only)
2935 /* The caller should call interp_create_method_pointer_llvmonly */
2936 g_assert_not_reached ();
2938 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2939 return imethod;
2941 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2943 * Interp in wrappers get the argument in the rgctx register. If
2944 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2945 * on that arch the rgctx register is not scratch, so we use a
2946 * separate temp register. We should update the wrappers for this
2947 * if we really care about those architectures (arm).
2949 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2951 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2952 #endif
2953 if (entry_wrapper) {
2954 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2955 entry_func = (gpointer)interp_entry_general;
2956 } else if (sig->hasthis) {
2957 if (sig->ret->type == MONO_TYPE_VOID)
2958 entry_func = entry_funcs_instance [sig->param_count];
2959 else
2960 entry_func = entry_funcs_instance_ret [sig->param_count];
2961 } else {
2962 if (sig->ret->type == MONO_TYPE_VOID)
2963 entry_func = entry_funcs_static [sig->param_count];
2964 else
2965 entry_func = entry_funcs_static_ret [sig->param_count];
2967 } else {
2968 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2969 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2970 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2971 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2972 #else
2973 mono_error_cleanup (error);
2974 error_init_reuse (error);
2975 if (!mono_native_to_interp_trampoline) {
2976 if (mono_aot_only) {
2977 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2978 } else {
2979 MonoTrampInfo *info;
2980 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2981 mono_tramp_info_register (info, NULL);
2984 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2985 /* We need the lmf wrapper only when being called from mixed mode */
2986 if (sig->pinvoke)
2987 entry_func = (gpointer)interp_entry_from_trampoline;
2988 else {
2989 static gpointer cached_func = NULL;
2990 if (!cached_func) {
2991 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);
2992 mono_memory_barrier ();
2994 entry_func = cached_func;
2996 #endif
2999 g_assert (entry_func);
3000 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
3001 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
3002 ftndesc->addr = entry_func;
3003 ftndesc->arg = imethod;
3004 mono_error_assert_ok (error);
3007 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
3008 * rgctx register using a trampoline.
3011 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
3013 info = domain_jit_info (domain);
3014 mono_domain_lock (domain);
3015 if (!info->interp_method_pointer_hash)
3016 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
3017 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
3018 mono_domain_unlock (domain);
3020 mono_memory_barrier ();
3021 imethod->jit_entry = addr;
3023 return addr;
3024 #endif
3027 static void
3028 interp_free_method (MonoDomain *domain, MonoMethod *method)
3030 MonoJitDomainInfo *info = domain_jit_info (domain);
3032 mono_domain_jit_code_hash_lock (domain);
3033 /* InterpMethod is allocated in the domain mempool. We might haven't
3034 * allocated an InterpMethod for this instance yet */
3035 mono_internal_hash_table_remove (&info->interp_code_hash, method);
3036 mono_domain_jit_code_hash_unlock (domain);
3039 #if COUNT_OPS
3040 static long opcode_counts[MINT_LASTOP];
3042 #define COUNT_OP(op) opcode_counts[op]++
3043 #else
3044 #define COUNT_OP(op)
3045 #endif
3047 #if DEBUG_INTERP
3048 #define DUMP_INSTR() \
3049 if (tracing > 1) { \
3050 char *ins; \
3051 if (sp > frame->stack) { \
3052 ins = dump_stack (frame->stack, sp); \
3053 } else { \
3054 ins = g_strdup (""); \
3056 sp->data.l = 0; \
3057 output_indent (); \
3058 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
3059 char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
3060 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
3061 g_free (mn); \
3062 g_free (ins); \
3063 g_free (disasm); \
3065 #else
3066 #define DUMP_INSTR()
3067 #endif
3069 #define INIT_VTABLE(vtable) do { \
3070 if (G_UNLIKELY (!(vtable)->initialized)) { \
3071 mono_runtime_class_init_full ((vtable), error); \
3072 if (!is_ok (error)) \
3073 goto throw_error_label; \
3075 } while (0);
3077 static MONO_NEVER_INLINE MonoObject*
3078 mono_interp_new (MonoDomain* domain, MonoClass* klass)
3080 ERROR_DECL (error);
3081 MonoObject* const object = mono_object_new_checked (domain, klass, error);
3082 mono_error_cleanup (error); // FIXME: do not swallow the error
3083 return object;
3086 static
3087 #ifndef DISABLE_REMOTING
3088 MONO_NEVER_INLINE // To reduce stack.
3089 #endif
3090 void
3091 mono_interp_load_remote_field (
3092 InterpMethod* imethod,
3093 MonoObject* o,
3094 const guint16* ip,
3095 stackval* sp)
3097 g_assert (o); // Caller checks and throws exception properly.
3099 void* addr;
3100 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
3102 #ifndef DISABLE_REMOTING
3103 gpointer tmp;
3104 if (mono_object_is_transparent_proxy (o)) {
3105 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3106 ERROR_DECL (error);
3107 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3108 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3109 } else
3110 #endif
3111 addr = (char*)o + field->offset;
3112 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3115 static
3116 #ifndef DISABLE_REMOTING
3117 MONO_NEVER_INLINE // To reduce stack.
3118 #endif
3119 guchar* // Return new vt_sp instead of take-address.
3120 mono_interp_load_remote_field_vt (
3121 InterpMethod* imethod,
3122 MonoObject* o,
3123 const guint16* ip,
3124 stackval* sp,
3125 guchar* vt_sp)
3127 g_assert (o); // Caller checks and throws exception properly.
3129 void* addr;
3130 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
3131 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
3132 int const i32 = mono_class_value_size (klass, NULL);
3134 #ifndef DISABLE_REMOTING
3135 gpointer tmp;
3136 if (mono_object_is_transparent_proxy (o)) {
3137 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3138 ERROR_DECL (error);
3139 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3140 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3141 } else
3142 #endif
3143 addr = (char*)o + field->offset;
3144 sp [-1].data.p = vt_sp;
3145 memcpy (vt_sp, addr, i32);
3146 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3149 static MONO_NEVER_INLINE gboolean
3150 mono_interp_isinst (MonoObject* object, MonoClass* klass)
3152 ERROR_DECL (error);
3153 gboolean isinst;
3154 MonoClass *obj_class = mono_object_class (object);
3155 // mono_class_is_assignable_from_checked can't handle remoting casts
3156 if (mono_class_is_transparent_proxy (obj_class))
3157 isinst = mono_object_isinst_checked (object, klass, error) != NULL;
3158 else
3159 mono_class_is_assignable_from_checked (klass, obj_class, &isinst, error);
3160 mono_error_cleanup (error); // FIXME: do not swallow the error
3161 return isinst;
3164 // This function is outlined to help save stack in its caller, on the premise
3165 // that it is relatively rarely called. This also lets it use alloca.
3166 static MONO_NEVER_INLINE void
3167 mono_interp_calli_nat_dynamic_pinvoke (
3168 // Parameters are sorted by name.
3169 InterpFrame* child_frame,
3170 guchar* code,
3171 ThreadContext* context,
3172 MonoMethodSignature* csignature,
3173 MonoError* error)
3175 // Recompute to limit parameters, which can also contribute to caller stack.
3176 InterpMethod* const imethod = child_frame->parent->imethod;
3178 g_assert (imethod->method->dynamic && csignature->pinvoke);
3180 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3181 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
3182 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
3184 MonoMethodPInvoke iinfo;
3185 memset (&iinfo, 0, sizeof (iinfo));
3187 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
3189 for (int i = csignature->param_count; i >= 0; i--)
3190 if (mspecs [i])
3191 mono_metadata_free_marshal_spec (mspecs [i]);
3194 ERROR_DECL (error);
3195 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
3196 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3199 interp_exec_method (child_frame, context, error);
3202 // Leave is split into pieces in order to consume less stack,
3203 // but not have to change how exception handling macros access labels and locals.
3204 static MONO_NEVER_INLINE MonoException*
3205 mono_interp_leave (InterpFrame* child_frame)
3207 stackval tmp_sp;
3209 * We need for mono_thread_get_undeniable_exception to be able to unwind
3210 * to check the abort threshold. For this to work we use child_frame as a
3211 * dummy frame that is stored in the lmf and serves as the transition frame
3213 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3215 return (MonoException*)tmp_sp.data.p;
3218 static MONO_NEVER_INLINE MonoException*
3219 mono_interp_newobj (
3220 // Parameters are sorted by name and parameter list is minimized
3221 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3222 // use no stack in caller).
3223 InterpFrame* child_frame,
3224 ThreadContext* context,
3225 MonoError* error,
3226 guchar* vt_sp)
3228 InterpFrame* const frame = child_frame->parent;
3229 InterpMethod* const imethod = frame->imethod;
3230 stackval* const sp = child_frame->stack_args;
3232 MonoObject* o = NULL; // See the comment about GC safety.
3233 stackval valuetype_this;
3234 stackval retval;
3236 MonoClass * const newobj_class = child_frame->imethod->method->klass;
3237 /*if (profiling_classes) {
3238 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3239 count++;
3240 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3244 * First arg is the object.
3246 if (m_class_is_valuetype (newobj_class)) {
3247 MonoType *t = m_class_get_byval_arg (newobj_class);
3248 memset (&valuetype_this, 0, sizeof (stackval));
3249 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3250 sp->data.p = vt_sp;
3251 valuetype_this.data.p = vt_sp;
3252 } else {
3253 sp->data.p = &valuetype_this;
3255 } else {
3256 if (newobj_class != mono_defaults.string_class) {
3257 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
3258 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
3259 MonoException* const exc = mono_error_convert_to_exception (error);
3260 g_assert (exc);
3261 return exc;
3263 ERROR_DECL (error);
3264 OBJREF (o) = mono_object_new_checked (imethod->domain, newobj_class, error);
3265 mono_error_cleanup (error); // FIXME: do not swallow the error
3266 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
3267 sp->data.o = o;
3268 #ifndef DISABLE_REMOTING
3269 if (mono_object_is_transparent_proxy (o)) {
3270 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
3271 mono_error_assert_ok (error);
3272 child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
3273 mono_error_assert_ok (error);
3275 #endif
3276 } else {
3277 sp->data.p = NULL;
3278 child_frame->retval = &retval;
3282 interp_exec_method (child_frame, context, error);
3284 CHECK_RESUME_STATE (context);
3287 * a constructor returns void, but we need to return the object we created
3289 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3290 *sp = valuetype_this;
3291 } else if (newobj_class == mono_defaults.string_class) {
3292 *sp = retval;
3293 } else {
3294 sp->data.o = o;
3296 resume:
3297 return NULL;
3300 static MONO_NEVER_INLINE void
3301 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3303 guint64 a_val = 0, b_val = 0;
3305 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3306 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3307 sp->data.i = (a_val & b_val) == b_val;
3310 static MONO_NEVER_INLINE int
3311 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3313 InterpMethod* const imethod = frame->imethod;
3314 MonoClass* const c = (MonoClass*)imethod->data_items [ip [1]];
3316 int const size = mono_class_value_size (c, NULL);
3318 guint16 offset = ip [2];
3319 guint16 pop_vt_sp = !ip [3];
3321 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3322 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3324 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3327 static MONO_NEVER_INLINE int
3328 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp)
3330 InterpMethod* const imethod = frame->imethod;
3332 MonoObject* o; // See the comment about GC safety.
3333 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [ip [1]];
3334 MonoClass* const c = vtable->klass;
3336 int const size = mono_class_value_size (c, NULL);
3338 guint16 offset = ip [2];
3339 guint16 pop_vt_sp = !ip [3];
3341 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3342 mono_value_copy_internal (mono_object_get_data (o), sp [-1 - offset].data.p, c);
3344 sp [-1 - offset].data.p = o;
3345 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3348 static MONO_NEVER_INLINE void
3349 mono_interp_box (InterpFrame* frame, const guint16* ip, stackval* sp)
3351 MonoObject *o; // See the comment about GC safety.
3352 MonoVTable * const vtable = (MonoVTable*)frame->imethod->data_items [ip [1]];
3354 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3356 guint16 const offset = ip [2];
3358 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (o), FALSE);
3360 sp [-1 - offset].data.p = o;
3363 static MONO_NEVER_INLINE int
3364 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3366 InterpMethod* const imethod = frame->imethod;
3367 MonoClassField *field;
3369 MonoObject* const o = sp [-2].data.o;
3371 field = (MonoClassField*)imethod->data_items[ip [1]];
3372 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3373 int const i32 = mono_class_value_size (klass, NULL);
3375 #ifndef DISABLE_REMOTING
3376 if (mono_object_is_transparent_proxy (o)) {
3377 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3378 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3379 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3380 } else
3381 #endif
3382 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3384 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3387 // varargs in wasm consumes extra linear stack per call-site.
3388 // These g_warning/g_error wrappers fix that. It is not the
3389 // small wasm stack, but conserving it is still desirable.
3390 static void
3391 g_warning_d (const char *format, int d)
3393 g_warning (format, d);
3396 static void
3397 g_warning_ds (const char *format, int d, const char *s)
3399 g_warning (format, d, s);
3402 #if !USE_COMPUTED_GOTO
3403 static void
3404 g_error_xsx (const char *format, int x1, const char *s, int x2)
3406 g_error (format, x1, s, x2);
3408 #endif
3410 static MONO_ALWAYS_INLINE gboolean
3411 method_entry (ThreadContext *context, InterpFrame *frame,
3412 #if DEBUG_INTERP
3413 int *out_tracing,
3414 #endif
3415 MonoException **out_ex, FrameClauseArgs *clause_args)
3417 gboolean slow = FALSE;
3419 #if DEBUG_INTERP
3420 debug_enter (frame, out_tracing);
3421 #endif
3423 *out_ex = NULL;
3424 if (!G_UNLIKELY (frame->imethod->transformed)) {
3425 slow = TRUE;
3426 #if DEBUG_INTERP
3427 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
3428 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3429 g_free (mn);
3430 #endif
3431 frame->ip = NULL;
3432 MonoException *ex = do_transform_method (frame, context);
3433 if (ex) {
3434 *out_ex = ex;
3435 return slow;
3439 if (!clause_args || clause_args->base_frame)
3440 alloc_stack_data (context, frame, frame->imethod->alloca_size);
3442 return slow;
3445 /* Save the state of the interpeter main loop into FRAME */
3446 #define SAVE_INTERP_STATE(frame) do { \
3447 frame->state.ip = ip; \
3448 frame->state.sp = sp; \
3449 frame->state.vt_sp = vt_sp; \
3450 frame->state.is_void = is_void; \
3451 frame->state.finally_ips = finally_ips; \
3452 frame->state.clause_args = clause_args; \
3453 } while (0)
3455 /* Load and clear state from FRAME */
3456 #define LOAD_INTERP_STATE(frame) do { \
3457 ip = frame->state.ip; \
3458 sp = frame->state.sp; \
3459 is_void = frame->state.is_void; \
3460 vt_sp = frame->state.vt_sp; \
3461 finally_ips = frame->state.finally_ips; \
3462 clause_args = frame->state.clause_args; \
3463 locals = (unsigned char *)frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size; \
3464 frame->state.ip = NULL; \
3465 } while (0)
3467 /* Initialize interpreter state for executing FRAME */
3468 #define INIT_INTERP_STATE(frame, _clause_args) do { \
3469 ip = _clause_args ? (_clause_args)->start_with_ip : (frame)->imethod->code; \
3470 sp = (frame)->stack; \
3471 vt_sp = (unsigned char *) sp + (frame)->imethod->stack_size; \
3472 locals = (unsigned char *) vt_sp + (frame)->imethod->vt_stack_size; \
3473 finally_ips = NULL; \
3474 } while (0)
3477 * If CLAUSE_ARGS is non-null, start executing from it.
3478 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3479 * to return error information.
3480 * FRAME is only valid until the next call to alloc_frame ().
3482 static MONO_NEVER_INLINE void
3483 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3485 InterpMethod *cmethod;
3486 MonoException *ex;
3487 gboolean is_void;
3488 stackval *retval;
3490 /* Interpreter main loop state (InterpState) */
3491 const guint16 *ip = NULL;
3492 stackval *sp;
3493 unsigned char *vt_sp;
3494 unsigned char *locals = NULL;
3495 GSList *finally_ips = NULL;
3497 InterpFrame *child_frame;
3498 #if DEBUG_INTERP
3499 int tracing = global_tracing;
3500 unsigned char *vtalloc;
3501 #endif
3502 #if USE_COMPUTED_GOTO
3503 static void * const in_labels[] = {
3504 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3505 #include "mintops.def"
3507 #endif
3509 if (method_entry (context, frame,
3510 #if DEBUG_INTERP
3511 &tracing,
3512 #endif
3513 &ex, clause_args)) {
3514 if (ex)
3515 THROW_EX (ex, NULL);
3516 EXCEPTION_CHECKPOINT;
3519 if (clause_args && clause_args->base_frame)
3520 memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size);
3522 INIT_INTERP_STATE (frame, clause_args);
3524 #if DEBUG_INTERP
3525 vtalloc = vt_sp;
3526 #endif
3528 if (clause_args && clause_args->filter_exception) {
3529 sp->data.p = clause_args->filter_exception;
3530 sp++;
3533 #ifdef ENABLE_EXPERIMENT_TIERED
3534 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0);
3535 #endif
3536 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3538 #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND)
3539 mono_threads_safepoint ();
3540 #endif
3542 * using while (ip < end) may result in a 15% performance drop,
3543 * but it may be useful for debug
3545 while (1) {
3546 MintOpcode opcode;
3547 main_loop:
3548 /* g_assert (sp >= frame->stack); */
3549 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3550 DUMP_INSTR();
3551 MINT_IN_SWITCH (*ip) {
3552 MINT_IN_CASE(MINT_INITLOCALS)
3553 memset (locals, 0, frame->imethod->locals_size);
3554 ++ip;
3555 MINT_IN_BREAK;
3556 MINT_IN_CASE(MINT_NOP)
3557 MINT_IN_CASE(MINT_NIY)
3558 g_assert_not_reached ();
3559 MINT_IN_BREAK;
3560 MINT_IN_CASE(MINT_BREAK)
3561 ++ip;
3562 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3563 MINT_IN_BREAK;
3564 MINT_IN_CASE(MINT_BREAKPOINT)
3565 ++ip;
3566 mono_break ();
3567 MINT_IN_BREAK;
3568 MINT_IN_CASE(MINT_LDNULL)
3569 sp->data.p = NULL;
3570 ++ip;
3571 ++sp;
3572 MINT_IN_BREAK;
3573 MINT_IN_CASE(MINT_ARGLIST)
3574 sp->data.p = vt_sp;
3575 *(gpointer*)sp->data.p = ((gpointer*)frame->retval->data.p) [-1];
3576 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3577 ++ip;
3578 ++sp;
3579 MINT_IN_BREAK;
3580 MINT_IN_CASE(MINT_VTRESULT) {
3581 int ret_size = ip [1];
3582 unsigned char *ret_vt_sp = vt_sp;
3583 vt_sp -= READ32(ip + 2);
3584 if (ret_size > 0) {
3585 memmove (vt_sp, ret_vt_sp, ret_size);
3586 sp [-1].data.p = vt_sp;
3587 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3589 ip += 4;
3590 MINT_IN_BREAK;
3592 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3593 MINT_IN_CASE(MINT_LDC_I4_M1)
3594 LDC(-1);
3595 MINT_IN_BREAK;
3596 MINT_IN_CASE(MINT_LDC_I4_0)
3597 LDC(0);
3598 MINT_IN_BREAK;
3599 MINT_IN_CASE(MINT_LDC_I4_1)
3600 LDC(1);
3601 MINT_IN_BREAK;
3602 MINT_IN_CASE(MINT_LDC_I4_2)
3603 LDC(2);
3604 MINT_IN_BREAK;
3605 MINT_IN_CASE(MINT_LDC_I4_3)
3606 LDC(3);
3607 MINT_IN_BREAK;
3608 MINT_IN_CASE(MINT_LDC_I4_4)
3609 LDC(4);
3610 MINT_IN_BREAK;
3611 MINT_IN_CASE(MINT_LDC_I4_5)
3612 LDC(5);
3613 MINT_IN_BREAK;
3614 MINT_IN_CASE(MINT_LDC_I4_6)
3615 LDC(6);
3616 MINT_IN_BREAK;
3617 MINT_IN_CASE(MINT_LDC_I4_7)
3618 LDC(7);
3619 MINT_IN_BREAK;
3620 MINT_IN_CASE(MINT_LDC_I4_8)
3621 LDC(8);
3622 MINT_IN_BREAK;
3623 MINT_IN_CASE(MINT_LDC_I4_S)
3624 sp->data.i = (short)ip [1];
3625 ip += 2;
3626 ++sp;
3627 MINT_IN_BREAK;
3628 MINT_IN_CASE(MINT_LDC_I4)
3629 ++ip;
3630 sp->data.i = READ32 (ip);
3631 ip += 2;
3632 ++sp;
3633 MINT_IN_BREAK;
3634 MINT_IN_CASE(MINT_LDC_I8)
3635 ++ip;
3636 sp->data.l = READ64 (ip);
3637 ip += 4;
3638 ++sp;
3639 MINT_IN_BREAK;
3640 MINT_IN_CASE(MINT_LDC_I8_S)
3641 sp->data.l = (short)ip [1];
3642 ip += 2;
3643 ++sp;
3644 MINT_IN_BREAK;
3645 MINT_IN_CASE(MINT_LDC_R4) {
3646 guint32 val;
3647 ++ip;
3648 val = READ32(ip);
3649 sp->data.f_r4 = * (float *)&val;
3650 ip += 2;
3651 ++sp;
3652 MINT_IN_BREAK;
3654 MINT_IN_CASE(MINT_LDC_R8)
3655 sp->data.l = READ64 (ip + 1); /* note union usage */
3656 ip += 5;
3657 ++sp;
3658 MINT_IN_BREAK;
3659 MINT_IN_CASE(MINT_DUP)
3660 sp [0] = sp[-1];
3661 ++sp;
3662 ++ip;
3663 MINT_IN_BREAK;
3664 MINT_IN_CASE(MINT_DUP_VT) {
3665 int const i32 = READ32 (ip + 1);
3666 sp->data.p = vt_sp;
3667 memcpy(sp->data.p, sp [-1].data.p, i32);
3668 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3669 ++sp;
3670 ip += 3;
3671 MINT_IN_BREAK;
3673 MINT_IN_CASE(MINT_POP) {
3674 sp--;
3675 ip++;
3676 MINT_IN_BREAK;
3678 MINT_IN_CASE(MINT_POP1) {
3679 sp [-2] = sp [-1];
3680 sp--;
3681 ip++;
3682 MINT_IN_BREAK;
3684 MINT_IN_CASE(MINT_JMP) {
3685 g_assert (sp == frame->stack);
3686 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [ip [1]];
3688 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3689 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3691 if (!new_method->transformed) {
3692 error_init_reuse (error);
3694 frame->ip = ip;
3695 mono_interp_transform_method (new_method, context, error);
3696 MonoException *ex = mono_error_convert_to_exception (error);
3697 if (ex)
3698 THROW_EX (ex, ip);
3700 ip += 2;
3701 const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
3702 frame->imethod = new_method;
3704 * We allocate the stack frame from scratch and store the arguments in the
3705 * locals again since it's possible for the caller stack frame to be smaller
3706 * than the callee stack frame (at the interp level)
3708 if (realloc_frame) {
3709 //frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3710 alloc_stack_data (context, frame, frame->imethod->alloca_size);
3711 memset (frame->stack, 0, frame->imethod->alloca_size);
3712 sp = frame->stack;
3714 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3715 #if DEBUG_INTERP
3716 vtalloc = vt_sp;
3717 #endif
3718 locals = vt_sp + frame->imethod->vt_stack_size;
3719 ip = frame->imethod->code;
3720 MINT_IN_BREAK;
3722 MINT_IN_CASE(MINT_CALLI) {
3723 MonoMethodSignature *csignature;
3725 frame->ip = ip;
3727 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3728 ip += 2;
3729 --sp;
3731 cmethod = (InterpMethod*)sp->data.p;
3732 if (cmethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3733 cmethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (cmethod->method, FALSE, FALSE), error);
3734 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3737 is_void = csignature->ret->type == MONO_TYPE_VOID;
3738 retval = is_void ? NULL : sp;
3740 sp->data.p = vt_sp;
3741 /* decrement by the actual number of args */
3742 sp -= csignature->param_count;
3743 if (csignature->hasthis)
3744 --sp;
3746 if (csignature->hasthis) {
3747 MonoObject *this_arg = (MonoObject*)sp->data.p;
3749 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3750 gpointer unboxed = mono_object_unbox_internal (this_arg);
3751 sp [0].data.p = unboxed;
3755 goto call;
3757 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3758 gpointer target_ip = sp [-1].data.p;
3759 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3760 int opcode = ip [2];
3761 gboolean save_last_error = ip [3];
3763 sp--;
3764 frame->ip = ip;
3766 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3767 EXCEPTION_CHECKPOINT_GC_UNSAFE;
3768 CHECK_RESUME_STATE (context);
3769 ip += 4;
3770 MINT_IN_BREAK;
3772 MINT_IN_CASE(MINT_CALLI_NAT) {
3773 MonoMethodSignature* csignature;
3775 frame->ip = ip;
3777 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3779 ip += 3;
3780 --sp;
3781 guchar* const code = (guchar*)sp->data.p;
3782 retval = sp;
3783 child_frame = alloc_frame (context, &retval, frame, NULL, NULL, retval);
3785 sp->data.p = vt_sp;
3786 /* decrement by the actual number of args */
3787 sp -= csignature->param_count;
3788 if (csignature->hasthis)
3789 --sp;
3790 child_frame->stack_args = sp;
3792 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3793 mono_interp_calli_nat_dynamic_pinvoke (child_frame, code, context, csignature, error);
3794 } else {
3795 const gboolean save_last_error = ip [-3 + 2];
3796 ves_pinvoke_method (child_frame, csignature, (MonoFuncV) code, context, save_last_error);
3798 CHECK_RESUME_STATE (context);
3800 if (csignature->ret->type != MONO_TYPE_VOID) {
3801 *sp = *retval;
3802 sp++;
3804 MINT_IN_BREAK;
3806 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3807 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3808 MonoObject *this_arg;
3809 is_void = *ip == MINT_VCALLVIRT_FAST;
3810 int slot;
3812 frame->ip = ip;
3814 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3815 slot = (gint16)ip [2];
3816 ip += 3;
3817 sp->data.p = vt_sp;
3819 retval = is_void ? NULL : sp;
3821 /* decrement by the actual number of args */
3822 sp -= cmethod->param_count + cmethod->hasthis;
3824 this_arg = (MonoObject*)sp->data.p;
3826 cmethod = get_virtual_method_fast (cmethod, this_arg->vtable, slot);
3827 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) {
3828 /* unbox */
3829 gpointer unboxed = mono_object_unbox_internal (this_arg);
3830 sp [0].data.p = unboxed;
3833 InterpMethodCodeType code_type = cmethod->code_type;
3835 g_assert (code_type == IMETHOD_CODE_UNKNOWN ||
3836 code_type == IMETHOD_CODE_INTERP ||
3837 code_type == IMETHOD_CODE_COMPILED);
3839 if (G_UNLIKELY (code_type == IMETHOD_CODE_UNKNOWN)) {
3840 MonoMethodSignature *sig = mono_method_signature_internal (cmethod->method);
3841 if (mono_interp_jit_call_supported (cmethod->method, sig))
3842 code_type = IMETHOD_CODE_COMPILED;
3843 else
3844 code_type = IMETHOD_CODE_INTERP;
3845 cmethod->code_type = code_type;
3848 if (code_type == IMETHOD_CODE_INTERP) {
3850 goto call;
3852 } else if (code_type == IMETHOD_CODE_COMPILED) {
3853 error_init_reuse (error);
3854 do_jit_call (sp, vt_sp, context, frame, cmethod, error);
3855 if (!is_ok (error)) {
3856 MonoException *ex = mono_error_convert_to_exception (error);
3857 THROW_EX (ex, ip);
3860 CHECK_RESUME_STATE (context);
3862 if (cmethod->rtype->type != MONO_TYPE_VOID)
3863 sp++;
3866 MINT_IN_BREAK;
3868 MINT_IN_CASE(MINT_CALL_VARARG) {
3869 MonoMethodSignature *csig;
3871 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3873 /* The real signature for vararg calls */
3874 csig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3876 frame->ip = ip;
3878 // Retval must be set unconditionally due to MINT_ARGLIST.
3879 // is_void guides exit_frame instead of retval nullness.
3880 retval = sp;
3881 is_void = csig->ret->type == MONO_TYPE_VOID;
3883 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3884 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3886 ip += 3;
3887 sp->data.p = vt_sp;
3889 /* decrement by the actual number of args */
3890 // FIXME This seems excessive: frame and csig param_count.
3891 sp -= cmethod->param_count + cmethod->hasthis + csig->param_count - csig->sentinelpos;
3893 goto call;
3895 MINT_IN_CASE(MINT_VCALL)
3896 MINT_IN_CASE(MINT_CALL)
3897 MINT_IN_CASE(MINT_CALLVIRT)
3898 MINT_IN_CASE(MINT_VCALLVIRT) {
3899 // FIXME CALLVIRT opcodes are not used on netcore. We should kill them.
3900 // FIXME braces from here until call: label.
3901 is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3902 gboolean is_virtual;
3903 is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3905 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3906 sp->data.p = vt_sp;
3907 retval = is_void ? NULL : sp;
3909 /* decrement by the actual number of args */
3910 sp -= ip [2];
3912 if (is_virtual) {
3913 MonoObject *this_arg = (MonoObject*)sp->data.p;
3915 cmethod = get_virtual_method (cmethod, this_arg->vtable);
3916 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) {
3917 /* unbox */
3918 gpointer unboxed = mono_object_unbox_internal (this_arg);
3919 sp [0].data.p = unboxed;
3923 frame->ip = ip;
3924 #ifdef ENABLE_EXPERIMENT_TIERED
3925 ip += 5;
3926 #else
3927 ip += 3;
3928 #endif
3929 call:;
3930 // FIXME This assumes a grow-down stack.
3931 gpointer native_stack_addr = frame->native_stack_addr ? (gpointer)((guint8*)frame->native_stack_addr - 1) : (gpointer)&retval;
3934 * Make a non-recursive call by loading the new interpreter state based on child frame,
3935 * and going back to the main loop.
3937 SAVE_INTERP_STATE (frame);
3939 frame = alloc_frame (context, native_stack_addr, frame, cmethod, sp, retval);
3941 #if DEBUG_INTERP
3942 int tracing;
3943 #endif
3944 if (method_entry (context, frame,
3945 #if DEBUG_INTERP
3946 &tracing,
3947 #endif
3948 &ex, NULL)) {
3949 if (ex)
3950 THROW_EX (ex, NULL);
3951 EXCEPTION_CHECKPOINT;
3954 clause_args = NULL;
3955 INIT_INTERP_STATE (frame, clause_args);
3957 MINT_IN_BREAK;
3959 MINT_IN_CASE(MINT_JIT_CALL) {
3960 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3961 error_init_reuse (error);
3962 frame->ip = ip;
3963 sp -= rmethod->param_count + rmethod->hasthis;
3964 do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3965 if (!is_ok (error)) {
3966 MonoException *ex = mono_error_convert_to_exception (error);
3967 THROW_EX (ex, ip);
3969 ip += 2;
3971 CHECK_RESUME_STATE (context);
3973 if (rmethod->rtype->type != MONO_TYPE_VOID)
3974 sp++;
3976 MINT_IN_BREAK;
3978 MINT_IN_CASE(MINT_JIT_CALL2) {
3979 #ifdef ENABLE_EXPERIMENT_TIERED
3980 InterpMethod *rmethod = (InterpMethod *) READ64 (ip + 1);
3982 error_init_reuse (error);
3983 frame->ip = ip;
3985 sp -= rmethod->param_count + rmethod->hasthis;
3986 do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3987 if (!is_ok (error)) {
3988 MonoException *ex = mono_error_convert_to_exception (error);
3989 THROW_EX (ex, ip);
3991 ip += 5;
3993 CHECK_RESUME_STATE (context);
3995 if (rmethod->rtype->type != MONO_TYPE_VOID)
3996 sp++;
3997 #else
3998 g_error ("MINT_JIT_ICALL2 shouldn't be used");
3999 #endif
4000 MINT_IN_BREAK;
4002 MINT_IN_CASE(MINT_CALLRUN) {
4003 #ifndef ENABLE_NETCORE
4004 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [1]];
4005 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
4007 sp->data.p = vt_sp;
4008 retval = sp;
4010 sp -= sig->param_count;
4011 if (sig->hasthis)
4012 sp--;
4014 MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval);
4015 if (ex)
4016 THROW_EX (ex, ip);
4018 if (sig->ret->type != MONO_TYPE_VOID) {
4019 *sp = *retval;
4020 sp++;
4022 ip += 3;
4023 #else
4024 g_assert_not_reached ();
4025 #endif
4026 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_RET)
4029 --sp;
4030 *frame->retval = *sp;
4031 if (sp > frame->stack)
4032 g_warning_d ("ret: more values on stack: %d", sp - frame->stack);
4033 goto exit_frame;
4034 MINT_IN_CASE(MINT_RET_VOID)
4035 if (sp > frame->stack)
4036 g_warning_ds ("ret.void: more values on stack: %d %s", sp - frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
4037 goto exit_frame;
4038 MINT_IN_CASE(MINT_RET_VT) {
4039 int const i32 = READ32 (ip + 1);
4040 --sp;
4041 memcpy(frame->retval->data.p, sp->data.p, i32);
4042 if (sp > frame->stack)
4043 g_warning_d ("ret.vt: more values on stack: %d", sp - frame->stack);
4044 goto exit_frame;
4047 #ifdef ENABLE_EXPERIMENT_TIERED
4048 #define BACK_BRANCH_PROFILE(offset) do { \
4049 if (offset < 0) \
4050 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0); \
4051 } while (0);
4052 #else
4053 #define BACK_BRANCH_PROFILE(offset)
4054 #endif
4056 MINT_IN_CASE(MINT_BR_S) {
4057 short br_offset = (short) *(ip + 1);
4058 BACK_BRANCH_PROFILE (br_offset);
4059 ip += br_offset;
4060 MINT_IN_BREAK;
4062 MINT_IN_CASE(MINT_BR) {
4063 gint32 br_offset = (gint32) READ32(ip + 1);
4064 BACK_BRANCH_PROFILE (br_offset);
4065 ip += br_offset;
4066 MINT_IN_BREAK;
4069 #define ZEROP_S(datamem, op) \
4070 --sp; \
4071 if (sp->data.datamem op 0) { \
4072 gint16 br_offset = (gint16) ip [1]; \
4073 BACK_BRANCH_PROFILE (br_offset); \
4074 ip += br_offset; \
4075 } else \
4076 ip += 2;
4078 #define ZEROP(datamem, op) \
4079 --sp; \
4080 if (sp->data.datamem op 0) { \
4081 gint32 br_offset = (gint32)READ32(ip + 1); \
4082 BACK_BRANCH_PROFILE (br_offset); \
4083 ip += br_offset; \
4084 } else \
4085 ip += 3;
4087 MINT_IN_CASE(MINT_BRFALSE_I4_S)
4088 ZEROP_S(i, ==);
4089 MINT_IN_BREAK;
4090 MINT_IN_CASE(MINT_BRFALSE_I8_S)
4091 ZEROP_S(l, ==);
4092 MINT_IN_BREAK;
4093 MINT_IN_CASE(MINT_BRFALSE_R4_S)
4094 ZEROP_S(f_r4, ==);
4095 MINT_IN_BREAK;
4096 MINT_IN_CASE(MINT_BRFALSE_R8_S)
4097 ZEROP_S(f, ==);
4098 MINT_IN_BREAK;
4099 MINT_IN_CASE(MINT_BRFALSE_I4)
4100 ZEROP(i, ==);
4101 MINT_IN_BREAK;
4102 MINT_IN_CASE(MINT_BRFALSE_I8)
4103 ZEROP(l, ==);
4104 MINT_IN_BREAK;
4105 MINT_IN_CASE(MINT_BRFALSE_R4)
4106 ZEROP_S(f_r4, ==);
4107 MINT_IN_BREAK;
4108 MINT_IN_CASE(MINT_BRFALSE_R8)
4109 ZEROP_S(f, ==);
4110 MINT_IN_BREAK;
4111 MINT_IN_CASE(MINT_BRTRUE_I4_S)
4112 ZEROP_S(i, !=);
4113 MINT_IN_BREAK;
4114 MINT_IN_CASE(MINT_BRTRUE_I8_S)
4115 ZEROP_S(l, !=);
4116 MINT_IN_BREAK;
4117 MINT_IN_CASE(MINT_BRTRUE_R4_S)
4118 ZEROP_S(f_r4, !=);
4119 MINT_IN_BREAK;
4120 MINT_IN_CASE(MINT_BRTRUE_R8_S)
4121 ZEROP_S(f, !=);
4122 MINT_IN_BREAK;
4123 MINT_IN_CASE(MINT_BRTRUE_I4)
4124 ZEROP(i, !=);
4125 MINT_IN_BREAK;
4126 MINT_IN_CASE(MINT_BRTRUE_I8)
4127 ZEROP(l, !=);
4128 MINT_IN_BREAK;
4129 MINT_IN_CASE(MINT_BRTRUE_R4)
4130 ZEROP(f_r4, !=);
4131 MINT_IN_BREAK;
4132 MINT_IN_CASE(MINT_BRTRUE_R8)
4133 ZEROP(f, !=);
4134 MINT_IN_BREAK;
4135 #define CONDBR_S(cond) \
4136 sp -= 2; \
4137 if (cond) { \
4138 gint16 br_offset = (gint16) ip [1]; \
4139 BACK_BRANCH_PROFILE (br_offset); \
4140 ip += br_offset; \
4141 } else \
4142 ip += 2;
4143 #define BRELOP_S(datamem, op) \
4144 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
4146 #define CONDBR(cond) \
4147 sp -= 2; \
4148 if (cond) { \
4149 gint32 br_offset = (gint32) READ32 (ip + 1); \
4150 BACK_BRANCH_PROFILE (br_offset); \
4151 ip += br_offset; \
4152 } else \
4153 ip += 3;
4155 #define BRELOP(datamem, op) \
4156 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
4158 MINT_IN_CASE(MINT_BEQ_I4_S)
4159 BRELOP_S(i, ==)
4160 MINT_IN_BREAK;
4161 MINT_IN_CASE(MINT_BEQ_I8_S)
4162 BRELOP_S(l, ==)
4163 MINT_IN_BREAK;
4164 MINT_IN_CASE(MINT_BEQ_R4_S)
4165 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
4166 MINT_IN_BREAK;
4167 MINT_IN_CASE(MINT_BEQ_R8_S)
4168 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
4169 MINT_IN_BREAK;
4170 MINT_IN_CASE(MINT_BEQ_I4)
4171 BRELOP(i, ==)
4172 MINT_IN_BREAK;
4173 MINT_IN_CASE(MINT_BEQ_I8)
4174 BRELOP(l, ==)
4175 MINT_IN_BREAK;
4176 MINT_IN_CASE(MINT_BEQ_R4)
4177 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
4178 MINT_IN_BREAK;
4179 MINT_IN_CASE(MINT_BEQ_R8)
4180 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
4181 MINT_IN_BREAK;
4182 MINT_IN_CASE(MINT_BGE_I4_S)
4183 BRELOP_S(i, >=)
4184 MINT_IN_BREAK;
4185 MINT_IN_CASE(MINT_BGE_I8_S)
4186 BRELOP_S(l, >=)
4187 MINT_IN_BREAK;
4188 MINT_IN_CASE(MINT_BGE_R4_S)
4189 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
4190 MINT_IN_BREAK;
4191 MINT_IN_CASE(MINT_BGE_R8_S)
4192 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
4193 MINT_IN_BREAK;
4194 MINT_IN_CASE(MINT_BGE_I4)
4195 BRELOP(i, >=)
4196 MINT_IN_BREAK;
4197 MINT_IN_CASE(MINT_BGE_I8)
4198 BRELOP(l, >=)
4199 MINT_IN_BREAK;
4200 MINT_IN_CASE(MINT_BGE_R4)
4201 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
4202 MINT_IN_BREAK;
4203 MINT_IN_CASE(MINT_BGE_R8)
4204 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
4205 MINT_IN_BREAK;
4206 MINT_IN_CASE(MINT_BGT_I4_S)
4207 BRELOP_S(i, >)
4208 MINT_IN_BREAK;
4209 MINT_IN_CASE(MINT_BGT_I8_S)
4210 BRELOP_S(l, >)
4211 MINT_IN_BREAK;
4212 MINT_IN_CASE(MINT_BGT_R4_S)
4213 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
4214 MINT_IN_BREAK;
4215 MINT_IN_CASE(MINT_BGT_R8_S)
4216 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
4217 MINT_IN_BREAK;
4218 MINT_IN_CASE(MINT_BGT_I4)
4219 BRELOP(i, >)
4220 MINT_IN_BREAK;
4221 MINT_IN_CASE(MINT_BGT_I8)
4222 BRELOP(l, >)
4223 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_BGT_R4)
4225 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
4226 MINT_IN_BREAK;
4227 MINT_IN_CASE(MINT_BGT_R8)
4228 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
4229 MINT_IN_BREAK;
4230 MINT_IN_CASE(MINT_BLT_I4_S)
4231 BRELOP_S(i, <)
4232 MINT_IN_BREAK;
4233 MINT_IN_CASE(MINT_BLT_I8_S)
4234 BRELOP_S(l, <)
4235 MINT_IN_BREAK;
4236 MINT_IN_CASE(MINT_BLT_R4_S)
4237 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
4238 MINT_IN_BREAK;
4239 MINT_IN_CASE(MINT_BLT_R8_S)
4240 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
4241 MINT_IN_BREAK;
4242 MINT_IN_CASE(MINT_BLT_I4)
4243 BRELOP(i, <)
4244 MINT_IN_BREAK;
4245 MINT_IN_CASE(MINT_BLT_I8)
4246 BRELOP(l, <)
4247 MINT_IN_BREAK;
4248 MINT_IN_CASE(MINT_BLT_R4)
4249 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
4250 MINT_IN_BREAK;
4251 MINT_IN_CASE(MINT_BLT_R8)
4252 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
4253 MINT_IN_BREAK;
4254 MINT_IN_CASE(MINT_BLE_I4_S)
4255 BRELOP_S(i, <=)
4256 MINT_IN_BREAK;
4257 MINT_IN_CASE(MINT_BLE_I8_S)
4258 BRELOP_S(l, <=)
4259 MINT_IN_BREAK;
4260 MINT_IN_CASE(MINT_BLE_R4_S)
4261 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_BLE_R8_S)
4264 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
4265 MINT_IN_BREAK;
4266 MINT_IN_CASE(MINT_BLE_I4)
4267 BRELOP(i, <=)
4268 MINT_IN_BREAK;
4269 MINT_IN_CASE(MINT_BLE_I8)
4270 BRELOP(l, <=)
4271 MINT_IN_BREAK;
4272 MINT_IN_CASE(MINT_BLE_R4)
4273 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
4274 MINT_IN_BREAK;
4275 MINT_IN_CASE(MINT_BLE_R8)
4276 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
4277 MINT_IN_BREAK;
4278 MINT_IN_CASE(MINT_BNE_UN_I4_S)
4279 BRELOP_S(i, !=)
4280 MINT_IN_BREAK;
4281 MINT_IN_CASE(MINT_BNE_UN_I8_S)
4282 BRELOP_S(l, !=)
4283 MINT_IN_BREAK;
4284 MINT_IN_CASE(MINT_BNE_UN_R4_S)
4285 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
4286 MINT_IN_BREAK;
4287 MINT_IN_CASE(MINT_BNE_UN_R8_S)
4288 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
4289 MINT_IN_BREAK;
4290 MINT_IN_CASE(MINT_BNE_UN_I4)
4291 BRELOP(i, !=)
4292 MINT_IN_BREAK;
4293 MINT_IN_CASE(MINT_BNE_UN_I8)
4294 BRELOP(l, !=)
4295 MINT_IN_BREAK;
4296 MINT_IN_CASE(MINT_BNE_UN_R4)
4297 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
4298 MINT_IN_BREAK;
4299 MINT_IN_CASE(MINT_BNE_UN_R8)
4300 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
4301 MINT_IN_BREAK;
4303 #define BRELOP_S_CAST(datamem, op, type) \
4304 sp -= 2; \
4305 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4306 gint16 br_offset = (gint16) ip [1]; \
4307 BACK_BRANCH_PROFILE (br_offset); \
4308 ip += br_offset; \
4309 } else \
4310 ip += 2;
4312 #define BRELOP_CAST(datamem, op, type) \
4313 sp -= 2; \
4314 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4315 gint32 br_offset = (gint32) ip [1]; \
4316 BACK_BRANCH_PROFILE (br_offset); \
4317 ip += br_offset; \
4318 } else \
4319 ip += 3;
4321 MINT_IN_CASE(MINT_BGE_UN_I4_S)
4322 BRELOP_S_CAST(i, >=, guint32);
4323 MINT_IN_BREAK;
4324 MINT_IN_CASE(MINT_BGE_UN_I8_S)
4325 BRELOP_S_CAST(l, >=, guint64);
4326 MINT_IN_BREAK;
4327 MINT_IN_CASE(MINT_BGE_UN_R4_S)
4328 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4329 MINT_IN_BREAK;
4330 MINT_IN_CASE(MINT_BGE_UN_R8_S)
4331 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4332 MINT_IN_BREAK;
4333 MINT_IN_CASE(MINT_BGE_UN_I4)
4334 BRELOP_CAST(i, >=, guint32);
4335 MINT_IN_BREAK;
4336 MINT_IN_CASE(MINT_BGE_UN_I8)
4337 BRELOP_CAST(l, >=, guint64);
4338 MINT_IN_BREAK;
4339 MINT_IN_CASE(MINT_BGE_UN_R4)
4340 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4341 MINT_IN_BREAK;
4342 MINT_IN_CASE(MINT_BGE_UN_R8)
4343 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4344 MINT_IN_BREAK;
4345 MINT_IN_CASE(MINT_BGT_UN_I4_S)
4346 BRELOP_S_CAST(i, >, guint32);
4347 MINT_IN_BREAK;
4348 MINT_IN_CASE(MINT_BGT_UN_I8_S)
4349 BRELOP_S_CAST(l, >, guint64);
4350 MINT_IN_BREAK;
4351 MINT_IN_CASE(MINT_BGT_UN_R4_S)
4352 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4353 MINT_IN_BREAK;
4354 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4355 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4356 MINT_IN_BREAK;
4357 MINT_IN_CASE(MINT_BGT_UN_I4)
4358 BRELOP_CAST(i, >, guint32);
4359 MINT_IN_BREAK;
4360 MINT_IN_CASE(MINT_BGT_UN_I8)
4361 BRELOP_CAST(l, >, guint64);
4362 MINT_IN_BREAK;
4363 MINT_IN_CASE(MINT_BGT_UN_R4)
4364 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4365 MINT_IN_BREAK;
4366 MINT_IN_CASE(MINT_BGT_UN_R8)
4367 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4368 MINT_IN_BREAK;
4369 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4370 BRELOP_S_CAST(i, <=, guint32);
4371 MINT_IN_BREAK;
4372 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4373 BRELOP_S_CAST(l, <=, guint64);
4374 MINT_IN_BREAK;
4375 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4376 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4377 MINT_IN_BREAK;
4378 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4379 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4380 MINT_IN_BREAK;
4381 MINT_IN_CASE(MINT_BLE_UN_I4)
4382 BRELOP_CAST(i, <=, guint32);
4383 MINT_IN_BREAK;
4384 MINT_IN_CASE(MINT_BLE_UN_I8)
4385 BRELOP_CAST(l, <=, guint64);
4386 MINT_IN_BREAK;
4387 MINT_IN_CASE(MINT_BLE_UN_R4)
4388 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4389 MINT_IN_BREAK;
4390 MINT_IN_CASE(MINT_BLE_UN_R8)
4391 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4392 MINT_IN_BREAK;
4393 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4394 BRELOP_S_CAST(i, <, guint32);
4395 MINT_IN_BREAK;
4396 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4397 BRELOP_S_CAST(l, <, guint64);
4398 MINT_IN_BREAK;
4399 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4400 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4401 MINT_IN_BREAK;
4402 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4403 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4404 MINT_IN_BREAK;
4405 MINT_IN_CASE(MINT_BLT_UN_I4)
4406 BRELOP_CAST(i, <, guint32);
4407 MINT_IN_BREAK;
4408 MINT_IN_CASE(MINT_BLT_UN_I8)
4409 BRELOP_CAST(l, <, guint64);
4410 MINT_IN_BREAK;
4411 MINT_IN_CASE(MINT_BLT_UN_R4)
4412 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4413 MINT_IN_BREAK;
4414 MINT_IN_CASE(MINT_BLT_UN_R8)
4415 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4416 MINT_IN_BREAK;
4417 MINT_IN_CASE(MINT_SWITCH) {
4418 guint32 n;
4419 const unsigned short *st;
4420 ++ip;
4421 n = READ32 (ip);
4422 ip += 2;
4423 st = ip + 2 * n;
4424 --sp;
4425 if ((guint32)sp->data.i < n) {
4426 gint offset;
4427 ip += 2 * (guint32)sp->data.i;
4428 offset = READ32 (ip);
4429 ip = ip + offset;
4430 } else {
4431 ip = st;
4433 MINT_IN_BREAK;
4435 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4436 NULL_CHECK (sp [-1].data.p);
4437 ++ip;
4438 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4439 MINT_IN_BREAK;
4440 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4441 NULL_CHECK (sp [-1].data.p);
4442 ++ip;
4443 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4444 MINT_IN_BREAK;
4445 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4446 NULL_CHECK (sp [-1].data.p);
4447 ++ip;
4448 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4449 MINT_IN_BREAK;
4450 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4451 NULL_CHECK (sp [-1].data.p);
4452 ++ip;
4453 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4454 MINT_IN_BREAK;
4455 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4456 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4457 NULL_CHECK (sp [-1].data.p);
4458 ++ip;
4459 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4460 MINT_IN_BREAK;
4461 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4462 NULL_CHECK (sp [-1].data.p);
4463 ++ip;
4464 #ifdef NO_UNALIGNED_ACCESS
4465 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4466 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4467 else
4468 #endif
4469 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4470 MINT_IN_BREAK;
4471 MINT_IN_CASE(MINT_LDIND_I) {
4472 guint16 offset = ip [1];
4473 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4474 ip += 2;
4475 MINT_IN_BREAK;
4477 MINT_IN_CASE(MINT_LDIND_I8) {
4478 guint16 offset = ip [1];
4479 #ifdef NO_UNALIGNED_ACCESS
4480 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4481 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4482 else
4483 #endif
4484 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4485 ip += 2;
4486 MINT_IN_BREAK;
4488 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4489 NULL_CHECK (sp [-1].data.p);
4490 ++ip;
4491 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4492 MINT_IN_BREAK;
4493 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4494 NULL_CHECK (sp [-1].data.p);
4495 ++ip;
4496 #ifdef NO_UNALIGNED_ACCESS
4497 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4498 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4499 else
4500 #endif
4501 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4502 MINT_IN_BREAK;
4503 MINT_IN_CASE(MINT_LDIND_REF)
4504 ++ip;
4505 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4506 MINT_IN_BREAK;
4507 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4508 NULL_CHECK (sp [-1].data.p);
4509 ++ip;
4510 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4511 MINT_IN_BREAK;
4513 MINT_IN_CASE(MINT_STIND_REF)
4514 ++ip;
4515 sp -= 2;
4516 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4517 MINT_IN_BREAK;
4518 MINT_IN_CASE(MINT_STIND_I1)
4519 ++ip;
4520 sp -= 2;
4521 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4522 MINT_IN_BREAK;
4523 MINT_IN_CASE(MINT_STIND_I2)
4524 ++ip;
4525 sp -= 2;
4526 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4527 MINT_IN_BREAK;
4528 MINT_IN_CASE(MINT_STIND_I4)
4529 ++ip;
4530 sp -= 2;
4531 * (gint32 *) sp->data.p = sp[1].data.i;
4532 MINT_IN_BREAK;
4533 MINT_IN_CASE(MINT_STIND_I)
4534 ++ip;
4535 sp -= 2;
4536 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4537 MINT_IN_BREAK;
4538 MINT_IN_CASE(MINT_STIND_I8)
4539 ++ip;
4540 sp -= 2;
4541 #ifdef NO_UNALIGNED_ACCESS
4542 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4543 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4544 else
4545 #endif
4546 * (gint64 *) sp->data.p = sp[1].data.l;
4547 MINT_IN_BREAK;
4548 MINT_IN_CASE(MINT_STIND_R4)
4549 ++ip;
4550 sp -= 2;
4551 * (float *) sp->data.p = sp[1].data.f_r4;
4552 MINT_IN_BREAK;
4553 MINT_IN_CASE(MINT_STIND_R8)
4554 ++ip;
4555 sp -= 2;
4556 #ifdef NO_UNALIGNED_ACCESS
4557 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4558 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4559 else
4560 #endif
4561 * (double *) sp->data.p = sp[1].data.f;
4562 MINT_IN_BREAK;
4563 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4564 ++ip;
4565 sp -= 2;
4566 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4567 MINT_IN_BREAK;
4568 #define BINOP(datamem, op) \
4569 --sp; \
4570 sp [-1].data.datamem op ## = sp [0].data.datamem; \
4571 ++ip;
4572 MINT_IN_CASE(MINT_ADD_I4)
4573 BINOP(i, +);
4574 MINT_IN_BREAK;
4575 MINT_IN_CASE(MINT_ADD_I8)
4576 BINOP(l, +);
4577 MINT_IN_BREAK;
4578 MINT_IN_CASE(MINT_ADD_R4)
4579 BINOP(f_r4, +);
4580 MINT_IN_BREAK;
4581 MINT_IN_CASE(MINT_ADD_R8)
4582 BINOP(f, +);
4583 MINT_IN_BREAK;
4584 MINT_IN_CASE(MINT_ADD1_I4)
4585 ++sp [-1].data.i;
4586 ++ip;
4587 MINT_IN_BREAK;
4588 MINT_IN_CASE(MINT_ADD1_I8)
4589 ++sp [-1].data.l;
4590 ++ip;
4591 MINT_IN_BREAK;
4592 MINT_IN_CASE(MINT_LOCADD1_I4)
4593 *(gint32*)(locals + ip [1]) += 1;
4594 ip += 2;
4595 MINT_IN_BREAK;
4596 MINT_IN_CASE(MINT_LOCADD1_I8)
4597 *(gint64*)(locals + ip [1]) += 1;
4598 ip += 2;
4599 MINT_IN_BREAK;
4600 MINT_IN_CASE(MINT_SUB_I4)
4601 BINOP(i, -);
4602 MINT_IN_BREAK;
4603 MINT_IN_CASE(MINT_SUB_I8)
4604 BINOP(l, -);
4605 MINT_IN_BREAK;
4606 MINT_IN_CASE(MINT_SUB_R4)
4607 BINOP(f_r4, -);
4608 MINT_IN_BREAK;
4609 MINT_IN_CASE(MINT_SUB_R8)
4610 BINOP(f, -);
4611 MINT_IN_BREAK;
4612 MINT_IN_CASE(MINT_SUB1_I4)
4613 --sp [-1].data.i;
4614 ++ip;
4615 MINT_IN_BREAK;
4616 MINT_IN_CASE(MINT_SUB1_I8)
4617 --sp [-1].data.l;
4618 ++ip;
4619 MINT_IN_BREAK;
4620 MINT_IN_CASE(MINT_LOCSUB1_I4)
4621 *(gint32*)(locals + ip [1]) -= 1;
4622 ip += 2;
4623 MINT_IN_BREAK;
4624 MINT_IN_CASE(MINT_LOCSUB1_I8)
4625 *(gint64*)(locals + ip [1]) -= 1;
4626 MINT_IN_BREAK;
4627 MINT_IN_CASE(MINT_MUL_I4)
4628 BINOP(i, *);
4629 MINT_IN_BREAK;
4630 MINT_IN_CASE(MINT_MUL_I8)
4631 BINOP(l, *);
4632 MINT_IN_BREAK;
4633 MINT_IN_CASE(MINT_MUL_R4)
4634 BINOP(f_r4, *);
4635 MINT_IN_BREAK;
4636 MINT_IN_CASE(MINT_MUL_R8)
4637 BINOP(f, *);
4638 MINT_IN_BREAK;
4639 MINT_IN_CASE(MINT_DIV_I4)
4640 if (sp [-1].data.i == 0)
4641 goto div_zero_label;
4642 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4643 goto overflow_label;
4644 BINOP(i, /);
4645 MINT_IN_BREAK;
4646 MINT_IN_CASE(MINT_DIV_I8)
4647 if (sp [-1].data.l == 0)
4648 goto div_zero_label;
4649 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4650 goto overflow_label;
4651 BINOP(l, /);
4652 MINT_IN_BREAK;
4653 MINT_IN_CASE(MINT_DIV_R4)
4654 BINOP(f_r4, /);
4655 MINT_IN_BREAK;
4656 MINT_IN_CASE(MINT_DIV_R8)
4657 BINOP(f, /);
4658 MINT_IN_BREAK;
4660 #define BINOP_CAST(datamem, op, type) \
4661 --sp; \
4662 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4663 ++ip;
4664 MINT_IN_CASE(MINT_DIV_UN_I4)
4665 if (sp [-1].data.i == 0)
4666 goto div_zero_label;
4667 BINOP_CAST(i, /, guint32);
4668 MINT_IN_BREAK;
4669 MINT_IN_CASE(MINT_DIV_UN_I8)
4670 if (sp [-1].data.l == 0)
4671 goto div_zero_label;
4672 BINOP_CAST(l, /, guint64);
4673 MINT_IN_BREAK;
4674 MINT_IN_CASE(MINT_REM_I4)
4675 if (sp [-1].data.i == 0)
4676 goto div_zero_label;
4677 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4678 goto overflow_label;
4679 BINOP(i, %);
4680 MINT_IN_BREAK;
4681 MINT_IN_CASE(MINT_REM_I8)
4682 if (sp [-1].data.l == 0)
4683 goto div_zero_label;
4684 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4685 goto overflow_label;
4686 BINOP(l, %);
4687 MINT_IN_BREAK;
4688 MINT_IN_CASE(MINT_REM_R4)
4689 /* FIXME: what do we actually do here? */
4690 --sp;
4691 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4692 ++ip;
4693 MINT_IN_BREAK;
4694 MINT_IN_CASE(MINT_REM_R8)
4695 /* FIXME: what do we actually do here? */
4696 --sp;
4697 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4698 ++ip;
4699 MINT_IN_BREAK;
4700 MINT_IN_CASE(MINT_REM_UN_I4)
4701 if (sp [-1].data.i == 0)
4702 goto div_zero_label;
4703 BINOP_CAST(i, %, guint32);
4704 MINT_IN_BREAK;
4705 MINT_IN_CASE(MINT_REM_UN_I8)
4706 if (sp [-1].data.l == 0)
4707 goto div_zero_label;
4708 BINOP_CAST(l, %, guint64);
4709 MINT_IN_BREAK;
4710 MINT_IN_CASE(MINT_AND_I4)
4711 BINOP(i, &);
4712 MINT_IN_BREAK;
4713 MINT_IN_CASE(MINT_AND_I8)
4714 BINOP(l, &);
4715 MINT_IN_BREAK;
4716 MINT_IN_CASE(MINT_OR_I4)
4717 BINOP(i, |);
4718 MINT_IN_BREAK;
4719 MINT_IN_CASE(MINT_OR_I8)
4720 BINOP(l, |);
4721 MINT_IN_BREAK;
4722 MINT_IN_CASE(MINT_XOR_I4)
4723 BINOP(i, ^);
4724 MINT_IN_BREAK;
4725 MINT_IN_CASE(MINT_XOR_I8)
4726 BINOP(l, ^);
4727 MINT_IN_BREAK;
4729 #define SHIFTOP(datamem, op) \
4730 --sp; \
4731 sp [-1].data.datamem op ## = sp [0].data.i; \
4732 ++ip;
4734 MINT_IN_CASE(MINT_SHL_I4)
4735 SHIFTOP(i, <<);
4736 MINT_IN_BREAK;
4737 MINT_IN_CASE(MINT_SHL_I8)
4738 SHIFTOP(l, <<);
4739 MINT_IN_BREAK;
4740 MINT_IN_CASE(MINT_SHR_I4)
4741 SHIFTOP(i, >>);
4742 MINT_IN_BREAK;
4743 MINT_IN_CASE(MINT_SHR_I8)
4744 SHIFTOP(l, >>);
4745 MINT_IN_BREAK;
4746 MINT_IN_CASE(MINT_SHR_UN_I4)
4747 --sp;
4748 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4749 ++ip;
4750 MINT_IN_BREAK;
4751 MINT_IN_CASE(MINT_SHR_UN_I8)
4752 --sp;
4753 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4754 ++ip;
4755 MINT_IN_BREAK;
4756 MINT_IN_CASE(MINT_NEG_I4)
4757 sp [-1].data.i = - sp [-1].data.i;
4758 ++ip;
4759 MINT_IN_BREAK;
4760 MINT_IN_CASE(MINT_NEG_I8)
4761 sp [-1].data.l = - sp [-1].data.l;
4762 ++ip;
4763 MINT_IN_BREAK;
4764 MINT_IN_CASE(MINT_NEG_R4)
4765 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4766 ++ip;
4767 MINT_IN_BREAK;
4768 MINT_IN_CASE(MINT_NEG_R8)
4769 sp [-1].data.f = - sp [-1].data.f;
4770 ++ip;
4771 MINT_IN_BREAK;
4772 MINT_IN_CASE(MINT_NOT_I4)
4773 sp [-1].data.i = ~ sp [-1].data.i;
4774 ++ip;
4775 MINT_IN_BREAK;
4776 MINT_IN_CASE(MINT_NOT_I8)
4777 sp [-1].data.l = ~ sp [-1].data.l;
4778 ++ip;
4779 MINT_IN_BREAK;
4780 MINT_IN_CASE(MINT_CONV_I1_I4)
4781 sp [-1].data.i = (gint8)sp [-1].data.i;
4782 ++ip;
4783 MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_CONV_I1_I8)
4785 sp [-1].data.i = (gint8)sp [-1].data.l;
4786 ++ip;
4787 MINT_IN_BREAK;
4788 MINT_IN_CASE(MINT_CONV_I1_R4)
4789 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4790 ++ip;
4791 MINT_IN_BREAK;
4792 MINT_IN_CASE(MINT_CONV_I1_R8)
4793 /* without gint32 cast, C compiler is allowed to use undefined
4794 * behaviour if data.f is bigger than >255. See conv.fpint section
4795 * in C standard:
4796 * > The conversion truncates; that is, the fractional part
4797 * > is discarded. The behavior is undefined if the truncated
4798 * > value cannot be represented in the destination type.
4799 * */
4800 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4801 ++ip;
4802 MINT_IN_BREAK;
4803 MINT_IN_CASE(MINT_CONV_U1_I4)
4804 sp [-1].data.i = (guint8)sp [-1].data.i;
4805 ++ip;
4806 MINT_IN_BREAK;
4807 MINT_IN_CASE(MINT_CONV_U1_I8)
4808 sp [-1].data.i = (guint8)sp [-1].data.l;
4809 ++ip;
4810 MINT_IN_BREAK;
4811 MINT_IN_CASE(MINT_CONV_U1_R4)
4812 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4813 ++ip;
4814 MINT_IN_BREAK;
4815 MINT_IN_CASE(MINT_CONV_U1_R8)
4816 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4817 ++ip;
4818 MINT_IN_BREAK;
4819 MINT_IN_CASE(MINT_CONV_I2_I4)
4820 sp [-1].data.i = (gint16)sp [-1].data.i;
4821 ++ip;
4822 MINT_IN_BREAK;
4823 MINT_IN_CASE(MINT_CONV_I2_I8)
4824 sp [-1].data.i = (gint16)sp [-1].data.l;
4825 ++ip;
4826 MINT_IN_BREAK;
4827 MINT_IN_CASE(MINT_CONV_I2_R4)
4828 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4829 ++ip;
4830 MINT_IN_BREAK;
4831 MINT_IN_CASE(MINT_CONV_I2_R8)
4832 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4833 ++ip;
4834 MINT_IN_BREAK;
4835 MINT_IN_CASE(MINT_CONV_U2_I4)
4836 sp [-1].data.i = (guint16)sp [-1].data.i;
4837 ++ip;
4838 MINT_IN_BREAK;
4839 MINT_IN_CASE(MINT_CONV_U2_I8)
4840 sp [-1].data.i = (guint16)sp [-1].data.l;
4841 ++ip;
4842 MINT_IN_BREAK;
4843 MINT_IN_CASE(MINT_CONV_U2_R4)
4844 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4845 ++ip;
4846 MINT_IN_BREAK;
4847 MINT_IN_CASE(MINT_CONV_U2_R8)
4848 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4849 ++ip;
4850 MINT_IN_BREAK;
4851 MINT_IN_CASE(MINT_CONV_I4_R4)
4852 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4853 ++ip;
4854 MINT_IN_BREAK;
4855 MINT_IN_CASE(MINT_CONV_I4_R8)
4856 sp [-1].data.i = (gint32)sp [-1].data.f;
4857 ++ip;
4858 MINT_IN_BREAK;
4859 MINT_IN_CASE(MINT_CONV_U4_I8)
4860 MINT_IN_CASE(MINT_CONV_I4_I8)
4861 sp [-1].data.i = (gint32)sp [-1].data.l;
4862 ++ip;
4863 MINT_IN_BREAK;
4864 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4865 sp [-2].data.i = (gint32)sp [-2].data.l;
4866 ++ip;
4867 MINT_IN_BREAK;
4868 MINT_IN_CASE(MINT_CONV_U4_R4)
4869 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4870 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4871 #else
4872 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4873 #endif
4874 ++ip;
4875 MINT_IN_BREAK;
4876 MINT_IN_CASE(MINT_CONV_U4_R8)
4877 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4878 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4879 #else
4880 sp [-1].data.i = (guint32) sp [-1].data.f;
4881 #endif
4882 ++ip;
4883 MINT_IN_BREAK;
4884 MINT_IN_CASE(MINT_CONV_I8_I4)
4885 sp [-1].data.l = sp [-1].data.i;
4886 ++ip;
4887 MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4889 sp [-2].data.l = sp [-2].data.i;
4890 ++ip;
4891 MINT_IN_BREAK;
4892 MINT_IN_CASE(MINT_CONV_I8_U4)
4893 sp [-1].data.l = (guint32)sp [-1].data.i;
4894 ++ip;
4895 MINT_IN_BREAK;
4896 MINT_IN_CASE(MINT_CONV_I8_R4)
4897 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4898 ++ip;
4899 MINT_IN_BREAK;
4900 MINT_IN_CASE(MINT_CONV_I8_R8)
4901 sp [-1].data.l = (gint64)sp [-1].data.f;
4902 ++ip;
4903 MINT_IN_BREAK;
4904 MINT_IN_CASE(MINT_CONV_R4_I4)
4905 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4906 ++ip;
4907 MINT_IN_BREAK;
4908 MINT_IN_CASE(MINT_CONV_R4_I8)
4909 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4910 ++ip;
4911 MINT_IN_BREAK;
4912 MINT_IN_CASE(MINT_CONV_R4_R8)
4913 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4914 ++ip;
4915 MINT_IN_BREAK;
4916 MINT_IN_CASE(MINT_CONV_R8_I4)
4917 sp [-1].data.f = (double)sp [-1].data.i;
4918 ++ip;
4919 MINT_IN_BREAK;
4920 MINT_IN_CASE(MINT_CONV_R8_I8)
4921 sp [-1].data.f = (double)sp [-1].data.l;
4922 ++ip;
4923 MINT_IN_BREAK;
4924 MINT_IN_CASE(MINT_CONV_R8_R4)
4925 sp [-1].data.f = (double) sp [-1].data.f_r4;
4926 ++ip;
4927 MINT_IN_BREAK;
4928 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4929 sp [-2].data.f = (double) sp [-2].data.f_r4;
4930 ++ip;
4931 MINT_IN_BREAK;
4932 MINT_IN_CASE(MINT_CONV_U8_R4)
4933 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4934 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4935 #else
4936 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4937 #endif
4938 ++ip;
4939 MINT_IN_BREAK;
4940 MINT_IN_CASE(MINT_CONV_U8_R8)
4941 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4942 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4943 #else
4944 sp [-1].data.l = (guint64)sp [-1].data.f;
4945 #endif
4946 ++ip;
4947 MINT_IN_BREAK;
4948 MINT_IN_CASE(MINT_CPOBJ) {
4949 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4950 g_assert (m_class_is_valuetype (c));
4951 /* if this assertion fails, we need to add a write barrier */
4952 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4953 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4954 ip += 2;
4955 sp -= 2;
4956 MINT_IN_BREAK;
4958 MINT_IN_CASE(MINT_CPOBJ_VT) {
4959 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4960 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4961 ip += 2;
4962 sp -= 2;
4963 MINT_IN_BREAK;
4965 MINT_IN_CASE(MINT_LDOBJ_VT) {
4966 int size = READ32(ip + 1);
4967 ip += 3;
4968 memcpy (vt_sp, sp [-1].data.p, size);
4969 sp [-1].data.p = vt_sp;
4970 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4971 MINT_IN_BREAK;
4973 MINT_IN_CASE(MINT_LDSTR)
4974 sp->data.p = frame->imethod->data_items [ip [1]];
4975 ++sp;
4976 ip += 2;
4977 MINT_IN_BREAK;
4978 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4979 MonoString *s = NULL;
4980 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [1]];
4982 MonoMethod *method = frame->imethod->method;
4983 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4984 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4985 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4986 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4987 } else {
4988 g_assert_not_reached ();
4990 sp->data.p = s;
4991 ++sp;
4992 ip += 2;
4993 MINT_IN_BREAK;
4995 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4996 MonoClass *newobj_class;
4997 guint32 token = ip [1];
4998 guint16 param_count = ip [2];
5000 newobj_class = (MonoClass*) frame->imethod->data_items [token];
5002 sp -= param_count;
5003 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
5004 if (!is_ok (error))
5005 goto throw_error_label;
5007 ++sp;
5008 ip += 3;
5009 MINT_IN_BREAK;
5011 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
5012 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]];
5013 INIT_VTABLE (vtable);
5014 MonoObject *o; // See the comment about GC safety.
5015 guint16 param_count;
5016 guint16 imethod_index = ip [1];
5018 const gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG;
5020 param_count = ip [2];
5022 // Make room for two copies of o -- this parameter and return value.
5023 if (param_count || !is_inlined) {
5024 sp -= param_count;
5025 memmove (sp + 2, sp, param_count * sizeof (stackval));
5028 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5029 if (G_UNLIKELY (!o)) {
5030 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
5031 goto throw_error_label;
5034 // Store o next to and before the parameters on the stack so GC will see it,
5035 // and where it is needed when the call returns.
5036 sp [0].data.o = o;
5037 sp [1].data.o = o;
5038 ip += 4;
5039 if (is_inlined) {
5040 sp += param_count + 2;
5041 } else {
5042 cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index];
5043 frame->ip = ip - 4;
5044 goto call_newobj;
5047 MINT_IN_BREAK;
5050 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
5051 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
5053 frame->ip = ip;
5054 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
5055 guint16 const param_count = ip [2];
5057 // Make room for extra parameter and result.
5058 if (param_count) {
5059 sp -= param_count;
5060 memmove (sp + 2, sp, param_count * sizeof (stackval));
5063 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
5064 if (vtst) {
5065 memset (vt_sp, 0, ip [3]);
5066 ip += 4;
5067 // Put extra parameter and result on stack, before other parameters,
5068 // and point stack to extra parameter, after result.
5069 // This pattern occurs for newobj_vt_fast and newobj_fast.
5070 sp [1].data.p = vt_sp;
5071 sp [0].data.p = vt_sp;
5072 } else {
5073 ip += 3;
5074 // Like newobj_fast, add valuetype_this parameter
5075 // and result and point stack to this after result.
5076 memset (sp, 0, sizeof (*sp));
5077 sp [1].data.p = &sp [0].data; // valuetype_this == result
5080 // call_newobj captures the pattern where the return value is placed
5081 // on the stack before the call, instead of the call forming it.
5082 call_newobj:
5083 ++sp; // Point sp at added extra param, after return value.
5084 is_void = TRUE;
5085 retval = NULL;
5086 goto call;
5088 MINT_IN_CASE(MINT_NEWOBJ) {
5089 int dummy;
5090 // This is split up to:
5091 // - conserve stack
5092 // - keep exception handling and resume mostly in the main function
5094 frame->ip = ip;
5096 guint32 const token = ip [1];
5097 ip += 2; // FIXME: Do this after throw?
5099 child_frame = alloc_frame (context, &dummy, frame, (InterpMethod*)frame->imethod->data_items [token], NULL, NULL);
5100 MonoMethodSignature* const csig = mono_method_signature_internal (child_frame->imethod->method);
5102 g_assert (csig->hasthis);
5103 if (csig->param_count) {
5104 sp -= csig->param_count;
5105 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
5108 child_frame->stack_args = sp;
5110 // FIXME remove recursion
5111 MonoException* const exc = mono_interp_newobj (child_frame, context, error, vt_sp);
5112 if (exc)
5113 THROW_EX (exc, ip);
5114 CHECK_RESUME_STATE (context);
5115 ++sp;
5116 MINT_IN_BREAK;
5118 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
5119 frame->ip = ip;
5120 ip += 2;
5122 MINT_IN_BREAK;
5124 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
5125 MonoMethodSignature *csig;
5126 guint32 token;
5128 frame->ip = ip;
5129 token = ip [1];
5130 ip += 2;
5132 InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token];
5133 csig = mono_method_signature_internal (cmethod->method);
5135 g_assert (csig->hasthis);
5136 sp -= csig->param_count;
5138 gpointer arg0 = sp [0].data.p;
5140 gpointer *byreference_this = (gpointer*)vt_sp;
5141 *byreference_this = arg0;
5143 /* Followed by a VTRESULT opcode which will push the result on the stack */
5144 ++sp;
5145 MINT_IN_BREAK;
5147 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
5148 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
5149 sp [-1].data.p = *byreference_this;
5150 ++ip;
5151 MINT_IN_BREAK;
5153 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
5154 sp -= 2;
5155 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
5156 sp ++;
5157 ++ip;
5158 MINT_IN_BREAK;
5160 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
5161 sp -= 2;
5162 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
5163 sp ++;
5164 ++ip;
5165 MINT_IN_BREAK;
5167 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
5168 MonoObject *obj = sp [-1].data.o;
5169 sp [-1].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
5170 ++ip;
5171 MINT_IN_BREAK;
5173 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
5174 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
5175 MonoObject* const o = sp [-1].data.o;
5176 if (o) {
5177 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5178 gboolean isinst;
5179 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
5180 isinst = TRUE;
5181 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
5182 /* slow path */
5183 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
5184 } else {
5185 isinst = FALSE;
5188 if (!isinst) {
5189 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
5190 if (isinst_instr)
5191 sp [-1].data.p = NULL;
5192 else
5193 goto invalid_cast_label;
5196 ip += 2;
5197 MINT_IN_BREAK;
5199 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
5200 MINT_IN_CASE(MINT_ISINST_COMMON) {
5201 MonoObject* const o = sp [-1].data.o;
5202 if (o) {
5203 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5204 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
5206 if (!isinst) {
5207 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
5208 if (isinst_instr)
5209 sp [-1].data.p = NULL;
5210 else
5211 goto invalid_cast_label;
5214 ip += 2;
5215 MINT_IN_BREAK;
5217 MINT_IN_CASE(MINT_CASTCLASS)
5218 MINT_IN_CASE(MINT_ISINST) {
5219 MonoObject* const o = sp [-1].data.o;
5220 if (o) {
5221 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5222 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
5223 gboolean const isinst_instr = *ip == MINT_ISINST;
5224 if (isinst_instr)
5225 sp [-1].data.p = NULL;
5226 else
5227 goto invalid_cast_label;
5230 ip += 2;
5231 MINT_IN_BREAK;
5233 MINT_IN_CASE(MINT_CONV_R_UN_I4)
5234 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
5235 ++ip;
5236 MINT_IN_BREAK;
5237 MINT_IN_CASE(MINT_CONV_R_UN_I8)
5238 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
5239 ++ip;
5240 MINT_IN_BREAK;
5241 MINT_IN_CASE(MINT_UNBOX) {
5242 MonoObject* const o = sp [-1].data.o;
5243 NULL_CHECK (o);
5244 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5246 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
5247 goto invalid_cast_label;
5249 sp [-1].data.p = mono_object_unbox_internal (o);
5250 ip += 2;
5251 MINT_IN_BREAK;
5253 MINT_IN_CASE(MINT_THROW)
5254 --sp;
5255 if (!sp->data.p)
5256 sp->data.p = mono_get_exception_null_reference ();
5258 THROW_EX ((MonoException *)sp->data.p, ip);
5259 MINT_IN_BREAK;
5260 MINT_IN_CASE(MINT_CHECKPOINT)
5261 /* Do synchronous checking of abort requests */
5262 EXCEPTION_CHECKPOINT;
5263 ++ip;
5264 MINT_IN_BREAK;
5265 MINT_IN_CASE(MINT_SAFEPOINT)
5266 /* Do synchronous checking of abort requests */
5267 EXCEPTION_CHECKPOINT;
5268 /* Poll safepoint */
5269 mono_threads_safepoint ();
5270 ++ip;
5271 MINT_IN_BREAK;
5272 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
5273 sp[-1].data.p = (char*)sp [-1].data.o + ip [1];
5274 ip += 2;
5275 MINT_IN_BREAK;
5277 MINT_IN_CASE(MINT_LDFLDA) {
5278 MonoObject* const o = sp [-1].data.o;
5279 NULL_CHECK (o);
5280 sp[-1].data.p = (char *)o + ip [1];
5281 ip += 2;
5282 MINT_IN_BREAK;
5284 MINT_IN_CASE(MINT_CKNULL_N) {
5285 /* Same as CKNULL, but further down the stack */
5286 int const n = ip [1];
5287 MonoObject* const o = sp [-n].data.o;
5288 NULL_CHECK (o);
5289 ip += 2;
5290 MINT_IN_BREAK;
5293 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5294 MonoObject* const o = sp [-1].data.o; \
5295 NULL_CHECK (o); \
5296 if (unaligned) \
5297 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
5298 else \
5299 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
5300 ip += 2; \
5301 } while (0)
5303 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
5305 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
5306 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
5307 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
5308 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
5309 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
5310 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
5311 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
5312 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
5313 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
5314 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
5315 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5316 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5318 MINT_IN_CASE(MINT_LDFLD_VT) {
5319 MonoObject* const o = sp [-1].data.o;
5320 NULL_CHECK (o);
5322 int size = READ32(ip + 2);
5323 sp [-1].data.p = vt_sp;
5324 memcpy (sp [-1].data.p, (char *)o + ip [1], size);
5325 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5326 ip += 4;
5327 MINT_IN_BREAK;
5330 MINT_IN_CASE(MINT_LDRMFLD) {
5331 MonoObject* const o = sp [-1].data.o;
5332 NULL_CHECK (o);
5333 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
5334 ip += 2;
5335 MINT_IN_BREAK;
5337 MINT_IN_CASE(MINT_LDRMFLD_VT) {
5338 MonoObject* const o = sp [-1].data.o;
5339 NULL_CHECK (o);
5340 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
5341 ip += 2;
5342 MINT_IN_BREAK;
5346 #define LDARGFLD(datamem, fieldtype) do { \
5347 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5348 NULL_CHECK (o); \
5349 sp [0].data.datamem = *(fieldtype *)((char *)o + ip [2]) ; \
5350 sp++; \
5351 ip += 3; \
5352 } while (0)
5353 MINT_IN_CASE(MINT_LDARGFLD_I1) LDARGFLD(i, gint8); MINT_IN_BREAK;
5354 MINT_IN_CASE(MINT_LDARGFLD_U1) LDARGFLD(i, guint8); MINT_IN_BREAK;
5355 MINT_IN_CASE(MINT_LDARGFLD_I2) LDARGFLD(i, gint16); MINT_IN_BREAK;
5356 MINT_IN_CASE(MINT_LDARGFLD_U2) LDARGFLD(i, guint16); MINT_IN_BREAK;
5357 MINT_IN_CASE(MINT_LDARGFLD_I4) LDARGFLD(i, gint32); MINT_IN_BREAK;
5358 MINT_IN_CASE(MINT_LDARGFLD_I8) LDARGFLD(l, gint64); MINT_IN_BREAK;
5359 MINT_IN_CASE(MINT_LDARGFLD_R4) LDARGFLD(f_r4, float); MINT_IN_BREAK;
5360 MINT_IN_CASE(MINT_LDARGFLD_R8) LDARGFLD(f, double); MINT_IN_BREAK;
5361 MINT_IN_CASE(MINT_LDARGFLD_O) LDARGFLD(p, gpointer); MINT_IN_BREAK;
5362 MINT_IN_CASE(MINT_LDARGFLD_P) LDARGFLD(p, gpointer); MINT_IN_BREAK;
5364 #define LDLOCFLD(datamem, fieldtype) do { \
5365 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5366 NULL_CHECK (o); \
5367 sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \
5368 sp++; \
5369 ip += 3; \
5370 } while (0)
5371 MINT_IN_CASE(MINT_LDLOCFLD_I1) LDLOCFLD(i, gint8); MINT_IN_BREAK;
5372 MINT_IN_CASE(MINT_LDLOCFLD_U1) LDLOCFLD(i, guint8); MINT_IN_BREAK;
5373 MINT_IN_CASE(MINT_LDLOCFLD_I2) LDLOCFLD(i, gint16); MINT_IN_BREAK;
5374 MINT_IN_CASE(MINT_LDLOCFLD_U2) LDLOCFLD(i, guint16); MINT_IN_BREAK;
5375 MINT_IN_CASE(MINT_LDLOCFLD_I4) LDLOCFLD(i, gint32); MINT_IN_BREAK;
5376 MINT_IN_CASE(MINT_LDLOCFLD_I8) LDLOCFLD(l, gint64); MINT_IN_BREAK;
5377 MINT_IN_CASE(MINT_LDLOCFLD_R4) LDLOCFLD(f_r4, float); MINT_IN_BREAK;
5378 MINT_IN_CASE(MINT_LDLOCFLD_R8) LDLOCFLD(f, double); MINT_IN_BREAK;
5379 MINT_IN_CASE(MINT_LDLOCFLD_O) LDLOCFLD(p, gpointer); MINT_IN_BREAK;
5380 MINT_IN_CASE(MINT_LDLOCFLD_P) LDLOCFLD(p, gpointer); MINT_IN_BREAK;
5382 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5383 MonoObject* const o = sp [-2].data.o; \
5384 NULL_CHECK (o); \
5385 sp -= 2; \
5386 if (unaligned) \
5387 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
5388 else \
5389 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
5390 ip += 2; \
5391 } while (0)
5393 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5395 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
5396 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
5397 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
5398 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
5399 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5400 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5401 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5402 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5403 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
5404 MINT_IN_CASE(MINT_STFLD_O) {
5405 MonoObject* const o = sp [-2].data.o;
5406 NULL_CHECK (o);
5407 sp -= 2;
5408 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [1], sp [1].data.o);
5409 ip += 2;
5410 MINT_IN_BREAK;
5412 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5413 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5415 MINT_IN_CASE(MINT_STFLD_VT) {
5416 MonoObject* const o = sp [-2].data.o;
5417 NULL_CHECK (o);
5418 sp -= 2;
5420 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [2]];
5421 int const i32 = mono_class_value_size (klass, NULL);
5423 guint16 offset = ip [1];
5424 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5426 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5427 ip += 3;
5428 MINT_IN_BREAK;
5430 MINT_IN_CASE(MINT_STRMFLD) {
5431 MonoClassField *field;
5433 MonoObject* const o = sp [-2].data.o;
5434 NULL_CHECK (o);
5436 field = (MonoClassField*)frame->imethod->data_items[ip [1]];
5437 ip += 2;
5439 #ifndef DISABLE_REMOTING
5440 if (mono_object_is_transparent_proxy (o)) {
5441 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5442 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5443 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5444 } else
5445 #endif
5446 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5448 sp -= 2;
5449 MINT_IN_BREAK;
5451 MINT_IN_CASE(MINT_STRMFLD_VT)
5453 NULL_CHECK (sp [-2].data.o);
5454 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5455 ip += 2;
5456 sp -= 2;
5457 MINT_IN_BREAK;
5459 #define STARGFLD(datamem, fieldtype) do { \
5460 MonoObject *o = frame->stack_args [ip [1]].data.o; \
5461 NULL_CHECK (o); \
5462 sp--; \
5463 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5464 ip += 3; \
5465 } while (0)
5466 MINT_IN_CASE(MINT_STARGFLD_I1) STARGFLD(i, gint8); MINT_IN_BREAK;
5467 MINT_IN_CASE(MINT_STARGFLD_U1) STARGFLD(i, guint8); MINT_IN_BREAK;
5468 MINT_IN_CASE(MINT_STARGFLD_I2) STARGFLD(i, gint16); MINT_IN_BREAK;
5469 MINT_IN_CASE(MINT_STARGFLD_U2) STARGFLD(i, guint16); MINT_IN_BREAK;
5470 MINT_IN_CASE(MINT_STARGFLD_I4) STARGFLD(i, gint32); MINT_IN_BREAK;
5471 MINT_IN_CASE(MINT_STARGFLD_I8) STARGFLD(l, gint64); MINT_IN_BREAK;
5472 MINT_IN_CASE(MINT_STARGFLD_R4) STARGFLD(f_r4, float); MINT_IN_BREAK;
5473 MINT_IN_CASE(MINT_STARGFLD_R8) STARGFLD(f, double); MINT_IN_BREAK;
5474 MINT_IN_CASE(MINT_STARGFLD_P) STARGFLD(p, gpointer); MINT_IN_BREAK;
5475 MINT_IN_CASE(MINT_STARGFLD_O) {
5476 MonoObject *o = frame->stack_args [ip [1]].data.o;
5477 NULL_CHECK (o);
5478 sp--;
5479 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o);
5480 ip += 3;
5481 MINT_IN_BREAK;
5484 #define STLOCFLD(datamem, fieldtype) do { \
5485 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5486 NULL_CHECK (o); \
5487 sp--; \
5488 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5489 ip += 3; \
5490 } while (0)
5491 MINT_IN_CASE(MINT_STLOCFLD_I1) STLOCFLD(i, gint8); MINT_IN_BREAK;
5492 MINT_IN_CASE(MINT_STLOCFLD_U1) STLOCFLD(i, guint8); MINT_IN_BREAK;
5493 MINT_IN_CASE(MINT_STLOCFLD_I2) STLOCFLD(i, gint16); MINT_IN_BREAK;
5494 MINT_IN_CASE(MINT_STLOCFLD_U2) STLOCFLD(i, guint16); MINT_IN_BREAK;
5495 MINT_IN_CASE(MINT_STLOCFLD_I4) STLOCFLD(i, gint32); MINT_IN_BREAK;
5496 MINT_IN_CASE(MINT_STLOCFLD_I8) STLOCFLD(l, gint64); MINT_IN_BREAK;
5497 MINT_IN_CASE(MINT_STLOCFLD_R4) STLOCFLD(f_r4, float); MINT_IN_BREAK;
5498 MINT_IN_CASE(MINT_STLOCFLD_R8) STLOCFLD(f, double); MINT_IN_BREAK;
5499 MINT_IN_CASE(MINT_STLOCFLD_P) STLOCFLD(p, gpointer); MINT_IN_BREAK;
5500 MINT_IN_CASE(MINT_STLOCFLD_O) {
5501 MonoObject *o = *(MonoObject**)(locals + ip [1]);
5502 NULL_CHECK (o);
5503 sp--;
5504 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o);
5505 ip += 3;
5506 MINT_IN_BREAK;
5509 MINT_IN_CASE(MINT_LDSFLDA) {
5510 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5511 INIT_VTABLE (vtable);
5512 sp->data.p = frame->imethod->data_items [ip [2]];
5513 ip += 3;
5514 ++sp;
5515 MINT_IN_BREAK;
5518 MINT_IN_CASE(MINT_LDSSFLDA) {
5519 guint32 offset = READ32(ip + 1);
5520 sp->data.p = mono_get_special_static_data (offset);
5521 ip += 3;
5522 ++sp;
5523 MINT_IN_BREAK;
5526 /* We init class here to preserve cctor order */
5527 #define LDSFLD(datamem, fieldtype) { \
5528 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5529 INIT_VTABLE (vtable); \
5530 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5531 ip += 3; \
5532 sp++; \
5535 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5536 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5537 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5538 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5539 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5540 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5541 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5542 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5543 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5544 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5546 MINT_IN_CASE(MINT_LDSFLD_VT) {
5547 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5548 INIT_VTABLE (vtable);
5549 sp->data.p = vt_sp;
5551 gpointer addr = frame->imethod->data_items [ip [2]];
5552 int const i32 = READ32 (ip + 3);
5553 memcpy (vt_sp, addr, i32);
5554 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5555 ip += 5;
5556 ++sp;
5557 MINT_IN_BREAK;
5560 #define LDTSFLD(datamem, fieldtype) { \
5561 MonoInternalThread *thread = mono_thread_internal_current (); \
5562 guint32 offset = READ32 (ip + 1); \
5563 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5564 sp[0].data.datamem = *(fieldtype*)addr; \
5565 ip += 3; \
5566 ++sp; \
5568 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5569 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5570 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5571 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5572 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5573 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5574 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5575 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5576 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5577 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5579 MINT_IN_CASE(MINT_LDSSFLD) {
5580 guint32 offset = READ32(ip + 2);
5581 gpointer addr = mono_get_special_static_data (offset);
5582 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5583 stackval_from_data (field->type, sp, addr, FALSE);
5584 ip += 4;
5585 ++sp;
5586 MINT_IN_BREAK;
5588 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5589 guint32 offset = READ32(ip + 1);
5590 gpointer addr = mono_get_special_static_data (offset);
5592 int size = READ32 (ip + 3);
5593 memcpy (vt_sp, addr, size);
5594 sp->data.p = vt_sp;
5595 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5596 ip += 5;
5597 ++sp;
5598 MINT_IN_BREAK;
5600 #define STSFLD(datamem, fieldtype) { \
5601 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5602 INIT_VTABLE (vtable); \
5603 sp --; \
5604 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5605 ip += 3; \
5608 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5609 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5610 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5611 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5612 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5613 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5614 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5615 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5616 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5617 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5619 MINT_IN_CASE(MINT_STSFLD_VT) {
5620 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5621 INIT_VTABLE (vtable);
5622 int const i32 = READ32 (ip + 3);
5623 gpointer addr = frame->imethod->data_items [ip [2]];
5625 memcpy (addr, sp [-1].data.vt, i32);
5626 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5627 ip += 5;
5628 --sp;
5629 MINT_IN_BREAK;
5632 #define STTSFLD(datamem, fieldtype) { \
5633 MonoInternalThread *thread = mono_thread_internal_current (); \
5634 guint32 offset = READ32 (ip + 1); \
5635 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5636 sp--; \
5637 *(fieldtype*)addr = sp[0].data.datamem; \
5638 ip += 3; \
5641 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5642 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5643 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5644 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5645 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5646 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5647 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5648 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5649 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5650 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5652 MINT_IN_CASE(MINT_STSSFLD) {
5653 guint32 offset = READ32(ip + 2);
5654 gpointer addr = mono_get_special_static_data (offset);
5655 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5656 --sp;
5657 stackval_to_data (field->type, sp, addr, FALSE);
5658 ip += 4;
5659 MINT_IN_BREAK;
5661 MINT_IN_CASE(MINT_STSSFLD_VT) {
5662 guint32 offset = READ32(ip + 1);
5663 gpointer addr = mono_get_special_static_data (offset);
5664 --sp;
5665 int size = READ32 (ip + 3);
5666 memcpy (addr, sp->data.vt, size);
5667 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5668 ip += 5;
5669 MINT_IN_BREAK;
5672 MINT_IN_CASE(MINT_STOBJ_VT) {
5673 int size;
5674 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5675 ip += 2;
5676 size = mono_class_value_size (c, NULL);
5677 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5678 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5679 sp -= 2;
5680 MINT_IN_BREAK;
5682 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5683 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5684 goto overflow_label;
5685 sp [-1].data.i = (gint32)sp [-1].data.f;
5686 ++ip;
5687 MINT_IN_BREAK;
5688 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5689 if (sp [-1].data.i < 0)
5690 goto overflow_label;
5691 sp [-1].data.l = sp [-1].data.i;
5692 ++ip;
5693 MINT_IN_BREAK;
5694 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5695 if (sp [-1].data.l < 0)
5696 goto overflow_label;
5697 ++ip;
5698 MINT_IN_BREAK;
5699 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5700 if ((guint64) sp [-1].data.l > G_MAXINT64)
5701 goto overflow_label;
5702 ++ip;
5703 MINT_IN_BREAK;
5704 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5705 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5706 goto overflow_label;
5707 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5708 ++ip;
5709 MINT_IN_BREAK;
5710 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5711 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5712 goto overflow_label;
5713 sp [-1].data.l = (guint64)sp [-1].data.f;
5714 ++ip;
5715 MINT_IN_BREAK;
5716 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5717 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5718 goto overflow_label;
5719 sp [-1].data.l = (gint64)sp [-1].data.f;
5720 ++ip;
5721 MINT_IN_BREAK;
5722 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5723 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5724 goto overflow_label;
5725 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5726 ++ip;
5727 MINT_IN_BREAK;
5728 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5729 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5730 goto overflow_label;
5731 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5732 ++ip;
5733 MINT_IN_BREAK;
5734 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5735 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5736 goto overflow_label;
5737 sp [-1].data.l = (gint64)sp [-1].data.f;
5738 ++ip;
5739 MINT_IN_BREAK;
5740 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5741 if ((guint64)sp [-1].data.l > G_MAXINT32)
5742 goto overflow_label;
5743 sp [-1].data.i = (gint32)sp [-1].data.l;
5744 ++ip;
5745 MINT_IN_BREAK;
5746 MINT_IN_CASE(MINT_BOX) {
5747 mono_interp_box (frame, ip, sp);
5748 ip += 3;
5749 MINT_IN_BREAK;
5751 MINT_IN_CASE(MINT_BOX_VT) {
5752 vt_sp -= mono_interp_box_vt (frame, ip, sp);
5753 ip += 4;
5754 MINT_IN_BREAK;
5756 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5757 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5758 ip += 4;
5759 MINT_IN_BREAK;
5761 MINT_IN_CASE(MINT_NEWARR) {
5762 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]];
5763 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5764 if (!is_ok (error)) {
5765 goto throw_error_label;
5767 ip += 2;
5768 /*if (profiling_classes) {
5769 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5770 count++;
5771 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5774 MINT_IN_BREAK;
5776 MINT_IN_CASE(MINT_LDLEN) {
5777 MonoObject* const o = sp [-1].data.o;
5778 NULL_CHECK (o);
5779 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5780 ++ip;
5781 MINT_IN_BREAK;
5783 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5784 MonoObject* const o = sp [-1].data.o;
5785 NULL_CHECK (o);
5786 gsize offset_length = (gsize)(gint16)ip [1];
5787 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5788 ip += 2;
5789 MINT_IN_BREAK;
5791 MINT_IN_CASE(MINT_GETCHR) {
5792 MonoString *s;
5793 s = (MonoString*)sp [-2].data.p;
5794 NULL_CHECK (s);
5795 int const i32 = sp [-1].data.i;
5796 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5797 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5798 --sp;
5799 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5800 ++ip;
5801 MINT_IN_BREAK;
5803 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5804 guint8 * const span = (guint8 *) sp [-2].data.p;
5805 const int index = sp [-1].data.i;
5806 sp--;
5808 NULL_CHECK (span);
5810 const gsize offset_length = (gsize)(gint16)ip [2];
5812 const gint32 length = *(gint32 *) (span + offset_length);
5813 if (index < 0 || index >= length)
5814 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5816 const gsize element_size = (gsize)(gint16)ip [1];
5817 const gsize offset_pointer = (gsize)(gint16)ip [3];
5819 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5820 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5822 ip += 4;
5823 MINT_IN_BREAK;
5825 MINT_IN_CASE(MINT_STRLEN) {
5826 ++ip;
5827 MonoObject* const o = sp [-1].data.o;
5828 NULL_CHECK (o);
5829 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5830 MINT_IN_BREAK;
5832 MINT_IN_CASE(MINT_ARRAY_RANK) {
5833 MonoObject* const o = sp [-1].data.o;
5834 NULL_CHECK (o);
5835 sp [-1].data.i = m_class_get_rank (mono_object_class (o));
5836 ip++;
5837 MINT_IN_BREAK;
5839 MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE) {
5840 MonoObject* const o = sp [-1].data.o;
5841 NULL_CHECK (o);
5842 sp [-1].data.i = mono_array_element_size (mono_object_class (o));
5843 ip++;
5844 MINT_IN_BREAK;
5846 MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE) {
5847 MonoObject* const o = sp [-1].data.o;
5848 NULL_CHECK (o);
5849 sp [-1].data.i = m_class_is_primitive (m_class_get_element_class (mono_object_class (o)));
5850 ip++;
5851 MINT_IN_BREAK;
5853 MINT_IN_CASE(MINT_LDELEMA1) {
5854 /* No bounds, one direction */
5855 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5856 NULL_CHECK (ao);
5857 gint32 const index = sp [-1].data.i;
5858 if (index >= ao->max_length)
5859 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5860 gint32 const size = READ32 (ip + 1);
5861 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5862 ip += 3;
5863 sp --;
5865 MINT_IN_BREAK;
5867 MINT_IN_CASE(MINT_LDELEMA) {
5868 guint16 rank = ip [1];
5869 gint32 const esize = READ32 (ip + 2);
5870 ip += 4;
5871 sp -= rank;
5873 MonoArray* const ao = (MonoArray*) sp [-1].data.o;
5874 NULL_CHECK (ao);
5876 g_assert (ao->bounds);
5877 guint32 pos = 0;
5878 for (int i = 0; i < rank; i++) {
5879 guint32 idx = sp [i].data.i;
5880 guint32 lower = ao->bounds [i].lower_bound;
5881 guint32 len = ao->bounds [i].length;
5882 if (idx < lower || (idx - lower) >= len)
5883 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5884 pos = (pos * len) + idx - lower;
5887 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
5888 MINT_IN_BREAK;
5890 MINT_IN_CASE(MINT_LDELEMA_TC) {
5891 guint16 rank = ip [1];
5892 ip += 3;
5893 sp -= rank;
5895 MonoObject* const o = sp [-1].data.o;
5896 NULL_CHECK (o);
5898 MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [-3 + 2]];
5899 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5900 MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, sp, needs_typecheck);
5901 if (ex)
5902 THROW_EX (ex, ip);
5903 MINT_IN_BREAK;
5906 #define LDELEM(datamem,elemtype) do { \
5907 sp--; \
5908 MonoArray *o = (MonoArray*)sp [-1].data.p; \
5909 NULL_CHECK (o); \
5910 gint32 aindex = sp [0].data.i; \
5911 if (aindex >= mono_array_length_internal (o)) \
5912 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5913 sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \
5914 ip++; \
5915 } while (0)
5916 MINT_IN_CASE(MINT_LDELEM_I1) LDELEM(i, gint8); MINT_IN_BREAK;
5917 MINT_IN_CASE(MINT_LDELEM_U1) LDELEM(i, guint8); MINT_IN_BREAK;
5918 MINT_IN_CASE(MINT_LDELEM_I2) LDELEM(i, gint16); MINT_IN_BREAK;
5919 MINT_IN_CASE(MINT_LDELEM_U2) LDELEM(i, guint16); MINT_IN_BREAK;
5920 MINT_IN_CASE(MINT_LDELEM_I4) LDELEM(i, gint32); MINT_IN_BREAK;
5921 MINT_IN_CASE(MINT_LDELEM_U4) LDELEM(i, guint32); MINT_IN_BREAK;
5922 MINT_IN_CASE(MINT_LDELEM_I8) LDELEM(l, guint64); MINT_IN_BREAK;
5923 MINT_IN_CASE(MINT_LDELEM_I) LDELEM(nati, mono_i); MINT_IN_BREAK;
5924 MINT_IN_CASE(MINT_LDELEM_R4) LDELEM(f_r4, float); MINT_IN_BREAK;
5925 MINT_IN_CASE(MINT_LDELEM_R8) LDELEM(f, double); MINT_IN_BREAK;
5926 MINT_IN_CASE(MINT_LDELEM_REF) LDELEM(p, gpointer); MINT_IN_BREAK;
5927 MINT_IN_CASE(MINT_LDELEM_VT) {
5928 sp--;
5929 MonoArray *o = (MonoArray*)sp [-1].data.p;
5930 NULL_CHECK (o);
5931 mono_u aindex = sp [0].data.i;
5932 if (aindex >= mono_array_length_internal (o))
5933 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5935 int i32 = READ32 (ip + 1);
5936 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5937 sp [-1].data.vt = vt_sp;
5938 // Copying to vtstack. No wbarrier needed
5939 memcpy (sp [-1].data.vt, src_addr, i32);
5940 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5942 ip += 3;
5943 MINT_IN_BREAK;
5945 #define STELEM_PROLOG(o, aindex) do { \
5946 sp -= 3; \
5947 o = (MonoArray*)sp [0].data.p; \
5948 NULL_CHECK (o); \
5949 aindex = sp [1].data.i; \
5950 if (aindex >= mono_array_length_internal (o)) \
5951 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
5952 } while (0)
5954 #define STELEM(datamem,elemtype) do { \
5955 MonoArray *o; \
5956 gint32 aindex; \
5957 STELEM_PROLOG(o, aindex); \
5958 mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \
5959 ip++; \
5960 } while (0)
5961 MINT_IN_CASE(MINT_STELEM_I1) STELEM(i, gint8); MINT_IN_BREAK;
5962 MINT_IN_CASE(MINT_STELEM_U1) STELEM(i, guint8); MINT_IN_BREAK;
5963 MINT_IN_CASE(MINT_STELEM_I2) STELEM(i, gint16); MINT_IN_BREAK;
5964 MINT_IN_CASE(MINT_STELEM_U2) STELEM(i, guint16); MINT_IN_BREAK;
5965 MINT_IN_CASE(MINT_STELEM_I4) STELEM(i, gint32); MINT_IN_BREAK;
5966 MINT_IN_CASE(MINT_STELEM_I8) STELEM(l, gint64); MINT_IN_BREAK;
5967 MINT_IN_CASE(MINT_STELEM_I) STELEM(nati, mono_i); MINT_IN_BREAK;
5968 MINT_IN_CASE(MINT_STELEM_R4) STELEM(f_r4, float); MINT_IN_BREAK;
5969 MINT_IN_CASE(MINT_STELEM_R8) STELEM(f, double); MINT_IN_BREAK;
5970 MINT_IN_CASE(MINT_STELEM_REF) {
5971 MonoArray *o;
5972 gint32 aindex;
5973 STELEM_PROLOG(o, aindex);
5975 if (sp [2].data.o) {
5976 gboolean isinst = mono_interp_isinst (sp [2].data.o, m_class_get_element_class (mono_object_class (o)));
5977 if (!isinst)
5978 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5980 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5981 ip++;
5982 MINT_IN_BREAK;
5985 MINT_IN_CASE(MINT_STELEM_VT) {
5986 MonoArray *o;
5987 gint32 aindex;
5988 STELEM_PROLOG(o, aindex);
5990 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [1]];
5991 int const i32 = READ32 (ip + 2);
5992 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5994 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5995 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5996 ip += 4;
5997 MINT_IN_BREAK;
5999 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
6000 if (sp [-1].data.i < 0)
6001 goto overflow_label;
6002 ++ip;
6003 MINT_IN_BREAK;
6004 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
6005 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
6006 goto overflow_label;
6007 sp [-1].data.i = (gint32) sp [-1].data.l;
6008 ++ip;
6009 MINT_IN_BREAK;
6010 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
6011 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
6012 goto overflow_label;
6013 sp [-1].data.i = (gint32) sp [-1].data.l;
6014 ++ip;
6015 MINT_IN_BREAK;
6016 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
6017 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32 || isnan (sp [-1].data.f_r4))
6018 goto overflow_label;
6019 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
6020 ++ip;
6021 MINT_IN_BREAK;
6022 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
6023 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32 || isnan (sp [-1].data.f))
6024 goto overflow_label;
6025 sp [-1].data.i = (gint32) sp [-1].data.f;
6026 ++ip;
6027 MINT_IN_BREAK;
6028 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
6029 if (sp [-1].data.i < 0)
6030 goto overflow_label;
6031 ++ip;
6032 MINT_IN_BREAK;
6033 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
6034 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
6035 goto overflow_label;
6036 sp [-1].data.i = (guint32) sp [-1].data.l;
6037 ++ip;
6038 MINT_IN_BREAK;
6039 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
6040 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32 || isnan (sp [-1].data.f_r4))
6041 goto overflow_label;
6042 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
6043 ++ip;
6044 MINT_IN_BREAK;
6045 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
6046 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32 || isnan (sp [-1].data.f))
6047 goto overflow_label;
6048 sp [-1].data.i = (guint32) sp [-1].data.f;
6049 ++ip;
6050 MINT_IN_BREAK;
6051 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
6052 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
6053 goto overflow_label;
6054 ++ip;
6055 MINT_IN_BREAK;
6056 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
6057 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
6058 goto overflow_label;
6059 ++ip;
6060 MINT_IN_BREAK;
6061 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
6062 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
6063 goto overflow_label;
6064 sp [-1].data.i = (gint16) sp [-1].data.l;
6065 ++ip;
6066 MINT_IN_BREAK;
6067 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
6068 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
6069 goto overflow_label;
6070 sp [-1].data.i = (gint16) sp [-1].data.l;
6071 ++ip;
6072 MINT_IN_BREAK;
6073 MINT_IN_CASE(MINT_CONV_OVF_I2_R4)
6074 if (sp [-1].data.f_r4 < G_MININT16 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4))
6075 goto overflow_label;
6076 sp [-1].data.i = (gint16) sp [-1].data.f_r4;
6077 ++ip;
6078 MINT_IN_BREAK;
6079 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
6080 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f))
6081 goto overflow_label;
6082 sp [-1].data.i = (gint16) sp [-1].data.f;
6083 ++ip;
6084 MINT_IN_BREAK;
6085 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4)
6086 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4))
6087 goto overflow_label;
6088 sp [-1].data.i = (gint16) sp [-1].data.f_r4;
6089 ++ip;
6090 MINT_IN_BREAK;
6091 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
6092 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f))
6093 goto overflow_label;
6094 sp [-1].data.i = (gint16) sp [-1].data.f;
6095 ++ip;
6096 MINT_IN_BREAK;
6097 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
6098 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
6099 goto overflow_label;
6100 ++ip;
6101 MINT_IN_BREAK;
6102 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
6103 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
6104 goto overflow_label;
6105 sp [-1].data.i = (guint16) sp [-1].data.l;
6106 ++ip;
6107 MINT_IN_BREAK;
6108 MINT_IN_CASE(MINT_CONV_OVF_U2_R4)
6109 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT16 || isnan (sp [-1].data.f_r4))
6110 goto overflow_label;
6111 sp [-1].data.i = (guint16) sp [-1].data.f_r4;
6112 ++ip;
6113 MINT_IN_BREAK;
6114 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
6115 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16 || isnan (sp [-1].data.f))
6116 goto overflow_label;
6117 sp [-1].data.i = (guint16) sp [-1].data.f;
6118 ++ip;
6119 MINT_IN_BREAK;
6120 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
6121 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
6122 goto overflow_label;
6123 ++ip;
6124 MINT_IN_BREAK;
6125 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
6126 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
6127 goto overflow_label;
6128 ++ip;
6129 MINT_IN_BREAK;
6130 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
6131 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
6132 goto overflow_label;
6133 sp [-1].data.i = (gint8) sp [-1].data.l;
6134 ++ip;
6135 MINT_IN_BREAK;
6136 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
6137 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
6138 goto overflow_label;
6139 sp [-1].data.i = (gint8) sp [-1].data.l;
6140 ++ip;
6141 MINT_IN_BREAK;
6142 MINT_IN_CASE(MINT_CONV_OVF_I1_R4)
6143 if (sp [-1].data.f_r4 < G_MININT8 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4))
6144 goto overflow_label;
6145 sp [-1].data.i = (gint8) sp [-1].data.f_r4;
6146 ++ip;
6147 MINT_IN_BREAK;
6148 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
6149 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f))
6150 goto overflow_label;
6151 sp [-1].data.i = (gint8) sp [-1].data.f;
6152 ++ip;
6153 MINT_IN_BREAK;
6154 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4)
6155 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4))
6156 goto overflow_label;
6157 sp [-1].data.i = (gint8) sp [-1].data.f_r4;
6158 ++ip;
6159 MINT_IN_BREAK;
6160 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
6161 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f))
6162 goto overflow_label;
6163 sp [-1].data.i = (gint8) sp [-1].data.f;
6164 ++ip;
6165 MINT_IN_BREAK;
6166 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
6167 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
6168 goto overflow_label;
6169 ++ip;
6170 MINT_IN_BREAK;
6171 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
6172 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
6173 goto overflow_label;
6174 sp [-1].data.i = (guint8) sp [-1].data.l;
6175 ++ip;
6176 MINT_IN_BREAK;
6177 MINT_IN_CASE(MINT_CONV_OVF_U1_R4)
6178 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT8 || isnan (sp [-1].data.f_r4))
6179 goto overflow_label;
6180 sp [-1].data.i = (guint8) sp [-1].data.f_r4;
6181 ++ip;
6182 MINT_IN_BREAK;
6183 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
6184 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8 || isnan (sp [-1].data.f))
6185 goto overflow_label;
6186 sp [-1].data.i = (guint8) sp [-1].data.f;
6187 ++ip;
6188 MINT_IN_BREAK;
6189 MINT_IN_CASE(MINT_CKFINITE)
6190 if (!mono_isfinite (sp [-1].data.f))
6191 THROW_EX (mono_get_exception_arithmetic (), ip);
6192 ++ip;
6193 MINT_IN_BREAK;
6194 MINT_IN_CASE(MINT_MKREFANY) {
6195 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
6197 /* The value address is on the stack */
6198 gpointer addr = sp [-1].data.p;
6199 /* Push the typedref value on the stack */
6200 sp [-1].data.p = vt_sp;
6201 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6203 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6204 tref->klass = c;
6205 tref->type = m_class_get_byval_arg (c);
6206 tref->value = addr;
6208 ip += 2;
6209 MINT_IN_BREAK;
6211 MINT_IN_CASE(MINT_REFANYTYPE) {
6212 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6213 MonoType *type = tref->type;
6215 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6216 sp [-1].data.p = vt_sp;
6217 vt_sp += 8;
6218 *(gpointer*)sp [-1].data.p = type;
6219 ip ++;
6220 MINT_IN_BREAK;
6222 MINT_IN_CASE(MINT_REFANYVAL) {
6223 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6224 gpointer addr = tref->value;
6226 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
6227 if (c != tref->klass)
6228 goto invalid_cast_label;
6230 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6232 sp [-1].data.p = addr;
6233 ip += 2;
6234 MINT_IN_BREAK;
6236 MINT_IN_CASE(MINT_LDTOKEN)
6237 sp->data.p = vt_sp;
6238 vt_sp += 8;
6239 * (gpointer *)sp->data.p = frame->imethod->data_items[ip [1]];
6240 ip += 2;
6241 ++sp;
6242 MINT_IN_BREAK;
6243 MINT_IN_CASE(MINT_ADD_OVF_I4)
6244 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6245 goto overflow_label;
6246 BINOP(i, +);
6247 MINT_IN_BREAK;
6248 MINT_IN_CASE(MINT_ADD_OVF_I8)
6249 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6250 goto overflow_label;
6251 BINOP(l, +);
6252 MINT_IN_BREAK;
6253 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
6254 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6255 goto overflow_label;
6256 BINOP_CAST(i, +, guint32);
6257 MINT_IN_BREAK;
6258 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
6259 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6260 goto overflow_label;
6261 BINOP_CAST(l, +, guint64);
6262 MINT_IN_BREAK;
6263 MINT_IN_CASE(MINT_MUL_OVF_I4)
6264 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6265 goto overflow_label;
6266 BINOP(i, *);
6267 MINT_IN_BREAK;
6268 MINT_IN_CASE(MINT_MUL_OVF_I8)
6269 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6270 goto overflow_label;
6271 BINOP(l, *);
6272 MINT_IN_BREAK;
6273 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
6274 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6275 goto overflow_label;
6276 BINOP_CAST(i, *, guint32);
6277 MINT_IN_BREAK;
6278 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
6279 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6280 goto overflow_label;
6281 BINOP_CAST(l, *, guint64);
6282 MINT_IN_BREAK;
6283 MINT_IN_CASE(MINT_SUB_OVF_I4)
6284 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6285 goto overflow_label;
6286 BINOP(i, -);
6287 MINT_IN_BREAK;
6288 MINT_IN_CASE(MINT_SUB_OVF_I8)
6289 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6290 goto overflow_label;
6291 BINOP(l, -);
6292 MINT_IN_BREAK;
6293 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
6294 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6295 goto overflow_label;
6296 BINOP_CAST(i, -, guint32);
6297 MINT_IN_BREAK;
6298 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
6299 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6300 goto overflow_label;
6301 BINOP_CAST(l, -, guint64);
6302 MINT_IN_BREAK;
6303 MINT_IN_CASE(MINT_START_ABORT_PROT)
6304 mono_threads_begin_abort_protected_block ();
6305 ip ++;
6306 MINT_IN_BREAK;
6307 MINT_IN_CASE(MINT_ENDFINALLY) {
6308 gboolean pending_abort = mono_threads_end_abort_protected_block ();
6309 ip ++;
6311 // After mono_threads_end_abort_protected_block to conserve stack.
6312 const int clause_index = *ip;
6314 if (clause_args && clause_index == clause_args->exit_clause)
6315 goto exit_frame;
6317 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
6318 g_assert (sp >= frame->stack);
6319 #endif
6320 sp = frame->stack;
6322 if (finally_ips) {
6323 ip = (const guint16*)finally_ips->data;
6324 finally_ips = g_slist_remove (finally_ips, ip);
6325 /* Throw abort after the last finally block to avoid confusing EH */
6326 if (pending_abort && !finally_ips)
6327 EXCEPTION_CHECKPOINT;
6328 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6329 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6330 goto main_loop;
6332 ves_abort();
6333 MINT_IN_BREAK;
6336 MINT_IN_CASE(MINT_LEAVE)
6337 MINT_IN_CASE(MINT_LEAVE_S)
6338 MINT_IN_CASE(MINT_LEAVE_CHECK)
6339 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
6340 int dummy;
6341 // Leave is split into pieces in order to consume less stack,
6342 // but not have to change how exception handling macros access labels and locals.
6344 g_assert (sp >= frame->stack);
6345 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
6347 frame->ip = ip;
6349 int opcode = *ip;
6350 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
6352 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
6353 child_frame = alloc_frame (context, &dummy, frame, NULL, NULL, NULL);
6354 MonoException *abort_exc = mono_interp_leave (child_frame);
6355 if (abort_exc)
6356 THROW_EX (abort_exc, frame->ip);
6359 opcode = *ip; // Refetch to avoid register/stack pressure.
6360 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
6361 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
6362 const guint16 *endfinally_ip = ip;
6363 GSList *old_list = finally_ips;
6364 MonoMethod *method = frame->imethod->method;
6365 #if DEBUG_INTERP
6366 if (tracing)
6367 g_print ("* Handle finally IL_%04x\n", endfinally_ip - frame->imethod->code);
6368 #endif
6369 // FIXME Null check for frame->imethod follows deref.
6370 if (frame->imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6371 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
6372 goto exit_frame;
6373 guint32 const ip_offset = frame->ip - frame->imethod->code;
6375 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
6377 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
6378 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
6379 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code))) {
6380 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6381 ip = frame->imethod->code + clause->handler_offset;
6382 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6383 #if DEBUG_INTERP
6384 if (tracing)
6385 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, context->has_resume_state ? "yes": "no");
6386 #endif
6391 if (old_list != finally_ips && finally_ips) {
6392 ip = (const guint16*)finally_ips->data;
6393 finally_ips = g_slist_remove (finally_ips, ip);
6394 // we set vt_sp later here so we relieve stack pressure
6395 vt_sp = (unsigned char*)sp + frame->imethod->stack_size;
6396 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6397 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6398 goto main_loop;
6401 ves_abort();
6402 MINT_IN_BREAK;
6404 MINT_IN_CASE(MINT_ICALL_V_V)
6405 MINT_IN_CASE(MINT_ICALL_V_P)
6406 MINT_IN_CASE(MINT_ICALL_P_V)
6407 MINT_IN_CASE(MINT_ICALL_P_P)
6408 MINT_IN_CASE(MINT_ICALL_PP_V)
6409 MINT_IN_CASE(MINT_ICALL_PP_P)
6410 MINT_IN_CASE(MINT_ICALL_PPP_V)
6411 MINT_IN_CASE(MINT_ICALL_PPP_P)
6412 MINT_IN_CASE(MINT_ICALL_PPPP_V)
6413 MINT_IN_CASE(MINT_ICALL_PPPP_P)
6414 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
6415 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
6416 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
6417 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
6418 frame->ip = ip;
6419 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [ip [1]], FALSE);
6420 EXCEPTION_CHECKPOINT_GC_UNSAFE;
6421 CHECK_RESUME_STATE (context);
6422 ip += 2;
6423 MINT_IN_BREAK;
6424 MINT_IN_CASE(MINT_MONO_LDPTR)
6425 sp->data.p = frame->imethod->data_items [ip [1]];
6426 ip += 2;
6427 ++sp;
6428 MINT_IN_BREAK;
6429 MINT_IN_CASE(MINT_MONO_NEWOBJ)
6430 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [1]]); // FIXME: do not swallow the error
6431 ip += 2;
6432 sp++;
6433 MINT_IN_BREAK;
6434 MINT_IN_CASE(MINT_MONO_RETOBJ)
6435 ++ip;
6436 sp--;
6437 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
6438 mono_method_signature_internal (frame->imethod->method)->pinvoke);
6439 if (sp > frame->stack)
6440 g_warning_d ("retobj: more values on stack: %d", sp - frame->stack);
6441 goto exit_frame;
6442 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
6443 sp->data.p = mono_tls_get_sgen_thread_info ();
6444 sp++;
6445 ++ip;
6446 MINT_IN_BREAK;
6447 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
6448 ++ip;
6449 mono_memory_barrier ();
6450 MINT_IN_BREAK;
6452 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
6453 sp->data.p = mono_domain_get ();
6454 ++sp;
6455 ++ip;
6456 MINT_IN_BREAK;
6457 MINT_IN_CASE(MINT_MONO_GET_SP)
6458 sp->data.p = &frame;
6459 ++sp;
6460 ++ip;
6461 MINT_IN_BREAK;
6462 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6463 if (G_UNLIKELY (ss_enabled)) {
6464 typedef void (*T) (void);
6465 static T ss_tramp;
6467 if (!ss_tramp) {
6468 void *tramp = mini_get_single_step_trampoline ();
6469 mono_memory_barrier ();
6470 ss_tramp = (T)tramp;
6474 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6475 * the address of that instruction is stored as the seq point address.
6477 frame->ip = ip + 1;
6480 * Use the same trampoline as the JIT. This ensures that
6481 * the debugger has the context for the last interpreter
6482 * native frame.
6484 do_debugger_tramp (ss_tramp, frame);
6486 CHECK_RESUME_STATE (context);
6488 ++ip;
6489 MINT_IN_BREAK;
6490 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6491 /* Just a placeholder for a breakpoint */
6492 ++ip;
6493 MINT_IN_BREAK;
6494 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6495 typedef void (*T) (void);
6496 static T bp_tramp;
6497 if (!bp_tramp) {
6498 void *tramp = mini_get_breakpoint_trampoline ();
6499 mono_memory_barrier ();
6500 bp_tramp = (T)tramp;
6503 frame->ip = ip;
6505 /* Use the same trampoline as the JIT */
6506 do_debugger_tramp (bp_tramp, frame);
6508 CHECK_RESUME_STATE (context);
6510 ++ip;
6511 MINT_IN_BREAK;
6514 #define RELOP(datamem, op) \
6515 --sp; \
6516 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6517 ++ip;
6519 #define RELOP_FP(datamem, op, noorder) \
6520 --sp; \
6521 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6522 sp [-1].data.i = noorder; \
6523 else \
6524 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6525 ++ip;
6527 MINT_IN_CASE(MINT_CEQ_I4)
6528 RELOP(i, ==);
6529 MINT_IN_BREAK;
6530 MINT_IN_CASE(MINT_CEQ0_I4)
6531 sp [-1].data.i = (sp [-1].data.i == 0);
6532 ++ip;
6533 MINT_IN_BREAK;
6534 MINT_IN_CASE(MINT_CEQ_I8)
6535 RELOP(l, ==);
6536 MINT_IN_BREAK;
6537 MINT_IN_CASE(MINT_CEQ_R4)
6538 RELOP_FP(f_r4, ==, 0);
6539 MINT_IN_BREAK;
6540 MINT_IN_CASE(MINT_CEQ_R8)
6541 RELOP_FP(f, ==, 0);
6542 MINT_IN_BREAK;
6543 MINT_IN_CASE(MINT_CNE_I4)
6544 RELOP(i, !=);
6545 MINT_IN_BREAK;
6546 MINT_IN_CASE(MINT_CNE_I8)
6547 RELOP(l, !=);
6548 MINT_IN_BREAK;
6549 MINT_IN_CASE(MINT_CNE_R4)
6550 RELOP_FP(f_r4, !=, 1);
6551 MINT_IN_BREAK;
6552 MINT_IN_CASE(MINT_CNE_R8)
6553 RELOP_FP(f, !=, 1);
6554 MINT_IN_BREAK;
6555 MINT_IN_CASE(MINT_CGT_I4)
6556 RELOP(i, >);
6557 MINT_IN_BREAK;
6558 MINT_IN_CASE(MINT_CGT_I8)
6559 RELOP(l, >);
6560 MINT_IN_BREAK;
6561 MINT_IN_CASE(MINT_CGT_R4)
6562 RELOP_FP(f_r4, >, 0);
6563 MINT_IN_BREAK;
6564 MINT_IN_CASE(MINT_CGT_R8)
6565 RELOP_FP(f, >, 0);
6566 MINT_IN_BREAK;
6567 MINT_IN_CASE(MINT_CGE_I4)
6568 RELOP(i, >=);
6569 MINT_IN_BREAK;
6570 MINT_IN_CASE(MINT_CGE_I8)
6571 RELOP(l, >=);
6572 MINT_IN_BREAK;
6573 MINT_IN_CASE(MINT_CGE_R4)
6574 RELOP_FP(f_r4, >=, 0);
6575 MINT_IN_BREAK;
6576 MINT_IN_CASE(MINT_CGE_R8)
6577 RELOP_FP(f, >=, 0);
6578 MINT_IN_BREAK;
6580 #define RELOP_CAST(datamem, op, type) \
6581 --sp; \
6582 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6583 ++ip;
6585 MINT_IN_CASE(MINT_CGE_UN_I4)
6586 RELOP_CAST(l, >=, guint32);
6587 MINT_IN_BREAK;
6588 MINT_IN_CASE(MINT_CGE_UN_I8)
6589 RELOP_CAST(l, >=, guint64);
6590 MINT_IN_BREAK;
6592 MINT_IN_CASE(MINT_CGT_UN_I4)
6593 RELOP_CAST(i, >, guint32);
6594 MINT_IN_BREAK;
6595 MINT_IN_CASE(MINT_CGT_UN_I8)
6596 RELOP_CAST(l, >, guint64);
6597 MINT_IN_BREAK;
6598 MINT_IN_CASE(MINT_CGT_UN_R4)
6599 RELOP_FP(f_r4, >, 1);
6600 MINT_IN_BREAK;
6601 MINT_IN_CASE(MINT_CGT_UN_R8)
6602 RELOP_FP(f, >, 1);
6603 MINT_IN_BREAK;
6604 MINT_IN_CASE(MINT_CLT_I4)
6605 RELOP(i, <);
6606 MINT_IN_BREAK;
6607 MINT_IN_CASE(MINT_CLT_I8)
6608 RELOP(l, <);
6609 MINT_IN_BREAK;
6610 MINT_IN_CASE(MINT_CLT_R4)
6611 RELOP_FP(f_r4, <, 0);
6612 MINT_IN_BREAK;
6613 MINT_IN_CASE(MINT_CLT_R8)
6614 RELOP_FP(f, <, 0);
6615 MINT_IN_BREAK;
6616 MINT_IN_CASE(MINT_CLT_UN_I4)
6617 RELOP_CAST(i, <, guint32);
6618 MINT_IN_BREAK;
6619 MINT_IN_CASE(MINT_CLT_UN_I8)
6620 RELOP_CAST(l, <, guint64);
6621 MINT_IN_BREAK;
6622 MINT_IN_CASE(MINT_CLT_UN_R4)
6623 RELOP_FP(f_r4, <, 1);
6624 MINT_IN_BREAK;
6625 MINT_IN_CASE(MINT_CLT_UN_R8)
6626 RELOP_FP(f, <, 1);
6627 MINT_IN_BREAK;
6628 MINT_IN_CASE(MINT_CLE_I4)
6629 RELOP(i, <=);
6630 MINT_IN_BREAK;
6631 MINT_IN_CASE(MINT_CLE_I8)
6632 RELOP(l, <=);
6633 MINT_IN_BREAK;
6634 MINT_IN_CASE(MINT_CLE_UN_I4)
6635 RELOP_CAST(l, <=, guint32);
6636 MINT_IN_BREAK;
6637 MINT_IN_CASE(MINT_CLE_UN_I8)
6638 RELOP_CAST(l, <=, guint64);
6639 MINT_IN_BREAK;
6640 MINT_IN_CASE(MINT_CLE_R4)
6641 RELOP_FP(f_r4, <=, 0);
6642 MINT_IN_BREAK;
6643 MINT_IN_CASE(MINT_CLE_R8)
6644 RELOP_FP(f, <=, 0);
6645 MINT_IN_BREAK;
6647 #undef RELOP
6648 #undef RELOP_FP
6649 #undef RELOP_CAST
6651 MINT_IN_CASE(MINT_LDFTN) {
6652 sp->data.p = frame->imethod->data_items [ip [1]];
6653 ++sp;
6654 ip += 2;
6655 MINT_IN_BREAK;
6657 MINT_IN_CASE(MINT_LDVIRTFTN) {
6658 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [1]];
6659 --sp;
6660 NULL_CHECK (sp->data.p);
6662 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6663 ip += 2;
6664 ++sp;
6665 MINT_IN_BREAK;
6667 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6668 error_init_reuse (error);
6669 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6670 mono_error_assert_ok (error);
6671 sp [-1].data.p = m;
6672 ip++;
6673 MINT_IN_BREAK;
6676 #define LDARG(datamem, argtype) \
6677 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6678 ip += 2; \
6679 ++sp;
6681 #define LDARGn(datamem, argtype, n) \
6682 sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \
6683 ++ip; \
6684 ++sp;
6686 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6687 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6688 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6689 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6690 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6691 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6692 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6693 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6694 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6695 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6697 MINT_IN_CASE(MINT_LDARG_P0) LDARGn(p, gpointer, 0); MINT_IN_BREAK;
6699 MINT_IN_CASE(MINT_LDARG_VT) {
6700 sp->data.p = vt_sp;
6701 int const i32 = READ32 (ip + 2);
6702 memcpy(sp->data.p, frame->stack_args [ip [1]].data.p, i32);
6703 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6704 ip += 4;
6705 ++sp;
6706 MINT_IN_BREAK;
6709 #define STARG(datamem, argtype) \
6710 --sp; \
6711 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6712 ip += 2; \
6714 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6715 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6716 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6717 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6718 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6719 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6720 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6721 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6722 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6723 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6725 MINT_IN_CASE(MINT_STARG_VT) {
6726 int const i32 = READ32 (ip + 2);
6727 --sp;
6728 memcpy(frame->stack_args [ip [1]].data.p, sp->data.p, i32);
6729 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6730 ip += 4;
6731 MINT_IN_BREAK;
6734 MINT_IN_CASE(MINT_PROF_ENTER) {
6735 guint16 flag = ip [1];
6736 ip += 2;
6738 if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter) &&
6739 (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT))) {
6740 MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6741 prof_ctx->interp_frame = frame;
6742 prof_ctx->method = frame->imethod->method;
6743 if (flag & TRACING_FLAG)
6744 mono_trace_enter_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx);
6745 if (flag & PROFILING_FLAG)
6746 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6747 g_free (prof_ctx);
6748 } else if ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter)) {
6749 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, NULL));
6751 MINT_IN_BREAK;
6754 MINT_IN_CASE(MINT_PROF_EXIT)
6755 MINT_IN_CASE(MINT_PROF_EXIT_VOID) {
6756 guint16 flag = ip [1];
6757 // Set retval
6758 int const i32 = READ32 (ip + 2);
6759 if (i32 == -1) {
6760 } else if (i32) {
6761 sp--;
6762 memcpy(frame->retval->data.p, sp->data.p, i32);
6763 } else {
6764 sp--;
6765 *frame->retval = *sp;
6768 if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_leave) &&
6769 (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT))) {
6770 MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6771 prof_ctx->interp_frame = frame;
6772 prof_ctx->method = frame->imethod->method;
6773 if (i32 != -1) {
6774 if (i32)
6775 prof_ctx->return_value = frame->retval->data.p;
6776 else
6777 prof_ctx->return_value = frame->retval;
6779 if (flag & TRACING_FLAG)
6780 mono_trace_leave_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx);
6781 if (flag & PROFILING_FLAG)
6782 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6783 g_free (prof_ctx);
6784 } else if ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter)) {
6785 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, NULL));
6788 ip += 4;
6789 goto exit_frame;
6792 MINT_IN_CASE(MINT_LDARGA)
6793 sp->data.p = &frame->stack_args [ip [1]];
6794 ip += 2;
6795 ++sp;
6796 MINT_IN_BREAK;
6798 MINT_IN_CASE(MINT_LDARGA_VT)
6799 sp->data.p = frame->stack_args [ip [1]].data.p;
6800 ip += 2;
6801 ++sp;
6802 MINT_IN_BREAK;
6804 #define LDLOC(datamem, argtype) \
6805 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6806 ip += 2; \
6807 ++sp;
6809 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6810 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6811 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6812 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6813 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6814 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6815 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6816 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6817 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6818 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6820 MINT_IN_CASE(MINT_LDLOC_VT) {
6821 sp->data.p = vt_sp;
6822 int const i32 = READ32 (ip + 2);
6823 memcpy(sp->data.p, locals + ip [1], i32);
6824 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6825 ip += 4;
6826 ++sp;
6827 MINT_IN_BREAK;
6829 MINT_IN_CASE(MINT_LDLOCA_S)
6830 sp->data.p = locals + ip [1];
6831 ip += 2;
6832 ++sp;
6833 MINT_IN_BREAK;
6835 #define STLOC(datamem, argtype) \
6836 --sp; \
6837 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6838 ip += 2;
6840 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6841 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6842 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6843 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6844 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6845 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6846 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6847 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6848 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6849 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6851 #define STLOC_NP(datamem, argtype) \
6852 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6853 ip += 2;
6855 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6856 MINT_IN_CASE(MINT_STLOC_NP_I8) STLOC_NP(l, gint64); MINT_IN_BREAK;
6857 MINT_IN_CASE(MINT_STLOC_NP_R4) STLOC_NP(f_r4, float); MINT_IN_BREAK;
6858 MINT_IN_CASE(MINT_STLOC_NP_R8) STLOC_NP(f, double); MINT_IN_BREAK;
6859 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6861 MINT_IN_CASE(MINT_STLOC_VT) {
6862 int const i32 = READ32 (ip + 2);
6863 --sp;
6864 memcpy(locals + ip [1], sp->data.p, i32);
6865 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6866 ip += 4;
6867 MINT_IN_BREAK;
6870 #define MOVLOC(argtype) \
6871 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6872 ip += 3;
6874 MINT_IN_CASE(MINT_MOVLOC_1) MOVLOC(guint8); MINT_IN_BREAK;
6875 MINT_IN_CASE(MINT_MOVLOC_2) MOVLOC(guint16); MINT_IN_BREAK;
6876 MINT_IN_CASE(MINT_MOVLOC_4) MOVLOC(guint32); MINT_IN_BREAK;
6877 MINT_IN_CASE(MINT_MOVLOC_8) MOVLOC(guint64); MINT_IN_BREAK;
6879 MINT_IN_CASE(MINT_MOVLOC_VT) {
6880 int const i32 = READ32(ip + 3);
6881 memcpy (locals + ip [2], locals + ip [1], i32);
6882 ip += 5;
6883 MINT_IN_BREAK;
6886 MINT_IN_CASE(MINT_LOCALLOC) {
6887 if (sp != frame->stack + 1) /*FIX?*/
6888 goto abort_label;
6890 int len = sp [-1].data.i;
6891 //sp [-1].data.p = alloca (len);
6892 sp [-1].data.p = alloc_extra_stack_data (context, ALIGN_TO (len, 8));
6894 if (frame->imethod->init_locals)
6895 memset (sp [-1].data.p, 0, len);
6896 ++ip;
6897 MINT_IN_BREAK;
6899 MINT_IN_CASE(MINT_ENDFILTER)
6900 /* top of stack is result of filter */
6901 frame->retval->data.i = sp [-1].data.i;
6902 goto exit_frame;
6903 MINT_IN_CASE(MINT_INITOBJ)
6904 --sp;
6905 memset (sp->data.vt, 0, READ32(ip + 1));
6906 ip += 3;
6907 MINT_IN_BREAK;
6908 MINT_IN_CASE(MINT_CPBLK)
6909 sp -= 3;
6910 if (!sp [0].data.p || !sp [1].data.p)
6911 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6912 ++ip;
6913 /* FIXME: value and size may be int64... */
6914 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6915 MINT_IN_BREAK;
6916 #if 0
6917 MINT_IN_CASE(MINT_CONSTRAINED_) {
6918 guint32 token;
6919 /* FIXME: implement */
6920 ++ip;
6921 token = READ32 (ip);
6922 ip += 2;
6923 MINT_IN_BREAK;
6925 #endif
6926 MINT_IN_CASE(MINT_INITBLK)
6927 sp -= 3;
6928 NULL_CHECK (sp [0].data.p);
6929 ++ip;
6930 /* FIXME: value and size may be int64... */
6931 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6932 MINT_IN_BREAK;
6933 #if 0
6934 MINT_IN_CASE(MINT_NO_)
6935 /* FIXME: implement */
6936 ip += 2;
6937 MINT_IN_BREAK;
6938 #endif
6939 MINT_IN_CASE(MINT_RETHROW) {
6940 int exvar_offset = ip [1];
6941 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6942 MINT_IN_BREAK;
6944 MINT_IN_CASE(MINT_MONO_RETHROW) {
6946 * need to clarify what this should actually do:
6948 * Takes an exception from the stack and rethrows it.
6949 * This is useful for wrappers that don't want to have to
6950 * use CEE_THROW and lose the exception stacktrace.
6953 --sp;
6954 if (!sp->data.p)
6955 sp->data.p = mono_get_exception_null_reference ();
6957 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6958 MINT_IN_BREAK;
6960 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6961 MonoDelegate *del;
6963 --sp;
6964 del = (MonoDelegate*)sp->data.p;
6965 if (!del->interp_method) {
6966 /* Not created from interpreted code */
6967 error_init_reuse (error);
6968 g_assert (del->method);
6969 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6970 mono_error_assert_ok (error);
6972 g_assert (del->interp_method);
6973 sp->data.p = del->interp_method;
6974 ++sp;
6975 ip += 1;
6976 MINT_IN_BREAK;
6978 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6979 MonoDelegate *del;
6980 int n = ip [1];
6981 del = (MonoDelegate*)sp [-n].data.p;
6982 if (!del->interp_invoke_impl) {
6984 * First time we are called. Set up the invoke wrapper. We might be able to do this
6985 * in ctor but we would need to handle AllocDelegateLike_internal separately
6987 error_init_reuse (error);
6988 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6989 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6990 mono_error_assert_ok (error);
6992 sp ++;
6993 sp [-1].data.p = del->interp_invoke_impl;
6994 ip += 2;
6995 MINT_IN_BREAK;
6998 #define MATH_UNOP(mathfunc) \
6999 sp [-1].data.f = mathfunc (sp [-1].data.f); \
7000 ++ip;
7002 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
7003 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
7004 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
7005 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
7006 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
7007 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
7008 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
7009 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
7010 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
7011 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
7012 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
7013 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
7014 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
7015 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
7016 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
7018 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
7019 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]];
7020 mono_interp_enum_hasflag (sp, klass);
7021 sp--;
7022 ip += 2;
7023 MINT_IN_BREAK;
7025 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
7026 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
7027 ip++;
7028 MINT_IN_BREAK;
7030 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
7031 NULL_CHECK (sp [-1].data.p);
7032 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
7033 ip++;
7034 MINT_IN_BREAK;
7037 #if !USE_COMPUTED_GOTO
7038 default:
7039 g_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code);
7040 #endif
7044 g_assert_not_reached ();
7046 abort_label:
7047 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
7048 null_label:
7049 THROW_EX (mono_get_exception_null_reference (), ip);
7050 div_zero_label:
7051 THROW_EX (mono_get_exception_divide_by_zero (), ip);
7052 overflow_label:
7053 THROW_EX (mono_get_exception_overflow (), ip);
7054 throw_error_label:
7055 THROW_EX (mono_error_convert_to_exception (error), ip);
7056 invalid_cast_label:
7057 THROW_EX (mono_get_exception_invalid_cast (), ip);
7058 resume:
7059 g_assert (context->has_resume_state);
7060 g_assert (frame->imethod);
7062 if (frame == context->handler_frame && (!clause_args || context->handler_ip < clause_args->end_at_ip)) {
7063 /* Set the current execution state to the resume state in context */
7065 ip = context->handler_ip;
7066 /* spec says stack should be empty at endfinally so it should be at the start too */
7067 sp = frame->stack;
7068 vt_sp = (guchar*)sp + frame->imethod->stack_size;
7069 g_assert (context->exc_gchandle);
7070 sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle);
7071 ++sp;
7073 finally_ips = clear_resume_state (context, finally_ips);
7074 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
7075 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
7076 goto main_loop;
7078 // fall through
7079 exit_frame:
7080 error_init_reuse (error);
7082 g_assert (frame->imethod);
7084 if (clause_args && clause_args->base_frame) {
7085 // We finished executing a filter. The execution stack of the base frame
7086 // should remain unmodified, but we need to update the local space.
7087 char *locals_base = (char*)clause_args->base_frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size;
7089 memcpy (locals_base, locals, frame->imethod->locals_size);
7092 if (!clause_args && frame->parent && frame->parent->state.ip) {
7093 /* Return to the main loop after a non-recursive interpreter call */
7094 //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);
7095 stackval *retval = frame->retval;
7097 InterpFrame *child_frame = frame;
7099 frame = frame->parent;
7100 LOAD_INTERP_STATE (frame);
7102 pop_frame (context, child_frame);
7104 CHECK_RESUME_STATE (context);
7106 if (!is_void) {
7107 *sp = *retval;
7108 sp ++;
7110 goto main_loop;
7113 if (!clause_args)
7114 pop_frame (context, frame);
7116 DEBUG_LEAVE ();
7119 static void
7120 interp_parse_options (const char *options)
7122 char **args, **ptr;
7124 if (!options)
7125 return;
7127 args = g_strsplit (options, ",", -1);
7128 for (ptr = args; ptr && *ptr; ptr ++) {
7129 char *arg = *ptr;
7131 if (strncmp (arg, "jit=", 4) == 0)
7132 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
7133 else if (strncmp (arg, "interp-only=", strlen ("interp-only=")) == 0)
7134 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
7135 else if (strncmp (arg, "-inline", 7) == 0)
7136 mono_interp_opt &= ~INTERP_OPT_INLINE;
7137 else if (strncmp (arg, "-cprop", 6) == 0)
7138 mono_interp_opt &= ~INTERP_OPT_CPROP;
7139 else if (strncmp (arg, "-super", 6) == 0)
7140 mono_interp_opt &= ~INTERP_OPT_SUPER_INSTRUCTIONS;
7141 else if (strncmp (arg, "-all", 4) == 0)
7142 mono_interp_opt = INTERP_OPT_NONE;
7147 * interp_set_resume_state:
7149 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
7151 static void
7152 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoObject *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
7154 ThreadContext *context;
7156 g_assert (jit_tls);
7157 context = (ThreadContext*)jit_tls->interp_context;
7158 g_assert (context);
7160 context->has_resume_state = TRUE;
7161 context->handler_frame = (InterpFrame*)interp_frame;
7162 context->handler_ei = ei;
7163 if (context->exc_gchandle)
7164 mono_gchandle_free_internal (context->exc_gchandle);
7165 context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
7166 /* Ditto */
7167 if (ei)
7168 *(MonoObject**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
7169 context->handler_ip = (const guint16*)handler_ip;
7172 static void
7173 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
7175 g_assert (jit_tls);
7176 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
7178 *has_resume_state = context ? context->has_resume_state : FALSE;
7179 if (!*has_resume_state)
7180 return;
7182 *interp_frame = context->handler_frame;
7183 *handler_ip = (gpointer)context->handler_ip;
7187 * interp_run_finally:
7189 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
7190 * frame->interp_frame.
7191 * Return TRUE if the finally clause threw an exception.
7193 static gboolean
7194 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
7196 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
7197 ThreadContext *context = get_context ();
7198 const unsigned short *old_ip = iframe->ip;
7199 FrameClauseArgs clause_args;
7200 const guint16 *saved_ip;
7202 memset (&clause_args, 0, sizeof (FrameClauseArgs));
7203 clause_args.start_with_ip = (const guint16*)handler_ip;
7204 clause_args.end_at_ip = (const guint16*)handler_ip_end;
7205 clause_args.exit_clause = clause_index;
7207 saved_ip = iframe->state.ip;
7208 iframe->state.ip = NULL;
7210 ERROR_DECL (error);
7211 interp_exec_method_full (iframe, context, &clause_args, error);
7212 iframe->state.ip = saved_ip;
7213 iframe->state.clause_args = NULL;
7214 if (context->has_resume_state) {
7215 return TRUE;
7216 } else {
7217 iframe->ip = old_ip;
7218 return FALSE;
7223 * interp_run_filter:
7225 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
7226 * frame->interp_frame.
7228 static gboolean
7229 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
7231 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
7232 ThreadContext *context = get_context ();
7233 InterpFrame *child_frame;
7234 stackval retval;
7235 FrameClauseArgs clause_args;
7238 * Have to run the clause in a new frame which is a copy of IFRAME, since
7239 * during debugging, there are two copies of the frame on the stack.
7241 child_frame = alloc_frame (context, &retval, iframe, iframe->imethod, iframe->stack_args, &retval);
7243 memset (&clause_args, 0, sizeof (FrameClauseArgs));
7244 clause_args.start_with_ip = (const guint16*)handler_ip;
7245 clause_args.end_at_ip = (const guint16*)handler_ip_end;
7246 clause_args.filter_exception = ex;
7247 clause_args.base_frame = iframe;
7249 ERROR_DECL (error);
7250 interp_exec_method_full (child_frame, context, &clause_args, error);
7251 /* ENDFILTER stores the result into child_frame->retval */
7252 return retval.data.i ? TRUE : FALSE;
7255 typedef struct {
7256 InterpFrame *current;
7257 } StackIter;
7260 * interp_frame_iter_init:
7262 * Initialize an iterator for iterating through interpreted frames.
7264 static void
7265 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
7267 StackIter *stack_iter = (StackIter*)iter;
7269 stack_iter->current = (InterpFrame*)interp_exit_data;
7273 * interp_frame_iter_next:
7275 * Fill out FRAME with date for the next interpreter frame.
7277 static gboolean
7278 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
7280 StackIter *stack_iter = (StackIter*)iter;
7281 InterpFrame *iframe = stack_iter->current;
7283 memset (frame, 0, sizeof (StackFrameInfo));
7284 /* pinvoke frames doesn't have imethod set */
7285 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
7286 iframe = iframe->parent;
7287 if (!iframe)
7288 return FALSE;
7290 MonoMethod *method = iframe->imethod->method;
7291 frame->domain = iframe->imethod->domain;
7292 frame->interp_frame = iframe;
7293 frame->method = method;
7294 frame->actual_method = method;
7295 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
7296 frame->native_offset = -1;
7297 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
7298 } else {
7299 frame->type = FRAME_TYPE_INTERP;
7300 /* This is the offset in the interpreter IR */
7301 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
7302 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
7303 frame->managed = TRUE;
7305 frame->ji = iframe->imethod->jinfo;
7306 frame->frame_addr = iframe->native_stack_addr;
7308 stack_iter->current = iframe->parent;
7310 return TRUE;
7313 static MonoJitInfo*
7314 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
7316 InterpMethod* imethod;
7318 imethod = lookup_imethod (domain, method);
7319 if (imethod)
7320 return imethod->jinfo;
7321 else
7322 return NULL;
7325 static void
7326 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
7328 guint16 *code = (guint16*)ip;
7329 g_assert (*code == MINT_SDB_SEQ_POINT);
7330 *code = MINT_SDB_BREAKPOINT;
7333 static void
7334 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
7336 guint16 *code = (guint16*)ip;
7337 g_assert (*code == MINT_SDB_BREAKPOINT);
7338 *code = MINT_SDB_SEQ_POINT;
7341 static MonoJitInfo*
7342 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
7344 InterpFrame *iframe = (InterpFrame*)frame;
7346 g_assert (iframe->imethod);
7347 return iframe->imethod->jinfo;
7350 static gpointer
7351 interp_frame_get_ip (MonoInterpFrameHandle frame)
7353 InterpFrame *iframe = (InterpFrame*)frame;
7355 g_assert (iframe->imethod);
7356 return (gpointer)iframe->ip;
7359 static gpointer
7360 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
7362 InterpFrame *iframe = (InterpFrame*)frame;
7363 MonoMethodSignature *sig;
7365 g_assert (iframe->imethod);
7367 sig = mono_method_signature_internal (iframe->imethod->method);
7368 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
7371 static gpointer
7372 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
7374 InterpFrame *iframe = (InterpFrame*)frame;
7376 g_assert (iframe->imethod);
7378 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
7381 static gpointer
7382 interp_frame_get_this (MonoInterpFrameHandle frame)
7384 InterpFrame *iframe = (InterpFrame*)frame;
7386 g_assert (iframe->imethod);
7387 g_assert (iframe->imethod->hasthis);
7388 return &iframe->stack_args [0].data.p;
7391 static MonoInterpFrameHandle
7392 interp_frame_get_parent (MonoInterpFrameHandle frame)
7394 InterpFrame *iframe = (InterpFrame*)frame;
7396 return iframe->parent;
7399 static gpointer
7400 interp_frame_get_res (MonoInterpFrameHandle frame)
7402 InterpFrame *iframe = (InterpFrame*)frame;
7403 MonoMethodSignature *sig;
7405 g_assert (iframe->imethod);
7406 sig = mono_method_signature_internal (iframe->imethod->method);
7407 if (sig->ret->type == MONO_TYPE_VOID)
7408 return NULL;
7409 else
7410 return stackval_to_data_addr (sig->ret, iframe->retval);
7413 static gpointer
7414 interp_frame_get_native_stack_addr (MonoInterpFrameHandle frame)
7416 InterpFrame *iframe = (InterpFrame*)frame;
7418 return iframe->native_stack_addr;
7421 static void
7422 interp_start_single_stepping (void)
7424 ss_enabled = TRUE;
7427 static void
7428 interp_stop_single_stepping (void)
7430 ss_enabled = FALSE;
7434 * interp_mark_stack:
7436 * Mark the interpreter stack frames for a thread.
7439 static void
7440 interp_mark_stack (gpointer thread_data, GcScanFunc func, gpointer gc_data, gboolean precise)
7442 MonoThreadInfo *info = (MonoThreadInfo*)thread_data;
7444 if (!mono_use_interpreter)
7445 return;
7446 if (precise)
7447 return;
7450 * We explicitly mark the frames instead of registering the stack fragments as GC roots, so
7451 * we have to process less data and avoid false pinning from data which is above 'pos'.
7453 * The stack frame handling code uses compiler write barriers only, but the calling code
7454 * in sgen-mono.c already did a mono_memory_barrier_process_wide () so we can
7455 * process these data structures normally.
7457 MonoJitTlsData *jit_tls = (MonoJitTlsData *)info->tls [TLS_KEY_JIT_TLS];
7458 if (!jit_tls)
7459 return;
7461 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
7462 if (!context || !context->data_stack.inited)
7463 return;
7465 StackFragment *frag;
7466 for (frag = context->data_stack.first; frag; frag = frag->next) {
7467 // FIXME: Scan the whole area with 1 call
7468 for (gpointer *p = (gpointer*)&frag->data; p < (gpointer*)frag->pos; ++p)
7469 func (p, gc_data);
7470 if (frag == context->data_stack.current)
7471 break;
7475 #if COUNT_OPS
7477 static int
7478 opcode_count_comparer (const void * pa, const void * pb)
7480 long counta = opcode_counts [*(int*)pa];
7481 long countb = opcode_counts [*(int*)pb];
7483 if (counta < countb)
7484 return 1;
7485 else if (counta > countb)
7486 return -1;
7487 else
7488 return 0;
7491 static void
7492 interp_print_op_count (void)
7494 int ordered_ops [MINT_LASTOP];
7495 int i;
7496 long total_ops = 0;
7498 for (i = 0; i < MINT_LASTOP; i++) {
7499 ordered_ops [i] = i;
7500 total_ops += opcode_counts [i];
7502 qsort (ordered_ops, MINT_LASTOP, sizeof (int), opcode_count_comparer);
7504 for (i = 0; i < MINT_LASTOP; i++) {
7505 long count = opcode_counts [ordered_ops [i]];
7506 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops [i]), count, (double)count / total_ops * 100);
7509 #endif
7511 static void
7512 interp_set_optimizations (guint32 opts)
7514 mono_interp_opt = opts;
7517 static void
7518 invalidate_transform (gpointer imethod_)
7520 InterpMethod *imethod = (InterpMethod *) imethod_;
7521 imethod->transformed = FALSE;
7524 static void
7525 interp_invalidate_transformed (MonoDomain *domain)
7527 MonoJitDomainInfo *info = domain_jit_info (domain);
7528 mono_domain_jit_code_hash_lock (domain);
7529 mono_internal_hash_table_apply (&info->interp_code_hash, invalidate_transform);
7530 mono_domain_jit_code_hash_unlock (domain);
7533 static void
7534 interp_cleanup (void)
7536 #if COUNT_OPS
7537 interp_print_op_count ();
7538 #endif
7541 static void
7542 register_interp_stats (void)
7544 mono_counters_init ();
7545 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
7546 mono_counters_register ("Methods transformed", MONO_COUNTER_INTERP | MONO_COUNTER_LONG, &mono_interp_stats.methods_transformed);
7547 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.cprop_time);
7548 mono_counters_register ("Total super instructions time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.super_instructions_time);
7549 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.stloc_nps);
7550 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.movlocs);
7551 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.copy_propagations);
7552 mono_counters_register ("Added pop count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.added_pop_count);
7553 mono_counters_register ("Constant folds", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.constant_folds);
7554 mono_counters_register ("Super instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.super_instructions);
7555 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.killed_instructions);
7556 mono_counters_register ("Emitted instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.emitted_instructions);
7557 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
7558 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
7561 #undef MONO_EE_CALLBACK
7562 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
7564 static const MonoEECallbacks mono_interp_callbacks = {
7565 MONO_EE_CALLBACKS
7568 void
7569 mono_ee_interp_init (const char *opts)
7571 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
7572 g_assert (!interp_init_done);
7573 interp_init_done = TRUE;
7575 mono_native_tls_alloc (&thread_context_id, NULL);
7576 set_context (NULL);
7578 interp_parse_options (opts);
7579 /* Don't do any optimizations if running under debugger */
7580 if (mini_get_debug_options ()->mdb_optimizations)
7581 mono_interp_opt = 0;
7582 mono_interp_transform_init ();
7584 mini_install_interp_callbacks (&mono_interp_callbacks);
7586 register_interp_stats ();