[mono] Introduce MonoMemoryManager to hold memory previously owned by the domain...
[mono-project.git] / mono / mini / interp / interp.c
blob555ea5af0f1aaa66a6f3829f3cff36cf01056916
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"
66 #include "interp-intrins.h"
68 #include <mono/mini/mini.h>
69 #include <mono/mini/mini-runtime.h>
70 #include <mono/mini/aot-runtime.h>
71 #include <mono/mini/llvm-runtime.h>
72 #include <mono/mini/llvmonly-runtime.h>
73 #include <mono/mini/jit-icalls.h>
74 #include <mono/mini/debugger-agent.h>
75 #include <mono/mini/ee.h>
76 #include <mono/mini/trace.h>
78 #ifdef TARGET_ARM
79 #include <mono/mini/mini-arm.h>
80 #endif
81 #include <mono/metadata/icall-decl.h>
83 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
84 struct FrameClauseArgs {
85 /* Where we start the frame execution from */
86 const guint16 *start_with_ip;
88 * End ip of the exit_clause. We need it so we know whether the resume
89 * state is for this frame (which is called from EH) or for the original
90 * frame further down the stack.
92 const guint16 *end_at_ip;
93 /* When exiting this clause we also exit the frame */
94 int exit_clause;
95 /* Exception that we are filtering */
96 MonoException *filter_exception;
97 /* Frame that is executing this clause */
98 InterpFrame *exec_frame;
102 * This code synchronizes with interp_mark_stack () using compiler memory barriers.
105 static FrameDataFragment*
106 frame_data_frag_new (int size)
108 FrameDataFragment *frag = (FrameDataFragment*)g_malloc (size);
110 frag->pos = (guint8*)&frag->data;
111 frag->end = (guint8*)frag + size;
112 frag->next = NULL;
113 return frag;
116 static void
117 frame_data_frag_free (FrameDataFragment *frag)
119 while (frag) {
120 FrameDataFragment *next = frag->next;
121 g_free (frag);
122 frag = next;
126 static void
127 frame_data_allocator_init (FrameDataAllocator *stack, int size)
129 FrameDataFragment *frag;
131 frag = frame_data_frag_new (size);
132 stack->first = stack->current = frag;
133 stack->infos_capacity = 4;
134 stack->infos = g_malloc (stack->infos_capacity * sizeof (FrameDataInfo));
137 static void
138 frame_data_allocator_free (FrameDataAllocator *stack)
140 /* Assert to catch leaks */
141 g_assert_checked (stack->current == stack->first && stack->current->pos == (guint8*)&stack->current->data);
142 frame_data_frag_free (stack->first);
145 static FrameDataFragment*
146 frame_data_allocator_add_frag (FrameDataAllocator *stack, int size)
148 FrameDataFragment *new_frag;
150 // FIXME:
151 int frag_size = 4096;
152 if (size + sizeof (FrameDataFragment) > frag_size)
153 frag_size = size + sizeof (FrameDataFragment);
154 new_frag = frame_data_frag_new (frag_size);
155 mono_compiler_barrier ();
156 stack->current->next = new_frag;
157 stack->current = new_frag;
158 return new_frag;
161 static gpointer
162 frame_data_allocator_alloc (FrameDataAllocator *stack, InterpFrame *frame, int size)
164 FrameDataFragment *current = stack->current;
165 gpointer res;
167 int infos_len = stack->infos_len;
169 if (!infos_len || (infos_len > 0 && stack->infos [infos_len - 1].frame != frame)) {
170 /* First allocation by this frame. Save the markers for restore */
171 if (infos_len == stack->infos_capacity) {
172 stack->infos_capacity = infos_len * 2;
173 stack->infos = g_realloc (stack->infos, stack->infos_capacity * sizeof (FrameDataInfo));
175 stack->infos [infos_len].frame = frame;
176 stack->infos [infos_len].frag = current;
177 stack->infos [infos_len].pos = current->pos;
178 stack->infos_len++;
181 if (G_LIKELY (current->pos + size <= current->end)) {
182 res = current->pos;
183 current->pos += size;
184 } else {
185 if (current->next && current->next->pos + size <= current->next->end) {
186 current = stack->current = current->next;
187 current->pos = (guint8*)&current->data;
188 } else {
189 FrameDataFragment *tmp = current->next;
190 /* avoid linking to be freed fragments, so the GC can't trip over it */
191 current->next = NULL;
192 mono_compiler_barrier ();
193 frame_data_frag_free (tmp);
195 current = frame_data_allocator_add_frag (stack, size);
197 g_assert (current->pos + size <= current->end);
198 res = (gpointer)current->pos;
199 current->pos += size;
201 mono_compiler_barrier ();
202 return res;
205 static void
206 frame_data_allocator_pop (FrameDataAllocator *stack, InterpFrame *frame)
208 int infos_len = stack->infos_len;
210 if (infos_len > 0 && stack->infos [infos_len - 1].frame == frame) {
211 infos_len--;
212 stack->current = stack->infos [infos_len].frag;
213 stack->current->pos = stack->infos [infos_len].pos;
214 stack->infos_len = infos_len;
219 * reinit_frame:
221 * Reinitialize a frame.
223 static void
224 reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *sp)
226 frame->parent = parent;
227 frame->imethod = imethod;
228 frame->stack = sp;
229 frame->state.ip = NULL;
233 * List of classes whose methods will be executed by transitioning to JITted code.
234 * Used for testing.
236 GSList *mono_interp_jit_classes;
237 /* Optimizations enabled with interpreter */
238 int mono_interp_opt = INTERP_OPT_DEFAULT;
239 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
240 static gboolean ss_enabled;
242 static gboolean interp_init_done = FALSE;
244 static void
245 interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args);
247 static MonoException* do_transform_method (InterpFrame *frame, ThreadContext *context);
249 static InterpMethod* lookup_method_pointer (gpointer addr);
251 typedef void (*ICallMethod) (InterpFrame *frame);
253 static MonoNativeTlsKey thread_context_id;
255 #define DEBUG_INTERP 0
256 #define COUNT_OPS 0
258 #if DEBUG_INTERP
259 int mono_interp_traceopt = 2;
260 /* If true, then we output the opcodes as we interpret them */
261 static int global_tracing = 2;
263 static int debug_indent_level = 0;
265 static int break_on_method = 0;
266 static int nested_trace = 0;
267 static GList *db_methods = NULL;
268 static char* dump_args (InterpFrame *inv);
270 static void
271 output_indent (void)
273 int h;
275 for (h = 0; h < debug_indent_level; h++)
276 g_print (" ");
279 static void
280 db_match_method (gpointer data, gpointer user_data)
282 MonoMethod *m = (MonoMethod*)user_data;
283 MonoMethodDesc *desc = (MonoMethodDesc*)data;
285 if (mono_method_desc_full_match (desc, m))
286 break_on_method = 1;
289 static void
290 debug_enter (InterpFrame *frame, int *tracing)
292 if (db_methods) {
293 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
294 if (break_on_method)
295 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
296 break_on_method = 0;
298 if (*tracing) {
299 MonoMethod *method = frame->imethod->method;
300 char *mn, *args = dump_args (frame);
301 debug_indent_level++;
302 output_indent ();
303 mn = mono_method_full_name (method, FALSE);
304 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
305 g_free (mn);
306 g_print ("%s)\n", args);
307 g_free (args);
311 #define DEBUG_LEAVE() \
312 if (tracing) { \
313 char *mn, *args; \
314 args = dump_retval (frame); \
315 output_indent (); \
316 mn = mono_method_full_name (frame->imethod->method, FALSE); \
317 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
318 g_free (mn); \
319 g_print (" => %s\n", args); \
320 g_free (args); \
321 debug_indent_level--; \
322 if (tracing == 3) global_tracing = 0; \
325 #else
327 int mono_interp_traceopt = 0;
328 #define DEBUG_LEAVE()
330 #endif
332 #if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP && !ENABLE_CHECKED_BUILD && !PROFILE_INTERP
333 #define USE_COMPUTED_GOTO 1
334 #endif
336 #if USE_COMPUTED_GOTO
338 #define MINT_IN_DISPATCH(op) goto *in_labels [opcode = (MintOpcode)(op)]
339 #define MINT_IN_SWITCH(op) MINT_IN_DISPATCH (op);
340 #define MINT_IN_BREAK MINT_IN_DISPATCH (*ip)
341 #define MINT_IN_CASE(x) LAB_ ## x:
343 #else
345 #define MINT_IN_SWITCH(op) COUNT_OP(op); switch (opcode = (MintOpcode)(op))
346 #define MINT_IN_CASE(x) case x:
347 #define MINT_IN_BREAK break
349 #endif
351 static GSList*
352 clear_resume_state (ThreadContext *context, GSList *finally_ips)
354 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
355 while (finally_ips &&
356 finally_ips->data >= context->handler_ei->try_start &&
357 finally_ips->data < context->handler_ei->try_end)
358 finally_ips = g_slist_remove (finally_ips, finally_ips->data);
359 context->has_resume_state = 0;
360 context->handler_frame = NULL;
361 context->handler_ei = NULL;
362 g_assert (context->exc_gchandle);
363 mono_gchandle_free_internal (context->exc_gchandle);
364 context->exc_gchandle = 0;
365 return finally_ips;
369 * If this bit is set, it means the call has thrown the exception, and we
370 * reached this point because the EH code in mono_handle_exception ()
371 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
372 * has set the fields in context to indicate where we have to resume execution.
374 #define CHECK_RESUME_STATE(context) do { \
375 if ((context)->has_resume_state) \
376 goto resume; \
377 } while (0)
379 static void
380 set_context (ThreadContext *context)
382 mono_native_tls_set_value (thread_context_id, context);
384 if (!context)
385 return;
387 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
388 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
390 /* jit_tls assumes ownership of 'context' */
391 jit_tls->interp_context = context;
394 static ThreadContext *
395 get_context (void)
397 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
398 if (context == NULL) {
399 context = g_new0 (ThreadContext, 1);
400 context->stack_start = (guchar*)mono_valloc (0, INTERP_STACK_SIZE, MONO_MMAP_READ | MONO_MMAP_WRITE, MONO_MEM_ACCOUNT_INTERP_STACK);
401 context->stack_pointer = context->stack_start;
403 frame_data_allocator_init (&context->data_stack, 8192);
404 /* Make sure all data is initialized before publishing the context */
405 mono_compiler_barrier ();
406 set_context (context);
408 return context;
411 static void
412 interp_free_context (gpointer ctx)
414 ThreadContext *context = (ThreadContext*)ctx;
416 mono_vfree (context->stack_start, INTERP_STACK_SIZE, MONO_MEM_ACCOUNT_INTERP_STACK);
417 /* Prevent interp_mark_stack from trying to scan the data_stack, before freeing it */
418 context->stack_start = NULL;
419 mono_compiler_barrier ();
420 frame_data_allocator_free (&context->data_stack);
421 g_free (context);
424 static void
425 mono_interp_error_cleanup (MonoError* error)
427 mono_error_cleanup (error); /* FIXME: don't swallow the error */
428 error_init_reuse (error); // one instruction, so this function is good inline candidate
431 static MONO_NEVER_INLINE void
432 ves_real_abort (int line, MonoMethod *mh,
433 const unsigned short *ip, stackval *stack, stackval *sp)
435 ERROR_DECL (error);
436 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
437 mono_error_cleanup (error); /* FIXME: don't swallow the error */
438 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
439 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
440 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
441 mono_metadata_free_mh (header);
442 g_assert_not_reached ();
445 #define ves_abort() \
446 do {\
447 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
448 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
449 } while (0);
451 static InterpMethod*
452 lookup_imethod (MonoDomain *domain, MonoMethod *method)
454 InterpMethod *imethod;
455 MonoJitDomainInfo *info;
457 info = domain_jit_info (domain);
458 mono_domain_jit_code_hash_lock (domain);
459 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
460 mono_domain_jit_code_hash_unlock (domain);
461 return imethod;
464 static gpointer
465 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
467 #ifndef DISABLE_REMOTING
468 InterpMethod *imethod;
470 if (addr) {
471 imethod = lookup_method_pointer (addr);
472 } else {
473 g_assert (method);
474 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
475 return_val_if_nok (error, NULL);
477 g_assert (imethod);
478 g_assert (mono_use_interpreter);
480 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
481 return_val_if_nok (error, NULL);
482 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
483 #else
484 g_assert_not_reached ();
485 return NULL;
486 #endif
489 InterpMethod*
490 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
492 InterpMethod *imethod;
493 MonoJitDomainInfo *info;
494 MonoMethodSignature *sig;
495 int i;
497 error_init (error);
499 info = domain_jit_info (domain);
500 mono_domain_jit_code_hash_lock (domain);
501 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
502 mono_domain_jit_code_hash_unlock (domain);
503 if (imethod)
504 return imethod;
506 sig = mono_method_signature_internal (method);
508 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
509 imethod->method = method;
510 imethod->domain = domain;
511 imethod->param_count = sig->param_count;
512 imethod->hasthis = sig->hasthis;
513 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
514 imethod->code_type = IMETHOD_CODE_UNKNOWN;
515 if (imethod->method->string_ctor)
516 imethod->rtype = m_class_get_byval_arg (mono_defaults.string_class);
517 else
518 imethod->rtype = mini_get_underlying_type (sig->ret);
519 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
520 for (i = 0; i < sig->param_count; ++i)
521 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
523 mono_domain_jit_code_hash_lock (domain);
524 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
525 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
526 mono_domain_jit_code_hash_unlock (domain);
528 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
530 return imethod;
533 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
534 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
535 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
537 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
538 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
539 * (registers are not accurate), thus resuming to the label does not work. */
540 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
541 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
542 #elif defined (_MSC_VER)
543 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
544 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
545 (ext).interp_exit_label_set = FALSE; \
546 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
547 if ((ext).interp_exit_label_set == FALSE) \
548 mono_arch_do_ip_adjustment (&(ext).ctx); \
549 if ((ext).interp_exit_label_set == TRUE) \
550 goto exit_label; \
551 (ext).interp_exit_label_set = TRUE;
552 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
553 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
554 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
555 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
556 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
557 mono_arch_do_ip_adjustment (&(ext).ctx);
558 #else
559 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
560 #endif
562 /* INTERP_PUSH_LMF_WITH_CTX:
564 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
565 * This is needed to resume into the interp when the exception is thrown from
566 * native code (see ./mono/tests/install_eh_callback.exe).
568 * This must be a macro in order to retrieve the right register values for
569 * MonoContext.
571 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
572 memset (&(ext), 0, sizeof (MonoLMFExt)); \
573 (ext).interp_exit_data = (frame); \
574 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
575 mono_push_lmf (&(ext));
578 * interp_push_lmf:
580 * Push an LMF frame on the LMF stack
581 * to mark the transition to native code.
582 * This is needed for the native code to
583 * be able to do stack walks.
585 static void
586 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
588 memset (ext, 0, sizeof (MonoLMFExt));
589 ext->kind = MONO_LMFEXT_INTERP_EXIT;
590 ext->interp_exit_data = frame;
592 mono_push_lmf (ext);
595 static void
596 interp_pop_lmf (MonoLMFExt *ext)
598 mono_pop_lmf (&ext->lmf);
601 static InterpMethod*
602 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
604 MonoMethod *m = imethod->method;
605 MonoDomain *domain = imethod->domain;
606 InterpMethod *ret = NULL;
608 #ifndef DISABLE_REMOTING
609 if (mono_class_is_transparent_proxy (vtable->klass)) {
610 ERROR_DECL (error);
611 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
612 mono_error_assert_ok (error);
613 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
614 mono_error_assert_ok (error);
615 return ret;
617 #endif
619 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
620 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
621 ERROR_DECL (error);
622 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
623 mono_error_cleanup (error); /* FIXME: don't swallow the error */
624 } else {
625 ret = imethod;
627 return ret;
630 mono_class_setup_vtable (vtable->klass);
632 int slot = mono_method_get_vtable_slot (m);
633 if (mono_class_is_interface (m->klass)) {
634 g_assert (vtable->klass != m->klass);
635 /* TODO: interface offset lookup is slow, go through IMT instead */
636 gboolean non_exact_match;
637 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
640 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
641 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
642 MonoGenericContext context = { NULL, NULL };
644 if (mono_class_is_ginst (virtual_method->klass))
645 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
646 else if (mono_class_is_gtd (virtual_method->klass))
647 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
648 context.method_inst = mono_method_get_context (m)->method_inst;
650 ERROR_DECL (error);
651 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
652 mono_error_cleanup (error); /* FIXME: don't swallow the error */
655 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
656 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
659 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
660 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
663 ERROR_DECL (error);
664 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
665 mono_error_cleanup (error); /* FIXME: don't swallow the error */
666 return virtual_imethod;
669 typedef struct {
670 InterpMethod *imethod;
671 InterpMethod *target_imethod;
672 } InterpVTableEntry;
674 /* memory manager lock must be held */
675 static GSList*
676 append_imethod (MonoMemoryManager *memory_manager, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
678 GSList *ret;
679 InterpVTableEntry *entry;
681 entry = (InterpVTableEntry*) mono_mem_manager_alloc_nolock (memory_manager, sizeof (InterpVTableEntry));
682 entry->imethod = imethod;
683 entry->target_imethod = target_imethod;
684 ret = g_slist_append_mempool (memory_manager->mp, list, entry);
686 return ret;
689 static InterpMethod*
690 get_target_imethod (GSList *list, InterpMethod *imethod)
692 while (list != NULL) {
693 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
694 if (entry->imethod == imethod)
695 return entry->target_imethod;
696 list = list->next;
698 return NULL;
701 static gpointer*
702 get_method_table (MonoVTable *vtable, int offset)
704 if (offset >= 0)
705 return vtable->interp_vtable;
706 else
707 return (gpointer*)vtable;
710 static gpointer*
711 alloc_method_table (MonoVTable *vtable, int offset)
713 gpointer *table;
715 if (offset >= 0) {
716 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
717 vtable->interp_vtable = table;
718 } else {
719 table = (gpointer*)vtable;
722 return table;
725 static InterpMethod* // Inlining causes additional stack use in caller.
726 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
728 gpointer *table;
729 MonoMemoryManager *memory_manager = mono_domain_ambient_memory_manager (vtable->domain);
731 #ifndef DISABLE_REMOTING
732 /* FIXME Remoting */
733 if (mono_class_is_transparent_proxy (vtable->klass))
734 return get_virtual_method (imethod, vtable);
735 #endif
737 table = get_method_table (vtable, offset);
739 if (!table) {
740 /* Lazily allocate method table */
741 mono_domain_lock (vtable->domain);
742 table = get_method_table (vtable, offset);
743 if (!table)
744 table = alloc_method_table (vtable, offset);
745 mono_domain_unlock (vtable->domain);
748 if (!table [offset]) {
749 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
750 /* Lazily initialize the method table slot */
751 mono_mem_manager_lock (memory_manager);
752 if (!table [offset]) {
753 if (imethod->method->is_inflated || offset < 0)
754 table [offset] = append_imethod (memory_manager, NULL, imethod, target_imethod);
755 else
756 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
758 mono_mem_manager_unlock (memory_manager);
761 if ((gsize)table [offset] & 0x1) {
762 /* Non generic virtual call. Only one method in slot */
763 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
764 } else {
765 /* Virtual generic or interface call. Multiple methods in slot */
766 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
768 if (!target_imethod) {
769 target_imethod = get_virtual_method (imethod, vtable);
770 mono_mem_manager_lock (memory_manager);
771 if (!get_target_imethod ((GSList*)table [offset], imethod))
772 table [offset] = append_imethod (memory_manager, (GSList*)table [offset], imethod, target_imethod);
773 mono_mem_manager_unlock (memory_manager);
775 return target_imethod;
779 static void inline
780 stackval_from_data (MonoType *type, stackval *result, const void *data, gboolean pinvoke)
782 type = mini_native_type_replace_type (type);
783 if (type->byref) {
784 switch (type->type) {
785 case MONO_TYPE_OBJECT:
786 case MONO_TYPE_CLASS:
787 case MONO_TYPE_STRING:
788 case MONO_TYPE_ARRAY:
789 case MONO_TYPE_SZARRAY:
790 break;
791 default:
792 break;
794 result->data.p = *(gpointer*)data;
795 return;
797 switch (type->type) {
798 case MONO_TYPE_VOID:
799 return;
800 case MONO_TYPE_I1:
801 result->data.i = *(gint8*)data;
802 return;
803 case MONO_TYPE_U1:
804 case MONO_TYPE_BOOLEAN:
805 result->data.i = *(guint8*)data;
806 return;
807 case MONO_TYPE_I2:
808 result->data.i = *(gint16*)data;
809 return;
810 case MONO_TYPE_U2:
811 case MONO_TYPE_CHAR:
812 result->data.i = *(guint16*)data;
813 return;
814 case MONO_TYPE_I4:
815 result->data.i = *(gint32*)data;
816 return;
817 case MONO_TYPE_U:
818 case MONO_TYPE_I:
819 result->data.nati = *(mono_i*)data;
820 return;
821 case MONO_TYPE_PTR:
822 result->data.p = *(gpointer*)data;
823 return;
824 case MONO_TYPE_U4:
825 result->data.i = *(guint32*)data;
826 return;
827 case MONO_TYPE_R4:
828 /* memmove handles unaligned case */
829 memmove (&result->data.f_r4, data, sizeof (float));
830 return;
831 case MONO_TYPE_I8:
832 case MONO_TYPE_U8:
833 memmove (&result->data.l, data, sizeof (gint64));
834 return;
835 case MONO_TYPE_R8:
836 memmove (&result->data.f, data, sizeof (double));
837 return;
838 case MONO_TYPE_STRING:
839 case MONO_TYPE_SZARRAY:
840 case MONO_TYPE_CLASS:
841 case MONO_TYPE_OBJECT:
842 case MONO_TYPE_ARRAY:
843 result->data.p = *(gpointer*)data;
844 return;
845 case MONO_TYPE_VALUETYPE:
846 if (m_class_is_enumtype (type->data.klass)) {
847 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
848 return;
849 } else if (pinvoke) {
850 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
851 } else {
852 mono_value_copy_internal (result->data.vt, data, type->data.klass);
854 return;
855 case MONO_TYPE_GENERICINST: {
856 if (mono_type_generic_inst_is_valuetype (type)) {
857 MonoClass *klass = mono_class_from_mono_type_internal (type);
858 if (pinvoke)
859 memcpy (result->data.vt, data, mono_class_native_size (klass, NULL));
860 else
861 mono_value_copy_internal (result->data.vt, data, klass);
862 return;
864 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
865 return;
867 default:
868 g_error ("got type 0x%02x", type->type);
872 static void inline
873 stackval_to_data (MonoType *type, stackval *val, void *data, gboolean pinvoke)
875 type = mini_native_type_replace_type (type);
876 if (type->byref) {
877 gpointer *p = (gpointer*)data;
878 *p = val->data.p;
879 return;
881 /* printf ("TODAT0 %p\n", data); */
882 switch (type->type) {
883 case MONO_TYPE_I1:
884 case MONO_TYPE_U1: {
885 guint8 *p = (guint8*)data;
886 *p = val->data.i;
887 return;
889 case MONO_TYPE_BOOLEAN: {
890 guint8 *p = (guint8*)data;
891 *p = (val->data.i != 0);
892 return;
894 case MONO_TYPE_I2:
895 case MONO_TYPE_U2:
896 case MONO_TYPE_CHAR: {
897 guint16 *p = (guint16*)data;
898 *p = val->data.i;
899 return;
901 case MONO_TYPE_I: {
902 mono_i *p = (mono_i*)data;
903 /* In theory the value used by stloc should match the local var type
904 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
905 a native int - both by csc and mcs). Not sure what to do about sign extension
906 as it is outside the spec... doing the obvious */
907 *p = (mono_i)val->data.nati;
908 return;
910 case MONO_TYPE_U: {
911 mono_u *p = (mono_u*)data;
912 /* see above. */
913 *p = (mono_u)val->data.nati;
914 return;
916 case MONO_TYPE_I4:
917 case MONO_TYPE_U4: {
918 gint32 *p = (gint32*)data;
919 *p = val->data.i;
920 return;
922 case MONO_TYPE_I8:
923 case MONO_TYPE_U8: {
924 memmove (data, &val->data.l, sizeof (gint64));
925 return;
927 case MONO_TYPE_R4: {
928 /* memmove handles unaligned case */
929 memmove (data, &val->data.f_r4, sizeof (float));
930 return;
932 case MONO_TYPE_R8: {
933 memmove (data, &val->data.f, sizeof (double));
934 return;
936 case MONO_TYPE_STRING:
937 case MONO_TYPE_SZARRAY:
938 case MONO_TYPE_CLASS:
939 case MONO_TYPE_OBJECT:
940 case MONO_TYPE_ARRAY: {
941 gpointer *p = (gpointer *) data;
942 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
943 return;
945 case MONO_TYPE_PTR: {
946 gpointer *p = (gpointer *) data;
947 *p = val->data.p;
948 return;
950 case MONO_TYPE_VALUETYPE:
951 if (m_class_is_enumtype (type->data.klass)) {
952 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
953 return;
954 } else if (pinvoke) {
955 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
956 } else {
957 mono_value_copy_internal (data, val->data.vt, type->data.klass);
959 return;
960 case MONO_TYPE_GENERICINST: {
961 MonoClass *container_class = type->data.generic_class->container_class;
963 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
964 MonoClass *klass = mono_class_from_mono_type_internal (type);
965 if (pinvoke)
966 memcpy (data, val->data.vt, mono_class_native_size (klass, NULL));
967 else
968 mono_value_copy_internal (data, val->data.vt, klass);
969 return;
971 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
972 return;
974 default:
975 g_error ("got type %x", type->type);
980 * Same as stackval_to_data but return address of storage instead
981 * of copying the value.
983 static gpointer
984 stackval_to_data_addr (MonoType *type, stackval *val)
986 type = mini_native_type_replace_type (type);
987 if (type->byref)
988 return &val->data.p;
990 switch (type->type) {
991 case MONO_TYPE_I1:
992 case MONO_TYPE_U1:
993 case MONO_TYPE_BOOLEAN:
994 case MONO_TYPE_I2:
995 case MONO_TYPE_U2:
996 case MONO_TYPE_CHAR:
997 case MONO_TYPE_I4:
998 case MONO_TYPE_U4:
999 return &val->data.i;
1000 case MONO_TYPE_I:
1001 case MONO_TYPE_U:
1002 return &val->data.nati;
1003 case MONO_TYPE_I8:
1004 case MONO_TYPE_U8:
1005 return &val->data.l;
1006 case MONO_TYPE_R4:
1007 return &val->data.f_r4;
1008 case MONO_TYPE_R8:
1009 return &val->data.f;
1010 case MONO_TYPE_STRING:
1011 case MONO_TYPE_SZARRAY:
1012 case MONO_TYPE_CLASS:
1013 case MONO_TYPE_OBJECT:
1014 case MONO_TYPE_ARRAY:
1015 case MONO_TYPE_PTR:
1016 return &val->data.p;
1017 case MONO_TYPE_VALUETYPE:
1018 if (m_class_is_enumtype (type->data.klass))
1019 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
1020 else
1021 return val->data.vt;
1022 case MONO_TYPE_TYPEDBYREF:
1023 return val->data.vt;
1024 case MONO_TYPE_GENERICINST: {
1025 MonoClass *container_class = type->data.generic_class->container_class;
1027 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
1028 return val->data.vt;
1029 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
1031 default:
1032 g_error ("got type %x", type->type);
1037 * interp_throw:
1038 * Throw an exception from the interpreter.
1040 static MONO_NEVER_INLINE void
1041 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, const guint16* ip, gboolean rethrow)
1043 ERROR_DECL (error);
1044 MonoLMFExt ext;
1046 interp_push_lmf (&ext, frame);
1048 * When explicitly throwing exception we pass the ip of the instruction that throws the exception.
1049 * Offset the subtraction from interp_frame_get_ip, so we don't end up in prev instruction.
1051 frame->state.ip = ip + 1;
1053 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
1054 MonoException *mono_ex = ex;
1055 if (!rethrow) {
1056 mono_ex->stack_trace = NULL;
1057 mono_ex->trace_ips = NULL;
1060 mono_error_assert_ok (error);
1062 MonoContext ctx;
1063 memset (&ctx, 0, sizeof (MonoContext));
1064 MONO_CONTEXT_SET_SP (&ctx, frame);
1067 * Call the JIT EH code. The EH code will call back to us using:
1068 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
1069 * Since ctx.ip is 0, this will start unwinding from the LMF frame
1070 * pushed above, which points to our frames.
1072 mono_handle_exception (&ctx, (MonoObject*)ex);
1073 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
1074 /* We need to unwind into non-interpreter code */
1075 mono_restore_context (&ctx);
1076 g_assert_not_reached ();
1079 interp_pop_lmf (&ext);
1081 g_assert (context->has_resume_state);
1084 // We conservatively pin exception object here to avoid tweaking the
1085 // numerous call sites of this macro, even though, in a few cases,
1086 // this is not needed.
1087 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
1088 do { \
1089 MonoException *__ex = (exception); \
1090 MONO_HANDLE_ASSIGN_RAW (tmp_handle, (MonoObject*)__ex); \
1091 interp_throw (context, __ex, (frame), (ex_ip), (rethrow)); \
1092 MONO_HANDLE_ASSIGN_RAW (tmp_handle, (MonoObject*)NULL); \
1093 goto resume; \
1094 } while (0)
1096 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
1098 #define NULL_CHECK(o) do { \
1099 if (G_UNLIKELY (!(o))) \
1100 THROW_EX (mono_get_exception_null_reference (), ip); \
1101 } while (0)
1103 #define EXCEPTION_CHECKPOINT \
1104 do { \
1105 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
1106 MonoException *exc = mono_thread_interruption_checkpoint (); \
1107 if (exc) \
1108 THROW_EX (exc, ip); \
1110 } while (0)
1112 /* Don't throw exception if thread is in GC Safe mode. Should only happen in managed-to-native wrapper. */
1113 #define EXCEPTION_CHECKPOINT_GC_UNSAFE \
1114 do { \
1115 if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method) && mono_thread_is_gc_unsafe_mode ()) { \
1116 MonoException *exc = mono_thread_interruption_checkpoint (); \
1117 if (exc) \
1118 THROW_EX (exc, ip); \
1120 } while (0)
1122 static MonoObject*
1123 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
1125 int rank = m_class_get_rank (klass);
1126 uintptr_t *lengths = g_newa (uintptr_t, rank * 2);
1127 intptr_t *lower_bounds = NULL;
1128 if (2 * rank == param_count) {
1129 for (int l = 0; l < 2; ++l) {
1130 int src = l;
1131 int dst = l * rank;
1132 for (int r = 0; r < rank; ++r, src += 2, ++dst) {
1133 lengths [dst] = values [src].data.i;
1136 /* lower bounds are first. */
1137 lower_bounds = (intptr_t *) lengths;
1138 lengths += rank;
1139 } else {
1140 /* Only lengths provided. */
1141 for (int i = 0; i < param_count; ++i) {
1142 lengths [i] = values [i].data.i;
1145 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
1148 static gint32
1149 ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
1151 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1153 guint32 pos = 0;
1154 if (ao->bounds) {
1155 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
1156 gint32 idx = sp [i].data.i;
1157 gint32 lower = ao->bounds [i].lower_bound;
1158 guint32 len = ao->bounds [i].length;
1159 if (safe && (idx < lower || (guint32)(idx - lower) >= len))
1160 return -1;
1161 pos = (pos * len) + (guint32)(idx - lower);
1163 } else {
1164 pos = sp [0].data.i;
1165 if (safe && pos >= ao->max_length)
1166 return -1;
1168 return pos;
1171 static MonoException*
1172 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1174 MonoObject *o = sp->data.o;
1175 MonoArray *ao = (MonoArray *) o;
1176 MonoClass *ac = o->vtable->klass;
1178 g_assert (m_class_get_rank (ac) >= 1);
1180 gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
1181 if (pos == -1)
1182 return mono_get_exception_index_out_of_range ();
1184 gint32 esize = mono_array_element_size (ac);
1185 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1187 MonoType *mt = sig->ret;
1188 stackval_from_data (mt, retval, ea, FALSE);
1189 return NULL;
1192 static MonoException*
1193 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1195 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1197 g_assert (m_class_get_rank (ac) >= 1);
1199 gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
1200 if (pos == -1)
1201 return mono_get_exception_index_out_of_range ();
1203 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
1204 return mono_get_exception_array_type_mismatch ();
1205 gint32 esize = mono_array_element_size (ac);
1206 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
1207 return NULL;
1210 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1211 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1212 #endif
1214 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1215 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1217 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1219 #ifdef TARGET_ARM
1220 g_assert (mono_arm_eabi_supported ());
1221 int i8_align = mono_arm_i8_align ();
1222 #endif
1224 #ifdef TARGET_WASM
1225 margs->sig = sig;
1226 #endif
1228 if (sig->hasthis)
1229 margs->ilen++;
1231 for (int i = 0; i < sig->param_count; i++) {
1232 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1233 switch (ptype) {
1234 case MONO_TYPE_BOOLEAN:
1235 case MONO_TYPE_CHAR:
1236 case MONO_TYPE_I1:
1237 case MONO_TYPE_U1:
1238 case MONO_TYPE_I2:
1239 case MONO_TYPE_U2:
1240 case MONO_TYPE_I4:
1241 case MONO_TYPE_U4:
1242 case MONO_TYPE_I:
1243 case MONO_TYPE_U:
1244 case MONO_TYPE_PTR:
1245 case MONO_TYPE_SZARRAY:
1246 case MONO_TYPE_CLASS:
1247 case MONO_TYPE_OBJECT:
1248 case MONO_TYPE_STRING:
1249 case MONO_TYPE_VALUETYPE:
1250 case MONO_TYPE_GENERICINST:
1251 #if SIZEOF_VOID_P == 8
1252 case MONO_TYPE_I8:
1253 case MONO_TYPE_U8:
1254 #endif
1255 margs->ilen++;
1256 break;
1257 #if SIZEOF_VOID_P == 4
1258 case MONO_TYPE_I8:
1259 case MONO_TYPE_U8:
1260 #ifdef TARGET_ARM
1261 /* pairs begin at even registers */
1262 if (i8_align == 8 && margs->ilen & 1)
1263 margs->ilen++;
1264 #endif
1265 margs->ilen += 2;
1266 break;
1267 #endif
1268 case MONO_TYPE_R4:
1269 case MONO_TYPE_R8:
1270 margs->flen++;
1271 break;
1272 default:
1273 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1277 if (margs->ilen > 0)
1278 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1280 if (margs->flen > 0)
1281 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1283 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1284 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1286 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1287 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1290 size_t int_i = 0;
1291 size_t int_f = 0;
1293 if (sig->hasthis) {
1294 margs->iargs [0] = frame->stack [0].data.p;
1295 int_i++;
1296 g_error ("FIXME if hasthis, we incorrectly access the args below");
1299 for (int i = 0; i < sig->param_count; i++) {
1300 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1301 switch (ptype) {
1302 case MONO_TYPE_BOOLEAN:
1303 case MONO_TYPE_CHAR:
1304 case MONO_TYPE_I1:
1305 case MONO_TYPE_U1:
1306 case MONO_TYPE_I2:
1307 case MONO_TYPE_U2:
1308 case MONO_TYPE_I4:
1309 case MONO_TYPE_U4:
1310 case MONO_TYPE_I:
1311 case MONO_TYPE_U:
1312 case MONO_TYPE_PTR:
1313 case MONO_TYPE_SZARRAY:
1314 case MONO_TYPE_CLASS:
1315 case MONO_TYPE_OBJECT:
1316 case MONO_TYPE_STRING:
1317 case MONO_TYPE_VALUETYPE:
1318 case MONO_TYPE_GENERICINST:
1319 #if SIZEOF_VOID_P == 8
1320 case MONO_TYPE_I8:
1321 case MONO_TYPE_U8:
1322 #endif
1323 margs->iargs [int_i] = frame->stack [i].data.p;
1324 #if DEBUG_INTERP
1325 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1326 #endif
1327 int_i++;
1328 break;
1329 #if SIZEOF_VOID_P == 4
1330 case MONO_TYPE_I8:
1331 case MONO_TYPE_U8: {
1332 stackval *sarg = &frame->stack [i];
1333 #ifdef TARGET_ARM
1334 /* pairs begin at even registers */
1335 if (i8_align == 8 && int_i & 1)
1336 int_i++;
1337 #endif
1338 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1339 int_i++;
1340 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1341 #if DEBUG_INTERP
1342 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);
1343 #endif
1344 int_i++;
1345 break;
1347 #endif
1348 case MONO_TYPE_R4:
1349 case MONO_TYPE_R8:
1350 if (ptype == MONO_TYPE_R4)
1351 * (float *) &(margs->fargs [int_f]) = frame->stack [i].data.f_r4;
1352 else
1353 margs->fargs [int_f] = frame->stack [i].data.f;
1354 #if DEBUG_INTERP
1355 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);
1356 #endif
1357 int_f ++;
1358 break;
1359 default:
1360 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1364 switch (sig->ret->type) {
1365 case MONO_TYPE_BOOLEAN:
1366 case MONO_TYPE_CHAR:
1367 case MONO_TYPE_I1:
1368 case MONO_TYPE_U1:
1369 case MONO_TYPE_I2:
1370 case MONO_TYPE_U2:
1371 case MONO_TYPE_I4:
1372 case MONO_TYPE_U4:
1373 case MONO_TYPE_I:
1374 case MONO_TYPE_U:
1375 case MONO_TYPE_PTR:
1376 case MONO_TYPE_SZARRAY:
1377 case MONO_TYPE_CLASS:
1378 case MONO_TYPE_OBJECT:
1379 case MONO_TYPE_STRING:
1380 case MONO_TYPE_I8:
1381 case MONO_TYPE_U8:
1382 case MONO_TYPE_VALUETYPE:
1383 case MONO_TYPE_GENERICINST:
1384 margs->retval = &frame->retval->data.p;
1385 margs->is_float_ret = 0;
1386 break;
1387 case MONO_TYPE_R4:
1388 case MONO_TYPE_R8:
1389 margs->retval = &frame->retval->data.p;
1390 margs->is_float_ret = 1;
1391 break;
1392 case MONO_TYPE_VOID:
1393 margs->retval = NULL;
1394 break;
1395 default:
1396 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1399 return margs;
1401 #endif
1403 static void
1404 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1406 InterpFrame *iframe = (InterpFrame*)frame;
1408 if (index == -1)
1409 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1410 else
1411 stackval_to_data (sig->params [index], &iframe->stack [index], data, sig->pinvoke);
1414 static void
1415 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1417 InterpFrame *iframe = (InterpFrame*)frame;
1419 if (index == -1)
1420 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1421 else if (sig->hasthis && index == 0)
1422 iframe->stack [index].data.p = *(gpointer*)data;
1423 else
1424 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack [index], data, sig->pinvoke);
1427 static gpointer
1428 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1430 InterpFrame *iframe = (InterpFrame*)frame;
1432 if (index == -1)
1433 return stackval_to_data_addr (sig->ret, iframe->retval);
1434 else
1435 return stackval_to_data_addr (sig->params [index], &iframe->stack [index]);
1438 static void
1439 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1441 InterpFrame *iframe = (InterpFrame*)frame;
1442 stackval *val = (index == -1) ? iframe->retval : &iframe->stack [index];
1443 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1445 switch (type->type) {
1446 case MONO_TYPE_GENERICINST:
1447 if (!MONO_TYPE_IS_REFERENCE (type))
1448 val->data.vt = storage;
1449 break;
1450 case MONO_TYPE_VALUETYPE:
1451 val->data.vt = storage;
1452 break;
1453 default:
1454 g_assert_not_reached ();
1458 static MonoPIFunc
1459 get_interp_to_native_trampoline (void)
1461 static MonoPIFunc trampoline = NULL;
1463 if (!trampoline) {
1464 if (mono_ee_features.use_aot_trampolines) {
1465 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1466 } else {
1467 MonoTrampInfo *info;
1468 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1469 mono_tramp_info_register (info, NULL);
1471 mono_memory_barrier ();
1473 return trampoline;
1476 static void
1477 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1479 get_interp_to_native_trampoline () (addr, ccontext);
1482 /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1483 #ifdef _MSC_VER
1484 #pragma optimize ("", off)
1485 #endif
1486 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1487 ves_pinvoke_method (
1488 MonoMethodSignature *sig,
1489 MonoFuncV addr,
1490 ThreadContext *context,
1491 InterpFrame *parent_frame,
1492 stackval *retval,
1493 gboolean save_last_error,
1494 gpointer *cache,
1495 stackval *sp)
1497 InterpFrame frame = {0};
1498 frame.parent = parent_frame;
1499 frame.stack = sp;
1500 frame.retval = retval;
1502 MonoLMFExt ext;
1503 gpointer args;
1505 g_assert (!frame.imethod);
1508 * When there's a calli in a pinvoke wrapper, we're in GC Safe mode.
1509 * When we're called for some other calli, we may be in GC Unsafe mode.
1511 * On any code path where we call anything other than the entry_func,
1512 * we need to switch back to GC Unsafe before calling the runtime.
1514 MONO_REQ_GC_NEUTRAL_MODE;
1516 #ifdef HOST_WASM
1518 * Use a per-signature entry function.
1519 * Cache it in imethod->data_items.
1520 * This is GC safe.
1522 MonoPIFunc entry_func = *cache;
1523 if (!entry_func) {
1524 entry_func = (MonoPIFunc)mono_wasm_get_interp_to_native_trampoline (sig);
1525 mono_memory_barrier ();
1526 *cache = entry_func;
1528 #else
1529 static MonoPIFunc entry_func = NULL;
1530 if (!entry_func) {
1531 MONO_ENTER_GC_UNSAFE;
1532 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1533 ERROR_DECL (error);
1534 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);
1535 mono_error_assert_ok (error);
1536 #else
1537 entry_func = get_interp_to_native_trampoline ();
1538 #endif
1539 mono_memory_barrier ();
1540 MONO_EXIT_GC_UNSAFE;
1542 #endif
1544 #ifdef ENABLE_NETCORE
1545 if (save_last_error) {
1546 mono_marshal_clear_last_error ();
1548 #endif
1550 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1551 CallContext ccontext;
1552 MONO_ENTER_GC_UNSAFE;
1553 mono_arch_set_native_call_context_args (&ccontext, &frame, sig);
1554 MONO_EXIT_GC_UNSAFE;
1555 args = &ccontext;
1556 #else
1557 InterpMethodArguments *margs = build_args_from_sig (sig, &frame);
1558 args = margs;
1559 #endif
1561 INTERP_PUSH_LMF_WITH_CTX (&frame, ext, exit_pinvoke);
1562 entry_func ((gpointer) addr, args);
1563 if (save_last_error)
1564 mono_marshal_set_last_error ();
1565 interp_pop_lmf (&ext);
1567 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1568 if (!context->has_resume_state) {
1569 MONO_ENTER_GC_UNSAFE;
1570 mono_arch_get_native_call_context_ret (&ccontext, &frame, sig);
1571 MONO_EXIT_GC_UNSAFE;
1574 g_free (ccontext.stack);
1575 #else
1576 if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
1577 stackval_from_data (sig->ret, frame.retval, (char*)&frame.retval->data.p, sig->pinvoke);
1579 g_free (margs->iargs);
1580 g_free (margs->fargs);
1581 g_free (margs);
1582 #endif
1583 goto exit_pinvoke; // prevent unused label warning in some configurations
1584 exit_pinvoke:
1585 return;
1587 #ifdef _MSC_VER
1588 #pragma optimize ("", on)
1589 #endif
1592 * interp_init_delegate:
1594 * Initialize del->interp_method.
1596 static void
1597 interp_init_delegate (MonoDelegate *del, MonoError *error)
1599 MonoMethod *method;
1601 if (del->interp_method) {
1602 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1603 del->method = ((InterpMethod *)del->interp_method)->method;
1604 } if (del->method_ptr && !del->method) {
1605 /* Delegate created from methodInfo.MethodHandle.GetFunctionPointer() */
1606 del->interp_method = (InterpMethod *)del->method_ptr;
1607 } else if (del->method) {
1608 /* Delegate created dynamically */
1609 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1610 } else {
1611 /* Created from JITted code */
1612 g_assert_not_reached ();
1615 method = ((InterpMethod*)del->interp_method)->method;
1616 if (del->target &&
1617 method &&
1618 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1619 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1620 mono_class_is_abstract (method->klass))
1621 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1623 method = ((InterpMethod*)del->interp_method)->method;
1624 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1625 const char *name = method->name;
1626 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1628 * When invoking the delegate interp_method is executed directly. If it's an
1629 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1631 * FIXME We should do this later, when we also know the delegate on which the
1632 * target method is called.
1634 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1635 mono_error_assert_ok (error);
1639 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1640 /* Return any errors from method compilation */
1641 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1642 return_if_nok (error);
1646 static void
1647 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1650 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1652 InterpMethod *imethod = (InterpMethod*)addr;
1654 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1655 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1656 /* virtual invoke delegates must not have null check */
1657 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1658 && MONO_HANDLE_IS_NULL (target)) {
1659 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1660 return;
1664 g_assert (imethod->method);
1665 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1666 return_if_nok (error);
1668 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1670 mono_delegate_ctor (this_obj, target, entry, imethod->method, error);
1674 * From the spec:
1675 * runtime specifies that the implementation of the method is automatically
1676 * provided by the runtime and is primarily used for the methods of delegates.
1678 #ifndef ENABLE_NETCORE
1679 static MONO_NEVER_INLINE MonoException*
1680 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1682 const char *name = method->name;
1683 mono_class_init_internal (method->klass);
1685 if (method->klass == mono_defaults.array_class) {
1686 if (!strcmp (name, "UnsafeMov")) {
1687 /* TODO: layout checks */
1688 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1689 return NULL;
1691 if (!strcmp (name, "UnsafeLoad"))
1692 return ves_array_get (frame, sp, retval, sig, FALSE);
1695 g_error ("Don't know how to exec runtime method %s.%s::%s",
1696 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1697 method->name);
1699 #endif
1701 #if DEBUG_INTERP
1702 static char*
1703 dump_stack (stackval *stack, stackval *sp)
1705 stackval *s = stack;
1706 GString *str = g_string_new ("");
1708 if (sp == stack)
1709 return g_string_free (str, FALSE);
1711 while (s < sp) {
1712 g_string_append_printf (str, "[%p (%" PRId64 ")] ", s->data.l, (gint64)s->data.l);
1713 ++s;
1715 return g_string_free (str, FALSE);
1718 static void
1719 dump_stackval (GString *str, stackval *s, MonoType *type)
1721 switch (type->type) {
1722 case MONO_TYPE_I1:
1723 case MONO_TYPE_U1:
1724 case MONO_TYPE_I2:
1725 case MONO_TYPE_U2:
1726 case MONO_TYPE_I4:
1727 case MONO_TYPE_U4:
1728 case MONO_TYPE_CHAR:
1729 case MONO_TYPE_BOOLEAN:
1730 g_string_append_printf (str, "[%d] ", s->data.i);
1731 break;
1732 case MONO_TYPE_STRING:
1733 case MONO_TYPE_SZARRAY:
1734 case MONO_TYPE_CLASS:
1735 case MONO_TYPE_OBJECT:
1736 case MONO_TYPE_ARRAY:
1737 case MONO_TYPE_PTR:
1738 case MONO_TYPE_I:
1739 case MONO_TYPE_U:
1740 g_string_append_printf (str, "[%p] ", s->data.p);
1741 break;
1742 case MONO_TYPE_VALUETYPE:
1743 if (m_class_is_enumtype (type->data.klass))
1744 g_string_append_printf (str, "[%d] ", s->data.i);
1745 else
1746 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1747 break;
1748 case MONO_TYPE_R4:
1749 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1750 break;
1751 case MONO_TYPE_R8:
1752 g_string_append_printf (str, "[%g] ", s->data.f);
1753 break;
1754 case MONO_TYPE_I8:
1755 case MONO_TYPE_U8:
1756 default: {
1757 GString *res = g_string_new ("");
1758 mono_type_get_desc (res, type, TRUE);
1759 g_string_append_printf (str, "[{%s} %" PRId64 "/0x%0" PRIx64 "] ", res->str, (gint64)s->data.l, (guint64)s->data.l);
1760 g_string_free (res, TRUE);
1761 break;
1766 static char*
1767 dump_retval (InterpFrame *inv)
1769 GString *str = g_string_new ("");
1770 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1772 if (ret->type != MONO_TYPE_VOID)
1773 dump_stackval (str, inv->retval, ret);
1775 return g_string_free (str, FALSE);
1778 static char*
1779 dump_args (InterpFrame *inv)
1781 GString *str = g_string_new ("");
1782 int i;
1783 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1785 if (signature->param_count == 0 && !signature->hasthis)
1786 return g_string_free (str, FALSE);
1788 if (signature->hasthis) {
1789 MonoMethod *method = inv->imethod->method;
1790 dump_stackval (str, inv->stack, m_class_get_byval_arg (method->klass));
1793 for (i = 0; i < signature->param_count; ++i)
1794 dump_stackval (str, inv->stack + (!!signature->hasthis) + i, signature->params [i]);
1796 return g_string_free (str, FALSE);
1798 #endif
1800 #define CHECK_ADD_OVERFLOW(a,b) \
1801 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1802 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1804 #define CHECK_SUB_OVERFLOW(a,b) \
1805 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1806 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1808 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1809 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1811 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1812 (guint32)(a) < (guint32)(b) ? -1 : 0
1814 #define CHECK_ADD_OVERFLOW64(a,b) \
1815 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1816 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1818 #define CHECK_SUB_OVERFLOW64(a,b) \
1819 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1820 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1822 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1823 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1825 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1826 (guint64)(a) < (guint64)(b) ? -1 : 0
1828 #if SIZEOF_VOID_P == 4
1829 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1830 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1831 #else
1832 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1833 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1834 #endif
1836 /* Resolves to TRUE if the operands would overflow */
1837 #define CHECK_MUL_OVERFLOW(a,b) \
1838 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1839 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1840 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1841 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1842 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1843 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1844 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1846 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1847 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1848 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1850 #define CHECK_MUL_OVERFLOW64(a,b) \
1851 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1852 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1853 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1854 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1855 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1856 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1857 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1859 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1860 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1861 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1863 #if SIZEOF_VOID_P == 4
1864 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1865 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1866 #else
1867 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1868 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1869 #endif
1871 // Do not inline in case order of frame addresses matters.
1872 static MONO_NEVER_INLINE MonoObject*
1873 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1875 ThreadContext *context = get_context ();
1876 MonoMethodSignature *sig = mono_method_signature_internal (method);
1877 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1878 stackval result;
1879 stackval *sp = (stackval*)context->stack_pointer;
1880 MonoMethod *target_method = method;
1882 error_init (error);
1883 if (exc)
1884 *exc = NULL;
1886 MonoDomain *domain = mono_domain_get ();
1888 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1889 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1890 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1892 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1894 result.data.vt = alloca (mono_class_instance_size (klass));
1895 if (sig->hasthis)
1896 sp [0].data.p = obj;
1897 else
1898 sp [0].data.p = NULL;
1899 sp [1].data.p = params;
1900 sp [2].data.p = exc;
1901 sp [3].data.p = target_method;
1903 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1904 mono_error_assert_ok (error);
1906 InterpFrame frame = {0};
1907 frame.imethod = imethod;
1908 frame.stack = sp;
1909 frame.retval = &result;
1911 // The method to execute might not be transformed yet, so we don't know how much stack
1912 // it uses. We bump the stack_pointer here so any code triggered by method compilation
1913 // will not attempt to use the space that we used to push the args for this method.
1914 // The real top of stack for this method will be set in interp_exec_method once the
1915 // method is transformed.
1916 context->stack_pointer = (guchar*)(sp + 4);
1918 interp_exec_method (&frame, context, NULL);
1920 context->stack_pointer = (guchar*)sp;
1922 if (context->has_resume_state) {
1924 * This can happen on wasm where native frames cannot be skipped during EH.
1925 * EH processing will continue when control returns to the interpreter.
1927 return NULL;
1929 return (MonoObject*)result.data.p;
1932 typedef struct {
1933 InterpMethod *rmethod;
1934 gpointer this_arg;
1935 gpointer res;
1936 gpointer args [16];
1937 gpointer *many_args;
1938 } InterpEntryData;
1940 /* Main function for entering the interpreter from compiled code */
1941 // Do not inline in case order of frame addresses matters.
1942 static MONO_NEVER_INLINE void
1943 interp_entry (InterpEntryData *data)
1945 InterpMethod *rmethod;
1946 ThreadContext *context;
1947 stackval *sp;
1948 stackval result;
1949 MonoMethod *method;
1950 MonoMethodSignature *sig;
1951 MonoType *type;
1952 gpointer orig_domain = NULL, attach_cookie;
1953 int i;
1955 if ((gsize)data->rmethod & 1) {
1956 /* Unbox */
1957 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1958 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1960 rmethod = data->rmethod;
1962 if (rmethod->needs_thread_attach)
1963 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1965 context = get_context ();
1966 sp = (stackval*)context->stack_pointer;
1968 method = rmethod->method;
1969 sig = mono_method_signature_internal (method);
1971 // FIXME: Optimize this
1973 if (sig->hasthis)
1974 sp [0].data.p = data->this_arg;
1976 gpointer *params;
1977 if (data->many_args)
1978 params = data->many_args;
1979 else
1980 params = data->args;
1981 for (i = 0; i < sig->param_count; ++i) {
1982 int a_index = i + (sig->hasthis ? 1 : 0);
1983 if (sig->params [i]->byref) {
1984 sp [a_index].data.p = params [i];
1985 continue;
1987 type = rmethod->param_types [i];
1988 switch (type->type) {
1989 case MONO_TYPE_VALUETYPE:
1990 sp [a_index].data.p = params [i];
1991 break;
1992 case MONO_TYPE_GENERICINST:
1993 if (MONO_TYPE_IS_REFERENCE (type))
1994 sp [a_index].data.p = *(gpointer*)params [i];
1995 else
1996 sp [a_index].data.vt = params [i];
1997 break;
1998 default:
1999 stackval_from_data (type, &sp [a_index], params [i], FALSE);
2000 break;
2004 memset (&result, 0, sizeof (result));
2006 InterpFrame frame = {0};
2007 frame.imethod = data->rmethod;
2008 frame.stack = sp;
2009 frame.retval = &result;
2011 type = rmethod->rtype;
2012 switch (type->type) {
2013 case MONO_TYPE_GENERICINST:
2014 if (!MONO_TYPE_IS_REFERENCE (type))
2015 result.data.vt = data->res;
2016 break;
2017 case MONO_TYPE_VALUETYPE:
2018 result.data.vt = data->res;
2019 break;
2020 default:
2021 break;
2024 context->stack_pointer = (guchar*)(sp + sig->hasthis + sig->param_count);
2026 interp_exec_method (&frame, context, NULL);
2028 context->stack_pointer = (guchar*)sp;
2030 g_assert (!context->has_resume_state);
2032 if (rmethod->needs_thread_attach)
2033 mono_threads_detach_coop (orig_domain, &attach_cookie);
2035 if (mono_llvm_only) {
2036 if (context->has_resume_state)
2037 mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
2038 } else {
2039 g_assert (!context->has_resume_state);
2042 type = rmethod->rtype;
2043 switch (type->type) {
2044 case MONO_TYPE_VOID:
2045 break;
2046 case MONO_TYPE_OBJECT:
2047 /* No need for a write barrier */
2048 *(MonoObject**)data->res = (MonoObject*)result.data.p;
2049 break;
2050 case MONO_TYPE_GENERICINST:
2051 if (MONO_TYPE_IS_REFERENCE (type)) {
2052 *(MonoObject**)data->res = (MonoObject*)result.data.p;
2053 } else {
2054 /* Already set before the call */
2056 break;
2057 case MONO_TYPE_VALUETYPE:
2058 /* Already set before the call */
2059 break;
2060 default:
2061 stackval_to_data (type, &result, data->res, FALSE);
2062 break;
2066 static stackval *
2067 do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2069 #ifdef ENABLE_NETCORE
2070 if (save_last_error)
2071 mono_marshal_clear_last_error ();
2072 #endif
2074 switch (op) {
2075 case MINT_ICALL_V_V: {
2076 typedef void (*T)(void);
2077 T func = (T)ptr;
2078 func ();
2079 break;
2081 case MINT_ICALL_V_P: {
2082 typedef gpointer (*T)(void);
2083 T func = (T)ptr;
2084 sp++;
2085 sp [-1].data.p = func ();
2086 break;
2088 case MINT_ICALL_P_V: {
2089 typedef void (*T)(gpointer);
2090 T func = (T)ptr;
2091 func (sp [-1].data.p);
2092 sp --;
2093 break;
2095 case MINT_ICALL_P_P: {
2096 typedef gpointer (*T)(gpointer);
2097 T func = (T)ptr;
2098 sp [-1].data.p = func (sp [-1].data.p);
2099 break;
2101 case MINT_ICALL_PP_V: {
2102 typedef void (*T)(gpointer,gpointer);
2103 T func = (T)ptr;
2104 sp -= 2;
2105 func (sp [0].data.p, sp [1].data.p);
2106 break;
2108 case MINT_ICALL_PP_P: {
2109 typedef gpointer (*T)(gpointer,gpointer);
2110 T func = (T)ptr;
2111 --sp;
2112 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
2113 break;
2115 case MINT_ICALL_PPP_V: {
2116 typedef void (*T)(gpointer,gpointer,gpointer);
2117 T func = (T)ptr;
2118 sp -= 3;
2119 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
2120 break;
2122 case MINT_ICALL_PPP_P: {
2123 typedef gpointer (*T)(gpointer,gpointer,gpointer);
2124 T func = (T)ptr;
2125 sp -= 2;
2126 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
2127 break;
2129 case MINT_ICALL_PPPP_V: {
2130 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
2131 T func = (T)ptr;
2132 sp -= 4;
2133 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
2134 break;
2136 case MINT_ICALL_PPPP_P: {
2137 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
2138 T func = (T)ptr;
2139 sp -= 3;
2140 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
2141 break;
2143 case MINT_ICALL_PPPPP_V: {
2144 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2145 T func = (T)ptr;
2146 sp -= 5;
2147 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
2148 break;
2150 case MINT_ICALL_PPPPP_P: {
2151 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2152 T func = (T)ptr;
2153 sp -= 4;
2154 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);
2155 break;
2157 case MINT_ICALL_PPPPPP_V: {
2158 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2159 T func = (T)ptr;
2160 sp -= 6;
2161 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);
2162 break;
2164 case MINT_ICALL_PPPPPP_P: {
2165 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2166 T func = (T)ptr;
2167 sp -= 5;
2168 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);
2169 break;
2171 default:
2172 g_assert_not_reached ();
2175 if (save_last_error)
2176 mono_marshal_set_last_error ();
2178 /* convert the native representation to the stackval representation */
2179 if (sig)
2180 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2182 return sp;
2185 /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2186 #ifdef _MSC_VER
2187 #pragma optimize ("", off)
2188 #endif
2189 // Do not inline in case order of frame addresses matters, and maybe other reasons.
2190 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2191 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2193 MonoLMFExt ext;
2194 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2196 sp = do_icall (sig, op, sp, ptr, save_last_error);
2198 interp_pop_lmf (&ext);
2200 goto exit_icall; // prevent unused label warning in some configurations
2201 exit_icall:
2202 return sp;
2204 #ifdef _MSC_VER
2205 #pragma optimize ("", on)
2206 #endif
2208 typedef struct {
2209 int pindex;
2210 gpointer jit_wrapper;
2211 gpointer *args;
2212 MonoFtnDesc ftndesc;
2213 } JitCallCbData;
2215 /* Callback called by mono_llvm_cpp_catch_exception () */
2216 static void
2217 jit_call_cb (gpointer arg)
2219 JitCallCbData *cb_data = (JitCallCbData*)arg;
2220 gpointer jit_wrapper = cb_data->jit_wrapper;
2221 int pindex = cb_data->pindex;
2222 gpointer *args = cb_data->args;
2223 MonoFtnDesc *ftndesc = &cb_data->ftndesc;
2225 switch (pindex) {
2226 case 0: {
2227 typedef void (*T)(gpointer);
2228 T func = (T)jit_wrapper;
2230 func (ftndesc);
2231 break;
2233 case 1: {
2234 typedef void (*T)(gpointer, gpointer);
2235 T func = (T)jit_wrapper;
2237 func (args [0], ftndesc);
2238 break;
2240 case 2: {
2241 typedef void (*T)(gpointer, gpointer, gpointer);
2242 T func = (T)jit_wrapper;
2244 func (args [0], args [1], ftndesc);
2245 break;
2247 case 3: {
2248 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2249 T func = (T)jit_wrapper;
2251 func (args [0], args [1], args [2], ftndesc);
2252 break;
2254 case 4: {
2255 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2256 T func = (T)jit_wrapper;
2258 func (args [0], args [1], args [2], args [3], ftndesc);
2259 break;
2261 case 5: {
2262 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2263 T func = (T)jit_wrapper;
2265 func (args [0], args [1], args [2], args [3], args [4], ftndesc);
2266 break;
2268 case 6: {
2269 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2270 T func = (T)jit_wrapper;
2272 func (args [0], args [1], args [2], args [3], args [4], args [5], ftndesc);
2273 break;
2275 case 7: {
2276 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2277 T func = (T)jit_wrapper;
2279 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], ftndesc);
2280 break;
2282 case 8: {
2283 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2284 T func = (T)jit_wrapper;
2286 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], ftndesc);
2287 break;
2289 default:
2290 g_assert_not_reached ();
2291 break;
2295 enum {
2296 /* Pass stackval->data.p */
2297 JIT_ARG_BYVAL,
2298 /* Pass &stackval->data.p */
2299 JIT_ARG_BYREF
2302 enum {
2303 JIT_RET_VOID,
2304 JIT_RET_SCALAR,
2305 JIT_RET_VTYPE
2308 typedef struct _JitCallInfo JitCallInfo;
2309 struct _JitCallInfo {
2310 gpointer addr;
2311 gpointer extra_arg;
2312 gpointer wrapper;
2313 MonoMethodSignature *sig;
2314 guint8 *arginfo;
2315 gint32 vt_res_size;
2316 int ret_mt;
2319 static MONO_NEVER_INLINE void
2320 init_jit_call_info (InterpMethod *rmethod, MonoError *error)
2322 MonoMethodSignature *sig;
2323 JitCallInfo *cinfo;
2325 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2327 MonoMethod *method = rmethod->method;
2329 // FIXME: Memory management
2330 cinfo = g_new0 (JitCallInfo, 1);
2332 sig = mono_method_signature_internal (method);
2333 g_assert (sig);
2335 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2336 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2338 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2339 mono_error_assert_ok (error);
2341 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2342 return_if_nok (error);
2343 g_assert (addr);
2345 if (mono_llvm_only)
2346 cinfo->addr = mini_llvmonly_add_method_wrappers (method, addr, FALSE, FALSE, &cinfo->extra_arg);
2347 else
2348 cinfo->addr = addr;
2349 cinfo->sig = sig;
2350 cinfo->wrapper = jit_wrapper;
2352 if (sig->ret->type != MONO_TYPE_VOID) {
2353 int mt = mint_type (sig->ret);
2354 if (mt == MINT_TYPE_VT) {
2355 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
2357 * We cache this size here, instead of the instruction stream of the
2358 * calling instruction, to save space for common callvirt instructions
2359 * that could end up doing a jit call.
2361 gint32 size = mono_class_value_size (klass, NULL);
2362 cinfo->vt_res_size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
2364 cinfo->ret_mt = mt;
2365 } else {
2366 cinfo->ret_mt = -1;
2369 if (sig->param_count) {
2370 cinfo->arginfo = g_new0 (guint8, sig->param_count);
2372 for (int i = 0; i < rmethod->param_count; ++i) {
2373 MonoType *t = rmethod->param_types [i];
2374 int mt = mint_type (t);
2375 if (sig->params [i]->byref) {
2376 cinfo->arginfo [i] = JIT_ARG_BYVAL;
2377 } else if (mt == MINT_TYPE_VT) {
2378 cinfo->arginfo [i] = JIT_ARG_BYVAL;
2379 } else if (mt == MINT_TYPE_O) {
2380 cinfo->arginfo [i] = JIT_ARG_BYREF;
2381 } else {
2382 /* stackval->data is an union */
2383 cinfo->arginfo [i] = JIT_ARG_BYREF;
2388 mono_memory_barrier ();
2389 rmethod->jit_call_info = cinfo;
2392 static MONO_NEVER_INLINE void
2393 do_jit_call (stackval *sp, unsigned char *vt_sp, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2395 guint8 res_buf [256];
2396 MonoLMFExt ext;
2397 JitCallInfo *cinfo;
2399 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2402 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2403 * by ref and return a return value using an explicit return value argument.
2405 if (G_UNLIKELY (!rmethod->jit_call_info)) {
2406 init_jit_call_info (rmethod, error);
2407 mono_error_assert_ok (error);
2409 cinfo = (JitCallInfo*)rmethod->jit_call_info;
2412 * Convert the arguments on the interpeter stack to the format expected by the gsharedvt_out wrapper.
2414 gpointer args [32];
2415 int pindex = 0;
2416 int stack_index = 0;
2417 if (rmethod->hasthis) {
2418 args [pindex ++] = sp [0].data.p;
2419 stack_index ++;
2421 switch (cinfo->ret_mt) {
2422 case -1:
2423 break;
2424 case MINT_TYPE_VT:
2425 args [pindex ++] = vt_sp;
2426 break;
2427 default:
2428 args [pindex ++] = res_buf;
2429 break;
2431 for (int i = 0; i < rmethod->param_count; ++i) {
2432 stackval *sval = &sp [stack_index + i];
2433 if (cinfo->arginfo [i] == JIT_ARG_BYVAL)
2434 args [pindex ++] = sval->data.p;
2435 else
2436 /* data is an union, so can use 'p' for all types */
2437 args [pindex ++] = &sval->data.p;
2440 JitCallCbData cb_data;
2441 memset (&cb_data, 0, sizeof (cb_data));
2442 cb_data.jit_wrapper = cinfo->wrapper;
2443 cb_data.pindex = pindex;
2444 cb_data.args = args;
2445 cb_data.ftndesc.addr = cinfo->addr;
2446 cb_data.ftndesc.arg = cinfo->extra_arg;
2448 interp_push_lmf (&ext, frame);
2449 gboolean thrown = FALSE;
2450 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2451 /* Catch the exception thrown by the native code using a try-catch */
2452 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2453 } else {
2454 jit_call_cb (&cb_data);
2456 interp_pop_lmf (&ext);
2457 if (thrown) {
2458 MonoObject *obj = mono_llvm_load_exception ();
2459 g_assert (obj);
2460 mono_error_set_exception_instance (error, (MonoException*)obj);
2461 return;
2464 if (cinfo->ret_mt != -1) {
2465 switch (cinfo->ret_mt) {
2466 case MINT_TYPE_O:
2467 sp->data.p = *(gpointer*)res_buf;
2468 break;
2469 case MINT_TYPE_I1:
2470 sp->data.i = *(gint8*)res_buf;
2471 break;
2472 case MINT_TYPE_U1:
2473 sp->data.i = *(guint8*)res_buf;
2474 break;
2475 case MINT_TYPE_I2:
2476 sp->data.i = *(gint16*)res_buf;
2477 break;
2478 case MINT_TYPE_U2:
2479 sp->data.i = *(guint16*)res_buf;
2480 break;
2481 case MINT_TYPE_I4:
2482 sp->data.i = *(gint32*)res_buf;
2483 break;
2484 case MINT_TYPE_I8:
2485 sp->data.l = *(gint64*)res_buf;
2486 break;
2487 case MINT_TYPE_R4:
2488 sp->data.f_r4 = *(float*)res_buf;
2489 break;
2490 case MINT_TYPE_R8:
2491 sp->data.f = *(double*)res_buf;
2492 break;
2493 case MINT_TYPE_VT:
2494 /* The result was written to vt_sp */
2495 sp->data.p = vt_sp;
2496 break;
2497 default:
2498 g_assert_not_reached ();
2503 static MONO_NEVER_INLINE void
2504 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2506 MonoLMFExt ext;
2507 interp_push_lmf (&ext, frame);
2508 tramp ();
2509 interp_pop_lmf (&ext);
2512 static MONO_NEVER_INLINE MonoException*
2513 do_transform_method (InterpFrame *frame, ThreadContext *context)
2515 MonoLMFExt ext;
2516 /* Don't push lmf if we have no interp data */
2517 gboolean push_lmf = frame->parent != NULL;
2518 ERROR_DECL (error);
2520 #if DEBUG_INTERP
2521 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
2522 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2523 g_free (mn);
2524 #endif
2526 /* Use the parent frame as the current frame is not complete yet */
2527 if (push_lmf)
2528 interp_push_lmf (&ext, frame->parent);
2530 mono_interp_transform_method (frame->imethod, context, error);
2532 if (push_lmf)
2533 interp_pop_lmf (&ext);
2535 return mono_error_convert_to_exception (error);
2538 static void
2539 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start)
2541 stackval *first_arg = sp - csig->param_count;
2542 guchar *vt_sp = vt_sp_start;
2545 * We need to have the varargs linearly on the stack so the ArgIterator
2546 * can iterate over them. We pass the signature first and then copy them
2547 * one by one on the vtstack. The callee (MINT_ARGLIST) will be able to
2548 * find this space by adding the current vt_sp pointer in the parent frame
2549 * with the amount of vtstack space used by the parameters.
2551 *(gpointer*)vt_sp = csig;
2552 vt_sp += sizeof (gpointer);
2554 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2555 int align, arg_size;
2556 arg_size = mono_type_stack_size (csig->params [i], &align);
2557 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2559 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2560 vt_sp += arg_size;
2565 * These functions are the entry points into the interpreter from compiled code.
2566 * They are called by the interp_in wrappers. They have the following signature:
2567 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2568 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2569 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2570 * more wrappers then these functions.
2571 * this/static * ret/void * 16 arguments -> 64 functions.
2574 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2575 InterpEntryData data; \
2576 (data).rmethod = (_method); \
2577 (data).res = (_res); \
2578 (data).this_arg = (_this_arg); \
2579 (data).many_args = NULL;
2581 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2582 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2583 interp_entry (&data); \
2585 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2586 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2587 (data).args [0] = arg1; \
2588 interp_entry (&data); \
2590 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2591 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2592 (data).args [0] = arg1; \
2593 (data).args [1] = arg2; \
2594 interp_entry (&data); \
2596 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2597 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2598 (data).args [0] = arg1; \
2599 (data).args [1] = arg2; \
2600 (data).args [2] = arg3; \
2601 interp_entry (&data); \
2603 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2604 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2605 (data).args [0] = arg1; \
2606 (data).args [1] = arg2; \
2607 (data).args [2] = arg3; \
2608 (data).args [3] = arg4; \
2609 interp_entry (&data); \
2611 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2612 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2613 (data).args [0] = arg1; \
2614 (data).args [1] = arg2; \
2615 (data).args [2] = arg3; \
2616 (data).args [3] = arg4; \
2617 (data).args [4] = arg5; \
2618 interp_entry (&data); \
2620 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2621 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2622 (data).args [0] = arg1; \
2623 (data).args [1] = arg2; \
2624 (data).args [2] = arg3; \
2625 (data).args [3] = arg4; \
2626 (data).args [4] = arg5; \
2627 (data).args [5] = arg6; \
2628 interp_entry (&data); \
2630 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2631 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2632 (data).args [0] = arg1; \
2633 (data).args [1] = arg2; \
2634 (data).args [2] = arg3; \
2635 (data).args [3] = arg4; \
2636 (data).args [4] = arg5; \
2637 (data).args [5] = arg6; \
2638 (data).args [6] = arg7; \
2639 interp_entry (&data); \
2641 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2642 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2643 (data).args [0] = arg1; \
2644 (data).args [1] = arg2; \
2645 (data).args [2] = arg3; \
2646 (data).args [3] = arg4; \
2647 (data).args [4] = arg5; \
2648 (data).args [5] = arg6; \
2649 (data).args [6] = arg7; \
2650 (data).args [7] = arg8; \
2651 interp_entry (&data); \
2654 #define ARGLIST0 InterpMethod *rmethod
2655 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2656 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2657 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2658 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2659 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2660 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2661 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2662 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2664 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2665 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2666 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2667 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2668 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2669 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2670 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2671 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2672 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2673 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2674 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2675 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2676 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2677 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2678 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2679 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2680 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2681 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2682 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2683 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2684 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2685 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2686 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2687 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2688 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2689 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2690 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2691 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2692 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2693 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2694 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2695 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2696 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2697 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2698 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2699 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2701 #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
2703 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2704 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2705 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2706 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2708 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2709 static void
2710 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2712 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2713 data.many_args = args;
2714 interp_entry (&data);
2717 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2719 // inline so we can alloc on stack
2720 #define alloc_storage_for_stackval(s, t, p) do { \
2721 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2722 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2723 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2724 if (p) \
2725 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2726 else \
2727 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2729 } while (0)
2731 // Do not inline in case order of frame addresses matters.
2732 static MONO_NEVER_INLINE void
2733 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2735 ThreadContext *context;
2736 stackval *sp;
2737 stackval result;
2738 MonoMethod *method;
2739 MonoMethodSignature *sig;
2740 CallContext *ccontext = (CallContext*) ccontext_untyped;
2741 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2742 gpointer orig_domain = NULL, attach_cookie;
2743 int i;
2745 if (rmethod->needs_thread_attach)
2746 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2748 context = get_context ();
2749 sp = (stackval*)context->stack_pointer;
2751 method = rmethod->method;
2752 sig = mono_method_signature_internal (method);
2753 if (method->string_ctor) {
2754 MonoMethodSignature *newsig = g_alloca (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
2755 memcpy (newsig, sig, mono_metadata_signature_size (sig));
2756 newsig->ret = m_class_get_byval_arg (mono_defaults.string_class);
2757 sig = newsig;
2760 /* Allocate storage for value types */
2761 for (i = 0; i < sig->param_count; i++) {
2762 MonoType *type = sig->params [i];
2763 alloc_storage_for_stackval (&sp [i + sig->hasthis], type, sig->pinvoke);
2766 if (sig->ret->type != MONO_TYPE_VOID)
2767 alloc_storage_for_stackval (&result, sig->ret, sig->pinvoke);
2769 InterpFrame frame = {0};
2770 frame.imethod = rmethod;
2771 frame.stack = sp;
2772 frame.retval = &result;
2774 /* Copy the args saved in the trampoline to the frame stack */
2775 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2777 context->stack_pointer = (guchar*)(sp + sig->hasthis + sig->param_count);
2779 interp_exec_method (&frame, context, NULL);
2781 context->stack_pointer = (guchar*)sp;
2782 g_assert (!context->has_resume_state);
2784 if (rmethod->needs_thread_attach)
2785 mono_threads_detach_coop (orig_domain, &attach_cookie);
2787 /* Write back the return value */
2788 /* 'frame' is still valid */
2789 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2792 #else
2794 static void
2795 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2797 g_assert_not_reached ();
2800 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2802 static InterpMethod*
2803 lookup_method_pointer (gpointer addr)
2805 MonoDomain *domain = mono_domain_get ();
2806 MonoJitDomainInfo *info = domain_jit_info (domain);
2807 InterpMethod *res = NULL;
2809 mono_domain_lock (domain);
2810 if (info->interp_method_pointer_hash)
2811 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2812 mono_domain_unlock (domain);
2814 return res;
2817 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2818 static void
2819 interp_no_native_to_managed (void)
2821 g_error ("interpreter: native-to-managed transition not available on this platform");
2823 #endif
2825 static void
2826 no_llvmonly_interp_method_pointer (void)
2828 g_assert_not_reached ();
2832 * interp_create_method_pointer_llvmonly:
2834 * Return an ftndesc for entering the interpreter and executing METHOD.
2836 static MonoFtnDesc*
2837 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2839 MonoDomain *domain = mono_domain_get ();
2840 gpointer addr, entry_func, entry_wrapper;
2841 MonoMethodSignature *sig;
2842 MonoMethod *wrapper;
2843 MonoJitDomainInfo *info;
2844 InterpMethod *imethod;
2846 imethod = mono_interp_get_imethod (domain, method, error);
2847 return_val_if_nok (error, NULL);
2849 if (unbox) {
2850 if (imethod->llvmonly_unbox_entry)
2851 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2852 } else {
2853 if (imethod->jit_entry)
2854 return (MonoFtnDesc*)imethod->jit_entry;
2857 sig = mono_method_signature_internal (method);
2860 * The entry functions need access to the method to call, so we have
2861 * to use a ftndesc. The caller uses a normal signature, while the
2862 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2863 * a gsharedvt_in_sig wrapper.
2864 * We use a gsharedvt_in_sig wrapper instead of an interp_in wrapper, because they
2865 * are mostly the same, and they are already generated. The exception is the
2866 * wrappers for methods with more than 8 arguments, those are different.
2868 if (sig->param_count > MAX_INTERP_ENTRY_ARGS)
2869 wrapper = mini_get_interp_in_wrapper (sig);
2870 else
2871 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2873 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2874 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2875 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2876 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2878 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2879 entry_func = (gpointer)interp_entry_general;
2880 } else if (sig->hasthis) {
2881 if (sig->ret->type == MONO_TYPE_VOID)
2882 entry_func = entry_funcs_instance [sig->param_count];
2883 else
2884 entry_func = entry_funcs_instance_ret [sig->param_count];
2885 } else {
2886 if (sig->ret->type == MONO_TYPE_VOID)
2887 entry_func = entry_funcs_static [sig->param_count];
2888 else
2889 entry_func = entry_funcs_static_ret [sig->param_count];
2891 g_assert (entry_func);
2893 /* Encode unbox in the lower bit of imethod */
2894 gpointer entry_arg = imethod;
2895 if (unbox)
2896 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2897 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2899 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2901 info = domain_jit_info (domain);
2902 mono_domain_lock (domain);
2903 if (!info->interp_method_pointer_hash)
2904 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2905 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2906 mono_domain_unlock (domain);
2908 mono_memory_barrier ();
2909 if (unbox)
2910 imethod->llvmonly_unbox_entry = addr;
2911 else
2912 imethod->jit_entry = addr;
2914 return (MonoFtnDesc*)addr;
2918 * interp_create_method_pointer:
2920 * Return a function pointer which can be used to call METHOD using the
2921 * interpreter. Return NULL for methods which are not supported.
2923 static gpointer
2924 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2926 gpointer addr, entry_func, entry_wrapper = NULL;
2927 MonoDomain *domain = mono_domain_get ();
2928 MonoJitDomainInfo *info;
2929 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2931 if (imethod->jit_entry)
2932 return imethod->jit_entry;
2934 if (compile && !imethod->transformed) {
2935 /* Return any errors from method compilation */
2936 mono_interp_transform_method (imethod, get_context (), error);
2937 return_val_if_nok (error, NULL);
2940 MonoMethodSignature *sig = mono_method_signature_internal (method);
2941 if (method->string_ctor) {
2942 MonoMethodSignature *newsig = g_alloca (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
2943 memcpy (newsig, sig, mono_metadata_signature_size (sig));
2944 newsig->ret = m_class_get_byval_arg (mono_defaults.string_class);
2945 sig = newsig;
2948 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2949 entry_func = (gpointer)interp_entry_general;
2950 } else if (sig->hasthis) {
2951 if (sig->ret->type == MONO_TYPE_VOID)
2952 entry_func = entry_funcs_instance [sig->param_count];
2953 else
2954 entry_func = entry_funcs_instance_ret [sig->param_count];
2955 } else {
2956 if (sig->ret->type == MONO_TYPE_VOID)
2957 entry_func = entry_funcs_static [sig->param_count];
2958 else
2959 entry_func = entry_funcs_static_ret [sig->param_count];
2962 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2963 #ifdef HOST_WASM
2964 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2965 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
2966 MonoMethod *orig_method = info->d.native_to_managed.method;
2969 * These are called from native code. Ask the host app for a trampoline.
2971 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2972 ftndesc->addr = entry_func;
2973 ftndesc->arg = imethod;
2975 addr = mono_wasm_get_native_to_interp_trampoline (orig_method, ftndesc);
2976 if (addr) {
2977 mono_memory_barrier ();
2978 imethod->jit_entry = addr;
2979 return addr;
2982 #ifdef ENABLE_NETCORE
2984 * The runtime expects a function pointer unique to method and
2985 * the native caller expects a function pointer with the
2986 * right signature, so fail right away.
2988 mono_error_set_platform_not_supported (error, "No native to managed transitions on this platform.");
2989 return NULL;
2990 #endif
2992 #endif
2993 return (gpointer)interp_no_native_to_managed;
2994 #endif
2996 if (mono_llvm_only) {
2997 /* The caller should call interp_create_method_pointer_llvmonly */
2998 //g_assert_not_reached ();
2999 return (gpointer)no_llvmonly_interp_method_pointer;
3002 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
3003 return imethod;
3005 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
3007 * Interp in wrappers get the argument in the rgctx register. If
3008 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
3009 * on that arch the rgctx register is not scratch, so we use a
3010 * separate temp register. We should update the wrappers for this
3011 * if we really care about those architectures (arm).
3013 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
3015 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
3016 #endif
3017 if (!entry_wrapper) {
3018 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
3019 g_assertion_message ("couldn't compile wrapper \"%s\" for \"%s\"",
3020 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
3021 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
3022 #else
3023 mono_error_cleanup (error);
3024 error_init_reuse (error);
3025 if (!mono_native_to_interp_trampoline) {
3026 if (mono_aot_only) {
3027 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
3028 } else {
3029 MonoTrampInfo *info;
3030 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
3031 mono_tramp_info_register (info, NULL);
3034 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
3035 /* We need the lmf wrapper only when being called from mixed mode */
3036 if (sig->pinvoke)
3037 entry_func = (gpointer)interp_entry_from_trampoline;
3038 else {
3039 static gpointer cached_func = NULL;
3040 if (!cached_func) {
3041 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);
3042 mono_memory_barrier ();
3044 entry_func = cached_func;
3046 #endif
3049 g_assert (entry_func);
3050 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
3051 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
3052 ftndesc->addr = entry_func;
3053 ftndesc->arg = imethod;
3054 mono_error_assert_ok (error);
3057 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
3058 * rgctx register using a trampoline.
3061 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
3063 info = domain_jit_info (domain);
3064 mono_domain_lock (domain);
3065 if (!info->interp_method_pointer_hash)
3066 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
3067 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
3068 mono_domain_unlock (domain);
3070 mono_memory_barrier ();
3071 imethod->jit_entry = addr;
3073 return addr;
3076 static void
3077 interp_free_method (MonoDomain *domain, MonoMethod *method)
3079 MonoJitDomainInfo *info = domain_jit_info (domain);
3081 mono_domain_jit_code_hash_lock (domain);
3082 /* InterpMethod is allocated in the domain mempool. We might haven't
3083 * allocated an InterpMethod for this instance yet */
3084 mono_internal_hash_table_remove (&info->interp_code_hash, method);
3085 mono_domain_jit_code_hash_unlock (domain);
3088 #if COUNT_OPS
3089 static long opcode_counts[MINT_LASTOP];
3091 #define COUNT_OP(op) opcode_counts[op]++
3092 #else
3093 #define COUNT_OP(op)
3094 #endif
3096 #if DEBUG_INTERP
3097 #define DUMP_INSTR() \
3098 if (tracing > 1) { \
3099 char *ins; \
3100 if (sp > frame->stack) { \
3101 ins = dump_stack (frame->stack, sp); \
3102 } else { \
3103 ins = g_strdup (""); \
3105 sp->data.l = 0; \
3106 output_indent (); \
3107 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
3108 char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
3109 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
3110 g_free (mn); \
3111 g_free (ins); \
3112 g_free (disasm); \
3114 #else
3115 #define DUMP_INSTR()
3116 #endif
3118 #define INIT_VTABLE(vtable) do { \
3119 if (G_UNLIKELY (!(vtable)->initialized)) { \
3120 mono_runtime_class_init_full ((vtable), error); \
3121 if (!is_ok (error)) \
3122 THROW_EX (mono_error_convert_to_exception (error), ip); \
3124 } while (0);
3126 static MonoObject*
3127 mono_interp_new (MonoDomain* domain, MonoClass* klass)
3129 ERROR_DECL (error);
3130 MonoObject* const object = mono_object_new_checked (domain, klass, error);
3131 mono_error_cleanup (error); // FIXME: do not swallow the error
3132 return object;
3135 static void
3136 mono_interp_load_remote_field (
3137 InterpMethod* imethod,
3138 MonoObject* o,
3139 const guint16* ip,
3140 stackval* sp)
3142 g_assert (o); // Caller checks and throws exception properly.
3144 void* addr;
3145 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
3147 #ifndef DISABLE_REMOTING
3148 gpointer tmp;
3149 if (mono_object_is_transparent_proxy (o)) {
3150 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3151 ERROR_DECL (error);
3152 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3153 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3154 } else
3155 #endif
3156 addr = (char*)o + field->offset;
3157 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3160 static
3161 guchar* // Return new vt_sp instead of take-address.
3162 mono_interp_load_remote_field_vt (
3163 InterpMethod* imethod,
3164 MonoObject* o,
3165 const guint16* ip,
3166 stackval* sp,
3167 guchar* vt_sp)
3169 g_assert (o); // Caller checks and throws exception properly.
3171 void* addr;
3172 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
3173 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
3174 int const i32 = mono_class_value_size (klass, NULL);
3176 #ifndef DISABLE_REMOTING
3177 gpointer tmp;
3178 if (mono_object_is_transparent_proxy (o)) {
3179 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3180 ERROR_DECL (error);
3181 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3182 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3183 } else
3184 #endif
3185 addr = (char*)o + field->offset;
3186 sp [-1].data.p = vt_sp;
3187 memcpy (vt_sp, addr, i32);
3188 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3191 static gboolean
3192 mono_interp_isinst (MonoObject* object, MonoClass* klass)
3194 ERROR_DECL (error);
3195 gboolean isinst;
3196 MonoClass *obj_class = mono_object_class (object);
3197 // mono_class_is_assignable_from_checked can't handle remoting casts
3198 if (mono_class_is_transparent_proxy (obj_class))
3199 isinst = mono_object_isinst_checked (object, klass, error) != NULL;
3200 else
3201 mono_class_is_assignable_from_checked (klass, obj_class, &isinst, error);
3202 mono_error_cleanup (error); // FIXME: do not swallow the error
3203 return isinst;
3206 static MONO_NEVER_INLINE InterpMethod*
3207 mono_interp_get_native_func_wrapper (InterpMethod* imethod, MonoMethodSignature* csignature, guchar* code)
3209 ERROR_DECL(error);
3211 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3212 MonoMarshalSpec** mspecs = g_newa0 (MonoMarshalSpec*, csignature->param_count + 1);
3214 MonoMethodPInvoke iinfo;
3215 memset (&iinfo, 0, sizeof (iinfo));
3217 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
3219 for (int i = csignature->param_count; i >= 0; i--)
3220 if (mspecs [i])
3221 mono_metadata_free_marshal_spec (mspecs [i]);
3223 InterpMethod *cmethod = mono_interp_get_imethod (imethod->domain, m, error);
3224 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3226 return cmethod;
3229 // Do not inline in case order of frame addresses matters.
3230 static MONO_NEVER_INLINE MonoException*
3231 mono_interp_leave (InterpFrame* parent_frame)
3233 InterpFrame frame = {parent_frame};
3235 stackval tmp_sp;
3237 * We need for mono_thread_get_undeniable_exception to be able to unwind
3238 * to check the abort threshold. For this to work we use frame as a
3239 * dummy frame that is stored in the lmf and serves as the transition frame
3241 do_icall_wrapper (&frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3243 return (MonoException*)tmp_sp.data.p;
3246 static void
3247 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3249 guint64 a_val = 0, b_val = 0;
3251 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3252 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3253 sp->data.i = (a_val & b_val) == b_val;
3256 static int
3257 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3259 InterpMethod* const imethod = frame->imethod;
3260 MonoClass* const c = (MonoClass*)imethod->data_items [ip [1]];
3262 int const size = mono_class_value_size (c, NULL);
3264 guint16 offset = ip [2];
3265 guint16 pop_vt_sp = !ip [3];
3267 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3268 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3270 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3273 static int
3274 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoObjectHandle tmp_handle)
3276 InterpMethod* const imethod = frame->imethod;
3278 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [ip [1]];
3279 MonoClass* const c = vtable->klass;
3281 int const size = mono_class_value_size (c, NULL);
3283 guint16 offset = ip [2];
3284 guint16 pop_vt_sp = !ip [3];
3286 MonoObject* o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3287 MONO_HANDLE_ASSIGN_RAW (tmp_handle, o);
3288 mono_value_copy_internal (mono_object_get_data (o), sp [-1 - offset].data.p, c);
3289 MONO_HANDLE_ASSIGN_RAW (tmp_handle, NULL);
3291 sp [-1 - offset].data.o = o;
3292 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3295 static void
3296 mono_interp_box (InterpFrame* frame, const guint16* ip, stackval* sp, MonoObjectHandle tmp_handle)
3298 MonoVTable * const vtable = (MonoVTable*)frame->imethod->data_items [ip [1]];
3299 guint16 const offset = ip [2];
3301 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3302 MONO_HANDLE_ASSIGN_RAW (tmp_handle, o);
3303 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (o), FALSE);
3304 MONO_HANDLE_ASSIGN_RAW (tmp_handle, NULL);
3306 sp [-1 - offset].data.o = o;
3309 static int
3310 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3312 InterpMethod* const imethod = frame->imethod;
3313 MonoClassField *field;
3315 MonoObject* const o = sp [-2].data.o;
3317 field = (MonoClassField*)imethod->data_items[ip [1]];
3318 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3319 int const i32 = mono_class_value_size (klass, NULL);
3321 #ifndef DISABLE_REMOTING
3322 if (mono_object_is_transparent_proxy (o)) {
3323 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3324 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3325 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3326 } else
3327 #endif
3328 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3330 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3333 // varargs in wasm consumes extra linear stack per call-site.
3334 // These g_warning/g_error wrappers fix that. It is not the
3335 // small wasm stack, but conserving it is still desirable.
3336 static void
3337 g_warning_d (const char *format, int d)
3339 g_warning (format, d);
3342 #if !USE_COMPUTED_GOTO
3343 static void
3344 interp_error_xsx (const char *format, int x1, const char *s, int x2)
3346 g_error (format, x1, s, x2);
3348 #endif
3350 static MONO_ALWAYS_INLINE gboolean
3351 method_entry (ThreadContext *context, InterpFrame *frame,
3352 #if DEBUG_INTERP
3353 int *out_tracing,
3354 #endif
3355 MonoException **out_ex)
3357 gboolean slow = FALSE;
3359 #if DEBUG_INTERP
3360 debug_enter (frame, out_tracing);
3361 #endif
3362 #if PROFILE_INTERP
3363 frame->imethod->calls++;
3364 #endif
3366 *out_ex = NULL;
3367 if (!G_UNLIKELY (frame->imethod->transformed)) {
3368 slow = TRUE;
3369 MonoException *ex = do_transform_method (frame, context);
3370 if (ex) {
3371 *out_ex = ex;
3373 * Initialize the stack base pointer here, in the uncommon branch, so we don't
3374 * need to check for it everytime when exitting a frame.
3376 frame->stack = (stackval*)context->stack_pointer;
3377 return slow;
3381 return slow;
3384 /* Save the state of the interpeter main loop into FRAME */
3385 #define SAVE_INTERP_STATE(frame) do { \
3386 frame->state.ip = ip; \
3387 frame->state.sp = sp; \
3388 frame->state.vt_sp = vt_sp; \
3389 frame->state.finally_ips = finally_ips; \
3390 } while (0)
3392 /* Load and clear state from FRAME */
3393 #define LOAD_INTERP_STATE(frame) do { \
3394 ip = frame->state.ip; \
3395 sp = frame->state.sp; \
3396 vt_sp = frame->state.vt_sp; \
3397 finally_ips = frame->state.finally_ips; \
3398 locals = (unsigned char *)frame->stack; \
3399 frame->state.ip = NULL; \
3400 } while (0)
3402 /* Initialize interpreter state for executing FRAME */
3403 #define INIT_INTERP_STATE(frame, _clause_args) do { \
3404 ip = _clause_args ? ((FrameClauseArgs *)_clause_args)->start_with_ip : (frame)->imethod->code; \
3405 locals = (unsigned char *)(frame)->stack; \
3406 vt_sp = (unsigned char *) locals + (frame)->imethod->total_locals_size; \
3407 sp = (stackval*)(vt_sp + (frame)->imethod->vt_stack_size); \
3408 finally_ips = NULL; \
3409 } while (0)
3411 #if PROFILE_INTERP
3412 static long total_executed_opcodes;
3413 #endif
3416 * If CLAUSE_ARGS is non-null, start executing from it.
3417 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3418 * to return error information.
3419 * FRAME is only valid until the next call to alloc_frame ().
3421 static MONO_NEVER_INLINE void
3422 interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args)
3424 InterpMethod *cmethod;
3425 MonoException *ex;
3426 ERROR_DECL(error);
3428 /* Interpreter main loop state (InterpState) */
3429 const guint16 *ip = NULL;
3430 stackval *sp;
3431 unsigned char *vt_sp;
3432 unsigned char *locals = NULL;
3433 GSList *finally_ips = NULL;
3435 #if DEBUG_INTERP
3436 int tracing = global_tracing;
3437 unsigned char *vtalloc;
3438 #endif
3439 #if USE_COMPUTED_GOTO
3440 static void * const in_labels[] = {
3441 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3442 #include "mintops.def"
3444 #endif
3446 HANDLE_FUNCTION_ENTER ();
3448 * GC SAFETY:
3450 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, we cannot rely on
3451 * scanning the stack or any registers. In order to make the code GC safe, every objref
3452 * handled by the code needs to be kept alive and pinned in any of the following ways:
3453 * - the object needs to be stored on the interpreter stack. In order to make sure the
3454 * object actually gets stored on the interp stack and the store is not optimized out,
3455 * the store/variable should be volatile.
3456 * - if the execution of an opcode requires an object not coming from interp stack to be
3457 * kept alive, the tmp_handle below can be used. This handle will keep only one object
3458 * pinned by the GC. Ideally, once this object is no longer needed, the handle should be
3459 * cleared. If we will need to have more objects pinned simultaneously, additional handles
3460 * can be reserved here.
3462 MonoObjectHandle tmp_handle = MONO_HANDLE_NEW (MonoObject, NULL);
3464 if (method_entry (context, frame,
3465 #if DEBUG_INTERP
3466 &tracing,
3467 #endif
3468 &ex)) {
3469 if (ex)
3470 THROW_EX (ex, NULL);
3471 EXCEPTION_CHECKPOINT;
3474 if (!clause_args) {
3475 context->stack_pointer = (guchar*)frame->stack + frame->imethod->alloca_size;
3476 /* Make sure the stack pointer is bumped before we store any references on the stack */
3477 mono_compiler_barrier ();
3480 INIT_INTERP_STATE (frame, clause_args);
3482 #if DEBUG_INTERP
3483 vtalloc = vt_sp;
3484 #endif
3486 if (clause_args && clause_args->filter_exception) {
3487 sp->data.p = clause_args->filter_exception;
3488 sp++;
3491 #ifdef ENABLE_EXPERIMENT_TIERED
3492 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0);
3493 #endif
3494 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3496 #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND)
3497 mono_threads_safepoint ();
3498 #endif
3499 main_loop:
3501 * using while (ip < end) may result in a 15% performance drop,
3502 * but it may be useful for debug
3504 while (1) {
3505 #if PROFILE_INTERP
3506 frame->imethod->opcounts++;
3507 total_executed_opcodes++;
3508 #endif
3509 MintOpcode opcode;
3510 #ifdef ENABLE_CHECKED_BUILD
3511 guchar *vt_start = (guchar*)frame->stack + frame->imethod->total_locals_size;
3512 guchar *sp_start = vt_start + frame->imethod->vt_stack_size;
3513 guchar *sp_end = sp_start + frame->imethod->stack_size;
3514 g_assert (locals == (guchar*)frame->stack);
3515 g_assert (vt_sp >= vt_start);
3516 g_assert (vt_sp <= sp_start);
3517 g_assert ((guchar*)sp >= sp_start);
3518 g_assert ((guchar*)sp <= sp_end);
3519 #endif
3520 DUMP_INSTR();
3521 MINT_IN_SWITCH (*ip) {
3522 MINT_IN_CASE(MINT_INITLOCALS)
3523 memset (locals + ip [1], 0, ip [2]);
3524 ip += 3;
3525 MINT_IN_BREAK;
3526 MINT_IN_CASE(MINT_NOP)
3527 MINT_IN_CASE(MINT_NIY)
3528 g_assert_not_reached ();
3529 MINT_IN_BREAK;
3530 MINT_IN_CASE(MINT_BREAK)
3531 ++ip;
3532 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3533 MINT_IN_BREAK;
3534 MINT_IN_CASE(MINT_BREAKPOINT)
3535 ++ip;
3536 mono_break ();
3537 MINT_IN_BREAK;
3538 MINT_IN_CASE(MINT_LDNULL)
3539 sp->data.p = NULL;
3540 ++ip;
3541 ++sp;
3542 MINT_IN_BREAK;
3543 MINT_IN_CASE(MINT_ARGLIST)
3544 sp->data.p = vt_sp;
3546 * We know we have been called by an MINT_CALL_VARARG and the amount of vtstack
3547 * used by the parameters is at ip [-1] (the last argument to MINT_CALL_VARARG that
3548 * is embedded in the instruction stream).
3550 *(gpointer*)sp->data.p = frame->parent->state.vt_sp + frame->parent->state.ip [-1];
3551 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3552 ++ip;
3553 ++sp;
3554 MINT_IN_BREAK;
3555 MINT_IN_CASE(MINT_VTRESULT) {
3556 int ret_size = ip [1];
3557 unsigned char *ret_vt_sp = vt_sp;
3558 vt_sp -= READ32(ip + 2);
3559 if (ret_size > 0) {
3560 memmove (vt_sp, ret_vt_sp, ret_size);
3561 sp [-1].data.p = vt_sp;
3562 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3564 ip += 4;
3565 MINT_IN_BREAK;
3567 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3568 MINT_IN_CASE(MINT_LDC_I4_M1)
3569 LDC(-1);
3570 MINT_IN_BREAK;
3571 MINT_IN_CASE(MINT_LDC_I4_0)
3572 LDC(0);
3573 MINT_IN_BREAK;
3574 MINT_IN_CASE(MINT_LDC_I4_1)
3575 LDC(1);
3576 MINT_IN_BREAK;
3577 MINT_IN_CASE(MINT_LDC_I4_2)
3578 LDC(2);
3579 MINT_IN_BREAK;
3580 MINT_IN_CASE(MINT_LDC_I4_3)
3581 LDC(3);
3582 MINT_IN_BREAK;
3583 MINT_IN_CASE(MINT_LDC_I4_4)
3584 LDC(4);
3585 MINT_IN_BREAK;
3586 MINT_IN_CASE(MINT_LDC_I4_5)
3587 LDC(5);
3588 MINT_IN_BREAK;
3589 MINT_IN_CASE(MINT_LDC_I4_6)
3590 LDC(6);
3591 MINT_IN_BREAK;
3592 MINT_IN_CASE(MINT_LDC_I4_7)
3593 LDC(7);
3594 MINT_IN_BREAK;
3595 MINT_IN_CASE(MINT_LDC_I4_8)
3596 LDC(8);
3597 MINT_IN_BREAK;
3598 MINT_IN_CASE(MINT_LDC_I4_S)
3599 sp->data.i = (short)ip [1];
3600 ip += 2;
3601 ++sp;
3602 MINT_IN_BREAK;
3603 MINT_IN_CASE(MINT_LDC_I4)
3604 ++ip;
3605 sp->data.i = READ32 (ip);
3606 ip += 2;
3607 ++sp;
3608 MINT_IN_BREAK;
3609 MINT_IN_CASE(MINT_LDC_I8)
3610 ++ip;
3611 sp->data.l = READ64 (ip);
3612 ip += 4;
3613 ++sp;
3614 MINT_IN_BREAK;
3615 MINT_IN_CASE(MINT_LDC_I8_S)
3616 sp->data.l = (short)ip [1];
3617 ip += 2;
3618 ++sp;
3619 MINT_IN_BREAK;
3620 MINT_IN_CASE(MINT_LDC_R4) {
3621 guint32 val;
3622 ++ip;
3623 val = READ32(ip);
3624 sp->data.f_r4 = * (float *)&val;
3625 ip += 2;
3626 ++sp;
3627 MINT_IN_BREAK;
3629 MINT_IN_CASE(MINT_LDC_R8)
3630 sp->data.l = READ64 (ip + 1); /* note union usage */
3631 ip += 5;
3632 ++sp;
3633 MINT_IN_BREAK;
3634 MINT_IN_CASE(MINT_DUP)
3635 sp [0] = sp[-1];
3636 ++sp;
3637 ++ip;
3638 MINT_IN_BREAK;
3639 MINT_IN_CASE(MINT_DUP_VT) {
3640 int const i32 = READ32 (ip + 1);
3641 sp->data.p = vt_sp;
3642 memcpy(sp->data.p, sp [-1].data.p, i32);
3643 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3644 ++sp;
3645 ip += 3;
3646 MINT_IN_BREAK;
3648 MINT_IN_CASE(MINT_POP) {
3649 sp--;
3650 ip++;
3651 MINT_IN_BREAK;
3653 MINT_IN_CASE(MINT_POP_VT) {
3654 int i32 = READ32 (ip + 1);
3655 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3656 sp--;
3657 ip += 3;
3658 MINT_IN_BREAK;
3660 MINT_IN_CASE(MINT_POP1) {
3661 sp [-2] = sp [-1];
3662 sp--;
3663 ip++;
3664 MINT_IN_BREAK;
3666 MINT_IN_CASE(MINT_JMP) {
3667 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
3668 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [ip [1]];
3670 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3671 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3673 if (!new_method->transformed) {
3674 error_init_reuse (error);
3676 mono_interp_transform_method (new_method, context, error);
3677 MonoException *ex = mono_error_convert_to_exception (error);
3678 if (ex)
3679 THROW_EX (ex, ip);
3680 EXCEPTION_CHECKPOINT;
3683 * It's possible for the caller stack frame to be smaller
3684 * than the callee stack frame (at the interp level)
3686 context->stack_pointer = (guchar*)frame->stack + new_method->alloca_size;
3687 frame->imethod = new_method;
3688 vt_sp = locals + frame->imethod->total_locals_size;
3689 #if DEBUG_INTERP
3690 vtalloc = vt_sp;
3691 #endif
3692 sp = (stackval*)(vt_sp + frame->imethod->vt_stack_size);
3693 ip = frame->imethod->code;
3694 MINT_IN_BREAK;
3696 MINT_IN_CASE(MINT_CALL_DELEGATE) {
3697 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3698 int param_count = csignature->param_count;
3699 MonoDelegate *del = (MonoDelegate*) sp [-param_count - 1].data.o;
3700 gboolean is_multicast = del->method == NULL;
3701 InterpMethod *del_imethod = (InterpMethod*)del->interp_invoke_impl;
3703 if (!del_imethod) {
3704 if (is_multicast) {
3705 error_init_reuse (error);
3706 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
3707 del_imethod = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
3708 del->interp_invoke_impl = del_imethod;
3709 mono_error_assert_ok (error);
3710 } else if (!del->interp_method) {
3711 // Not created from interpreted code
3712 error_init_reuse (error);
3713 g_assert (del->method);
3714 del_imethod = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
3715 del->interp_method = del_imethod;
3716 del->interp_invoke_impl = del_imethod;
3717 mono_error_assert_ok (error);
3718 } else {
3719 del_imethod = (InterpMethod*)del->interp_method;
3720 if (del_imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3721 error_init_reuse (error);
3722 del_imethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (del_imethod->method, FALSE, FALSE), error);
3723 mono_error_assert_ok (error);
3724 del->interp_invoke_impl = del_imethod;
3725 } else if (del_imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL && !del->target) {
3726 // 'this' is passed dynamically, we need to recompute the target method
3727 // with each call
3728 del_imethod = get_virtual_method (del_imethod, sp [-param_count].data.o->vtable);
3729 } else {
3730 del->interp_invoke_impl = del_imethod;
3734 cmethod = del_imethod;
3735 vt_sp -= ip [2];
3736 sp -= param_count + 1;
3737 if (!is_multicast) {
3738 if (cmethod->param_count == param_count + 1) {
3739 // Target method is static but the delegate has a target object. We handle
3740 // this separately from the case below, because, for these calls, the instance
3741 // is allowed to be null.
3742 sp [0].data.o = del->target;
3743 } else if (del->target) {
3744 MonoObject *this_arg = del->target;
3746 // replace the MonoDelegate* on the stack with 'this' pointer
3747 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3748 gpointer unboxed = mono_object_unbox_internal (this_arg);
3749 sp [0].data.p = unboxed;
3750 } else {
3751 sp [0].data.o = this_arg;
3753 } else {
3754 // skip the delegate pointer for static calls
3755 // FIXME we could avoid memmove
3756 memmove (sp, sp + 1, param_count * sizeof (stackval));
3759 ip += 3;
3761 goto call;
3763 MINT_IN_CASE(MINT_CALLI) {
3764 MonoMethodSignature *csignature;
3766 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3767 --sp;
3769 cmethod = (InterpMethod*)sp->data.p;
3770 if (cmethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3771 cmethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (cmethod->method, FALSE, FALSE), error);
3772 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3775 /* decrement by the actual number of args */
3776 sp -= csignature->param_count;
3777 if (csignature->hasthis)
3778 --sp;
3779 vt_sp -= ip [2];
3781 if (csignature->hasthis) {
3782 MonoObject *this_arg = (MonoObject*)sp->data.p;
3784 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3785 gpointer unboxed = mono_object_unbox_internal (this_arg);
3786 sp [0].data.p = unboxed;
3789 ip += 3;
3791 goto call;
3793 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3794 gpointer target_ip = sp [-1].data.p;
3795 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3796 int opcode = ip [2];
3797 gboolean save_last_error = ip [3];
3799 sp--;
3800 /* for calls, have ip pointing at the start of next instruction */
3801 frame->state.ip = ip + 4;
3803 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3804 EXCEPTION_CHECKPOINT_GC_UNSAFE;
3805 CHECK_RESUME_STATE (context);
3806 ip += 4;
3807 MINT_IN_BREAK;
3809 MINT_IN_CASE(MINT_CALLI_NAT_DYNAMIC) {
3810 MonoMethodSignature* csignature;
3812 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3814 --sp;
3815 guchar* code = (guchar*)sp->data.p;
3817 /* decrement by the actual number of args */
3818 sp -= csignature->param_count;
3819 if (csignature->hasthis)
3820 --sp;
3821 vt_sp -= ip [2];
3823 cmethod = mono_interp_get_native_func_wrapper (frame->imethod, csignature, code);
3825 ip += 3;
3826 goto call;
3828 MINT_IN_CASE(MINT_CALLI_NAT) {
3829 MonoMethodSignature* csignature;
3830 stackval retval;
3832 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3834 --sp;
3835 guchar* const code = (guchar*)sp->data.p;
3837 /* decrement by the actual number of args */
3838 sp -= csignature->param_count;
3839 if (csignature->hasthis)
3840 --sp;
3841 vt_sp -= ip [2];
3842 /* If this is a vt return, the pinvoke will write the result directly to vt_sp */
3843 retval.data.p = vt_sp;
3845 gboolean save_last_error = ip [4];
3846 gpointer *cache = (gpointer*)&frame->imethod->data_items [ip [5]];
3847 /* for calls, have ip pointing at the start of next instruction */
3848 frame->state.ip = ip + 6;
3849 ves_pinvoke_method (csignature, (MonoFuncV)code, context, frame, &retval, save_last_error, cache, sp);
3851 EXCEPTION_CHECKPOINT_GC_UNSAFE;
3852 CHECK_RESUME_STATE (context);
3854 if (csignature->ret->type != MONO_TYPE_VOID) {
3855 *sp = retval;
3856 vt_sp += ip [3];
3857 sp++;
3859 ip += 6;
3860 MINT_IN_BREAK;
3862 MINT_IN_CASE(MINT_CALLVIRT_FAST) {
3863 MonoObject *this_arg;
3864 int slot;
3866 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3867 slot = (gint16)ip [2];
3869 /* decrement by the actual number of args */
3870 sp -= cmethod->param_count + cmethod->hasthis;
3871 vt_sp -= ip [3];
3872 this_arg = (MonoObject*)sp->data.p;
3873 ip += 4;
3875 cmethod = get_virtual_method_fast (cmethod, this_arg->vtable, slot);
3876 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) {
3877 /* unbox */
3878 gpointer unboxed = mono_object_unbox_internal (this_arg);
3879 sp [0].data.p = unboxed;
3882 InterpMethodCodeType code_type = cmethod->code_type;
3884 g_assert (code_type == IMETHOD_CODE_UNKNOWN ||
3885 code_type == IMETHOD_CODE_INTERP ||
3886 code_type == IMETHOD_CODE_COMPILED);
3888 if (G_UNLIKELY (code_type == IMETHOD_CODE_UNKNOWN)) {
3889 MonoMethodSignature *sig = mono_method_signature_internal (cmethod->method);
3890 if (mono_interp_jit_call_supported (cmethod->method, sig))
3891 code_type = IMETHOD_CODE_COMPILED;
3892 else
3893 code_type = IMETHOD_CODE_INTERP;
3894 cmethod->code_type = code_type;
3897 if (code_type == IMETHOD_CODE_INTERP) {
3899 goto call;
3901 } else if (code_type == IMETHOD_CODE_COMPILED) {
3902 frame->state.ip = ip;
3903 error_init_reuse (error);
3904 do_jit_call (sp, vt_sp, frame, cmethod, error);
3905 if (!is_ok (error)) {
3906 MonoException *ex = mono_error_convert_to_exception (error);
3907 THROW_EX (ex, ip);
3910 CHECK_RESUME_STATE (context);
3912 if (cmethod->rtype->type != MONO_TYPE_VOID) {
3913 sp++;
3914 vt_sp += ((JitCallInfo*)cmethod->jit_call_info)->vt_res_size;
3918 MINT_IN_BREAK;
3920 MINT_IN_CASE(MINT_CALL_VARARG) {
3921 MonoMethodSignature *csig;
3923 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3925 /* The real signature for vararg calls */
3926 csig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3928 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3929 copy_varargs_vtstack (csig, sp, vt_sp);
3930 vt_sp -= ip [3];
3932 /* decrement by the actual number of args */
3933 // FIXME This seems excessive: frame and csig param_count.
3934 sp -= cmethod->param_count + cmethod->hasthis + csig->param_count - csig->sentinelpos;
3936 ip += 4;
3937 goto call;
3939 MINT_IN_CASE(MINT_CALLVIRT) {
3940 // FIXME CALLVIRT opcodes are not used on netcore. We should kill them.
3941 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3943 /* decrement by the actual number of args */
3944 sp -= ip [2];
3945 vt_sp -= ip [3];
3947 MonoObject *this_arg = (MonoObject*)sp->data.p;
3949 cmethod = get_virtual_method (cmethod, this_arg->vtable);
3950 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) {
3951 /* unbox */
3952 gpointer unboxed = mono_object_unbox_internal (this_arg);
3953 sp [0].data.p = unboxed;
3956 #ifdef ENABLE_EXPERIMENT_TIERED
3957 ip += 5;
3958 #else
3959 ip += 4;
3960 #endif
3961 goto call;
3963 MINT_IN_CASE(MINT_CALL) {
3964 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3966 /* decrement by the actual number of args */
3967 sp -= ip [2];
3968 vt_sp -= ip [3];
3970 #ifdef ENABLE_EXPERIMENT_TIERED
3971 ip += 5;
3972 #else
3973 ip += 4;
3974 #endif
3975 call:
3977 * Make a non-recursive call by loading the new interpreter state based on child frame,
3978 * and going back to the main loop.
3980 SAVE_INTERP_STATE (frame);
3982 // Allocate child frame.
3983 // FIXME: Add stack overflow checks
3985 InterpFrame *child_frame = frame->next_free;
3986 if (!child_frame) {
3987 child_frame = g_newa0 (InterpFrame, 1);
3988 // Not free currently, but will be when allocation attempted.
3989 frame->next_free = child_frame;
3991 reinit_frame (child_frame, frame, cmethod, sp);
3992 frame = child_frame;
3994 if (method_entry (context, frame,
3995 #if DEBUG_INTERP
3996 &tracing,
3997 #endif
3998 &ex)) {
3999 if (ex)
4000 THROW_EX (ex, NULL);
4001 EXCEPTION_CHECKPOINT;
4004 context->stack_pointer = (guchar*)sp + cmethod->alloca_size;
4005 /* Make sure the stack pointer is bumped before we store any references on the stack */
4006 mono_compiler_barrier ();
4008 INIT_INTERP_STATE (frame, NULL);
4010 MINT_IN_BREAK;
4012 MINT_IN_CASE(MINT_JIT_CALL) {
4013 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
4014 error_init_reuse (error);
4015 sp -= rmethod->param_count + rmethod->hasthis;
4016 vt_sp -= ip [2];
4017 /* for calls, have ip pointing at the start of next instruction */
4018 frame->state.ip = ip + 3;
4019 do_jit_call (sp, vt_sp, frame, rmethod, error);
4020 if (!is_ok (error)) {
4021 MonoException *ex = mono_error_convert_to_exception (error);
4022 THROW_EX (ex, ip);
4025 CHECK_RESUME_STATE (context);
4027 if (rmethod->rtype->type != MONO_TYPE_VOID) {
4028 sp++;
4029 vt_sp += ((JitCallInfo*)rmethod->jit_call_info)->vt_res_size;
4031 ip += 3;
4033 MINT_IN_BREAK;
4035 MINT_IN_CASE(MINT_JIT_CALL2) {
4036 #ifdef ENABLE_EXPERIMENT_TIERED
4037 InterpMethod *rmethod = (InterpMethod *) READ64 (ip + 1);
4039 error_init_reuse (error);
4041 sp -= rmethod->param_count + rmethod->hasthis;
4042 frame->state.ip = ip + 5;
4043 do_jit_call (sp, vt_sp, frame, rmethod, error);
4044 if (!is_ok (error)) {
4045 MonoException *ex = mono_error_convert_to_exception (error);
4046 THROW_EX (ex, ip);
4049 CHECK_RESUME_STATE (context);
4051 if (rmethod->rtype->type != MONO_TYPE_VOID)
4052 sp++;
4053 ip += 5;
4054 #else
4055 g_error ("MINT_JIT_ICALL2 shouldn't be used");
4056 #endif
4057 MINT_IN_BREAK;
4059 MINT_IN_CASE(MINT_CALLRUN) {
4060 #ifndef ENABLE_NETCORE
4061 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [1]];
4062 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
4064 sp->data.p = vt_sp;
4065 stackval *retval = sp;
4067 sp -= sig->param_count;
4068 if (sig->hasthis)
4069 sp--;
4071 MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval);
4072 if (ex)
4073 THROW_EX (ex, ip);
4075 if (sig->ret->type != MONO_TYPE_VOID) {
4076 *sp = *retval;
4077 sp++;
4079 ip += 3;
4080 #else
4081 g_assert_not_reached ();
4082 #endif
4083 MINT_IN_BREAK;
4085 MINT_IN_CASE(MINT_RET)
4086 --sp;
4087 if (frame->parent) {
4088 frame->parent->state.sp [0] = *sp;
4089 frame->parent->state.sp++;
4090 } else {
4091 // FIXME This can only happen in a few wrappers. Add separate opcode for it
4092 *frame->retval = *sp;
4094 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
4095 goto exit_frame;
4096 MINT_IN_CASE(MINT_RET_VOID)
4097 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
4098 goto exit_frame;
4099 MINT_IN_CASE(MINT_RET_VT) {
4100 int const i32 = READ32 (ip + 1);
4101 --sp;
4102 if (frame->parent) {
4103 gpointer dest_vt = frame->parent->state.vt_sp;
4104 // Push the valuetype in the parent frame. parent->state.sp [0] can be inside
4105 // vt to be returned, so we need to copy it before updating sp [0].
4106 memcpy (dest_vt, sp->data.p, i32);
4107 frame->parent->state.sp [0].data.p = dest_vt;
4108 frame->parent->state.sp++;
4109 frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4110 } else {
4111 gpointer dest_vt = frame->retval->data.p;
4112 memcpy (dest_vt, sp->data.p, i32);
4114 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
4115 goto exit_frame;
4117 MINT_IN_CASE(MINT_RET_LOCALLOC)
4118 --sp;
4119 if (frame->parent) {
4120 frame->parent->state.sp [0] = *sp;
4121 frame->parent->state.sp++;
4122 } else {
4123 // FIXME This can only happen in a few wrappers. Add separate opcode for it
4124 *frame->retval = *sp;
4126 frame_data_allocator_pop (&context->data_stack, frame);
4127 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
4128 goto exit_frame;
4129 MINT_IN_CASE(MINT_RET_VOID_LOCALLOC)
4130 frame_data_allocator_pop (&context->data_stack, frame);
4131 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
4132 goto exit_frame;
4133 MINT_IN_CASE(MINT_RET_VT_LOCALLOC) {
4134 int const i32 = READ32 (ip + 1);
4135 --sp;
4136 if (frame->parent) {
4137 gpointer dest_vt = frame->parent->state.vt_sp;
4138 /* Push the valuetype in the parent frame */
4139 memcpy (dest_vt, sp->data.p, i32);
4140 frame->parent->state.sp [0].data.p = dest_vt;
4141 frame->parent->state.sp++;
4142 frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4143 } else {
4144 memcpy (frame->retval->data.p, sp->data.p, i32);
4146 frame_data_allocator_pop (&context->data_stack, frame);
4147 g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size));
4148 goto exit_frame;
4151 #ifdef ENABLE_EXPERIMENT_TIERED
4152 #define BACK_BRANCH_PROFILE(offset) do { \
4153 if (offset < 0) \
4154 mini_tiered_inc (frame->imethod->domain, frame->imethod->method, &frame->imethod->tiered_counter, 0); \
4155 } while (0);
4156 #else
4157 #define BACK_BRANCH_PROFILE(offset)
4158 #endif
4160 MINT_IN_CASE(MINT_BR_S) {
4161 short br_offset = (short) *(ip + 1);
4162 BACK_BRANCH_PROFILE (br_offset);
4163 ip += br_offset;
4164 MINT_IN_BREAK;
4166 MINT_IN_CASE(MINT_BR) {
4167 gint32 br_offset = (gint32) READ32(ip + 1);
4168 BACK_BRANCH_PROFILE (br_offset);
4169 ip += br_offset;
4170 MINT_IN_BREAK;
4173 #define ZEROP_S(datamem, op) \
4174 --sp; \
4175 if (sp->data.datamem op 0) { \
4176 gint16 br_offset = (gint16) ip [1]; \
4177 BACK_BRANCH_PROFILE (br_offset); \
4178 ip += br_offset; \
4179 } else \
4180 ip += 2;
4182 #define ZEROP(datamem, op) \
4183 --sp; \
4184 if (sp->data.datamem op 0) { \
4185 gint32 br_offset = (gint32)READ32(ip + 1); \
4186 BACK_BRANCH_PROFILE (br_offset); \
4187 ip += br_offset; \
4188 } else \
4189 ip += 3;
4191 MINT_IN_CASE(MINT_BRFALSE_I4_S)
4192 ZEROP_S(i, ==);
4193 MINT_IN_BREAK;
4194 MINT_IN_CASE(MINT_BRFALSE_I8_S)
4195 ZEROP_S(l, ==);
4196 MINT_IN_BREAK;
4197 MINT_IN_CASE(MINT_BRFALSE_R4_S)
4198 ZEROP_S(f_r4, ==);
4199 MINT_IN_BREAK;
4200 MINT_IN_CASE(MINT_BRFALSE_R8_S)
4201 ZEROP_S(f, ==);
4202 MINT_IN_BREAK;
4203 MINT_IN_CASE(MINT_BRFALSE_I4)
4204 ZEROP(i, ==);
4205 MINT_IN_BREAK;
4206 MINT_IN_CASE(MINT_BRFALSE_I8)
4207 ZEROP(l, ==);
4208 MINT_IN_BREAK;
4209 MINT_IN_CASE(MINT_BRFALSE_R4)
4210 ZEROP_S(f_r4, ==);
4211 MINT_IN_BREAK;
4212 MINT_IN_CASE(MINT_BRFALSE_R8)
4213 ZEROP_S(f, ==);
4214 MINT_IN_BREAK;
4215 MINT_IN_CASE(MINT_BRTRUE_I4_S)
4216 ZEROP_S(i, !=);
4217 MINT_IN_BREAK;
4218 MINT_IN_CASE(MINT_BRTRUE_I8_S)
4219 ZEROP_S(l, !=);
4220 MINT_IN_BREAK;
4221 MINT_IN_CASE(MINT_BRTRUE_R4_S)
4222 ZEROP_S(f_r4, !=);
4223 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_BRTRUE_R8_S)
4225 ZEROP_S(f, !=);
4226 MINT_IN_BREAK;
4227 MINT_IN_CASE(MINT_BRTRUE_I4)
4228 ZEROP(i, !=);
4229 MINT_IN_BREAK;
4230 MINT_IN_CASE(MINT_BRTRUE_I8)
4231 ZEROP(l, !=);
4232 MINT_IN_BREAK;
4233 MINT_IN_CASE(MINT_BRTRUE_R4)
4234 ZEROP(f_r4, !=);
4235 MINT_IN_BREAK;
4236 MINT_IN_CASE(MINT_BRTRUE_R8)
4237 ZEROP(f, !=);
4238 MINT_IN_BREAK;
4239 #define CONDBR_S(cond) \
4240 sp -= 2; \
4241 if (cond) { \
4242 gint16 br_offset = (gint16) ip [1]; \
4243 BACK_BRANCH_PROFILE (br_offset); \
4244 ip += br_offset; \
4245 } else \
4246 ip += 2;
4247 #define BRELOP_S(datamem, op) \
4248 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
4250 #define CONDBR(cond) \
4251 sp -= 2; \
4252 if (cond) { \
4253 gint32 br_offset = (gint32) READ32 (ip + 1); \
4254 BACK_BRANCH_PROFILE (br_offset); \
4255 ip += br_offset; \
4256 } else \
4257 ip += 3;
4259 #define BRELOP(datamem, op) \
4260 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
4262 MINT_IN_CASE(MINT_BEQ_I4_S)
4263 BRELOP_S(i, ==)
4264 MINT_IN_BREAK;
4265 MINT_IN_CASE(MINT_BEQ_I8_S)
4266 BRELOP_S(l, ==)
4267 MINT_IN_BREAK;
4268 MINT_IN_CASE(MINT_BEQ_R4_S)
4269 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
4270 MINT_IN_BREAK;
4271 MINT_IN_CASE(MINT_BEQ_R8_S)
4272 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
4273 MINT_IN_BREAK;
4274 MINT_IN_CASE(MINT_BEQ_I4)
4275 BRELOP(i, ==)
4276 MINT_IN_BREAK;
4277 MINT_IN_CASE(MINT_BEQ_I8)
4278 BRELOP(l, ==)
4279 MINT_IN_BREAK;
4280 MINT_IN_CASE(MINT_BEQ_R4)
4281 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_BEQ_R8)
4284 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_BGE_I4_S)
4287 BRELOP_S(i, >=)
4288 MINT_IN_BREAK;
4289 MINT_IN_CASE(MINT_BGE_I8_S)
4290 BRELOP_S(l, >=)
4291 MINT_IN_BREAK;
4292 MINT_IN_CASE(MINT_BGE_R4_S)
4293 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
4294 MINT_IN_BREAK;
4295 MINT_IN_CASE(MINT_BGE_R8_S)
4296 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
4297 MINT_IN_BREAK;
4298 MINT_IN_CASE(MINT_BGE_I4)
4299 BRELOP(i, >=)
4300 MINT_IN_BREAK;
4301 MINT_IN_CASE(MINT_BGE_I8)
4302 BRELOP(l, >=)
4303 MINT_IN_BREAK;
4304 MINT_IN_CASE(MINT_BGE_R4)
4305 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
4306 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_BGE_R8)
4308 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
4309 MINT_IN_BREAK;
4310 MINT_IN_CASE(MINT_BGT_I4_S)
4311 BRELOP_S(i, >)
4312 MINT_IN_BREAK;
4313 MINT_IN_CASE(MINT_BGT_I8_S)
4314 BRELOP_S(l, >)
4315 MINT_IN_BREAK;
4316 MINT_IN_CASE(MINT_BGT_R4_S)
4317 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
4318 MINT_IN_BREAK;
4319 MINT_IN_CASE(MINT_BGT_R8_S)
4320 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
4321 MINT_IN_BREAK;
4322 MINT_IN_CASE(MINT_BGT_I4)
4323 BRELOP(i, >)
4324 MINT_IN_BREAK;
4325 MINT_IN_CASE(MINT_BGT_I8)
4326 BRELOP(l, >)
4327 MINT_IN_BREAK;
4328 MINT_IN_CASE(MINT_BGT_R4)
4329 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
4330 MINT_IN_BREAK;
4331 MINT_IN_CASE(MINT_BGT_R8)
4332 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
4333 MINT_IN_BREAK;
4334 MINT_IN_CASE(MINT_BLT_I4_S)
4335 BRELOP_S(i, <)
4336 MINT_IN_BREAK;
4337 MINT_IN_CASE(MINT_BLT_I8_S)
4338 BRELOP_S(l, <)
4339 MINT_IN_BREAK;
4340 MINT_IN_CASE(MINT_BLT_R4_S)
4341 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
4342 MINT_IN_BREAK;
4343 MINT_IN_CASE(MINT_BLT_R8_S)
4344 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
4345 MINT_IN_BREAK;
4346 MINT_IN_CASE(MINT_BLT_I4)
4347 BRELOP(i, <)
4348 MINT_IN_BREAK;
4349 MINT_IN_CASE(MINT_BLT_I8)
4350 BRELOP(l, <)
4351 MINT_IN_BREAK;
4352 MINT_IN_CASE(MINT_BLT_R4)
4353 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
4354 MINT_IN_BREAK;
4355 MINT_IN_CASE(MINT_BLT_R8)
4356 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
4357 MINT_IN_BREAK;
4358 MINT_IN_CASE(MINT_BLE_I4_S)
4359 BRELOP_S(i, <=)
4360 MINT_IN_BREAK;
4361 MINT_IN_CASE(MINT_BLE_I8_S)
4362 BRELOP_S(l, <=)
4363 MINT_IN_BREAK;
4364 MINT_IN_CASE(MINT_BLE_R4_S)
4365 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
4366 MINT_IN_BREAK;
4367 MINT_IN_CASE(MINT_BLE_R8_S)
4368 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
4369 MINT_IN_BREAK;
4370 MINT_IN_CASE(MINT_BLE_I4)
4371 BRELOP(i, <=)
4372 MINT_IN_BREAK;
4373 MINT_IN_CASE(MINT_BLE_I8)
4374 BRELOP(l, <=)
4375 MINT_IN_BREAK;
4376 MINT_IN_CASE(MINT_BLE_R4)
4377 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
4378 MINT_IN_BREAK;
4379 MINT_IN_CASE(MINT_BLE_R8)
4380 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
4381 MINT_IN_BREAK;
4382 MINT_IN_CASE(MINT_BNE_UN_I4_S)
4383 BRELOP_S(i, !=)
4384 MINT_IN_BREAK;
4385 MINT_IN_CASE(MINT_BNE_UN_I8_S)
4386 BRELOP_S(l, !=)
4387 MINT_IN_BREAK;
4388 MINT_IN_CASE(MINT_BNE_UN_R4_S)
4389 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
4390 MINT_IN_BREAK;
4391 MINT_IN_CASE(MINT_BNE_UN_R8_S)
4392 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
4393 MINT_IN_BREAK;
4394 MINT_IN_CASE(MINT_BNE_UN_I4)
4395 BRELOP(i, !=)
4396 MINT_IN_BREAK;
4397 MINT_IN_CASE(MINT_BNE_UN_I8)
4398 BRELOP(l, !=)
4399 MINT_IN_BREAK;
4400 MINT_IN_CASE(MINT_BNE_UN_R4)
4401 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
4402 MINT_IN_BREAK;
4403 MINT_IN_CASE(MINT_BNE_UN_R8)
4404 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
4405 MINT_IN_BREAK;
4407 #define BRELOP_S_CAST(datamem, op, type) \
4408 sp -= 2; \
4409 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4410 gint16 br_offset = (gint16) ip [1]; \
4411 BACK_BRANCH_PROFILE (br_offset); \
4412 ip += br_offset; \
4413 } else \
4414 ip += 2;
4416 #define BRELOP_CAST(datamem, op, type) \
4417 sp -= 2; \
4418 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \
4419 gint32 br_offset = (gint32) ip [1]; \
4420 BACK_BRANCH_PROFILE (br_offset); \
4421 ip += br_offset; \
4422 } else \
4423 ip += 3;
4425 MINT_IN_CASE(MINT_BGE_UN_I4_S)
4426 BRELOP_S_CAST(i, >=, guint32);
4427 MINT_IN_BREAK;
4428 MINT_IN_CASE(MINT_BGE_UN_I8_S)
4429 BRELOP_S_CAST(l, >=, guint64);
4430 MINT_IN_BREAK;
4431 MINT_IN_CASE(MINT_BGE_UN_R4_S)
4432 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4433 MINT_IN_BREAK;
4434 MINT_IN_CASE(MINT_BGE_UN_R8_S)
4435 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4436 MINT_IN_BREAK;
4437 MINT_IN_CASE(MINT_BGE_UN_I4)
4438 BRELOP_CAST(i, >=, guint32);
4439 MINT_IN_BREAK;
4440 MINT_IN_CASE(MINT_BGE_UN_I8)
4441 BRELOP_CAST(l, >=, guint64);
4442 MINT_IN_BREAK;
4443 MINT_IN_CASE(MINT_BGE_UN_R4)
4444 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4445 MINT_IN_BREAK;
4446 MINT_IN_CASE(MINT_BGE_UN_R8)
4447 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4448 MINT_IN_BREAK;
4449 MINT_IN_CASE(MINT_BGT_UN_I4_S)
4450 BRELOP_S_CAST(i, >, guint32);
4451 MINT_IN_BREAK;
4452 MINT_IN_CASE(MINT_BGT_UN_I8_S)
4453 BRELOP_S_CAST(l, >, guint64);
4454 MINT_IN_BREAK;
4455 MINT_IN_CASE(MINT_BGT_UN_R4_S)
4456 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4457 MINT_IN_BREAK;
4458 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4459 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4460 MINT_IN_BREAK;
4461 MINT_IN_CASE(MINT_BGT_UN_I4)
4462 BRELOP_CAST(i, >, guint32);
4463 MINT_IN_BREAK;
4464 MINT_IN_CASE(MINT_BGT_UN_I8)
4465 BRELOP_CAST(l, >, guint64);
4466 MINT_IN_BREAK;
4467 MINT_IN_CASE(MINT_BGT_UN_R4)
4468 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4469 MINT_IN_BREAK;
4470 MINT_IN_CASE(MINT_BGT_UN_R8)
4471 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4472 MINT_IN_BREAK;
4473 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4474 BRELOP_S_CAST(i, <=, guint32);
4475 MINT_IN_BREAK;
4476 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4477 BRELOP_S_CAST(l, <=, guint64);
4478 MINT_IN_BREAK;
4479 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4480 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4481 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4483 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4484 MINT_IN_BREAK;
4485 MINT_IN_CASE(MINT_BLE_UN_I4)
4486 BRELOP_CAST(i, <=, guint32);
4487 MINT_IN_BREAK;
4488 MINT_IN_CASE(MINT_BLE_UN_I8)
4489 BRELOP_CAST(l, <=, guint64);
4490 MINT_IN_BREAK;
4491 MINT_IN_CASE(MINT_BLE_UN_R4)
4492 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4493 MINT_IN_BREAK;
4494 MINT_IN_CASE(MINT_BLE_UN_R8)
4495 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4496 MINT_IN_BREAK;
4497 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4498 BRELOP_S_CAST(i, <, guint32);
4499 MINT_IN_BREAK;
4500 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4501 BRELOP_S_CAST(l, <, guint64);
4502 MINT_IN_BREAK;
4503 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4504 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4505 MINT_IN_BREAK;
4506 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4507 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4508 MINT_IN_BREAK;
4509 MINT_IN_CASE(MINT_BLT_UN_I4)
4510 BRELOP_CAST(i, <, guint32);
4511 MINT_IN_BREAK;
4512 MINT_IN_CASE(MINT_BLT_UN_I8)
4513 BRELOP_CAST(l, <, guint64);
4514 MINT_IN_BREAK;
4515 MINT_IN_CASE(MINT_BLT_UN_R4)
4516 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4517 MINT_IN_BREAK;
4518 MINT_IN_CASE(MINT_BLT_UN_R8)
4519 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4520 MINT_IN_BREAK;
4521 MINT_IN_CASE(MINT_SWITCH) {
4522 guint32 n;
4523 const unsigned short *st;
4524 ++ip;
4525 n = READ32 (ip);
4526 ip += 2;
4527 st = ip + 2 * n;
4528 --sp;
4529 if ((guint32)sp->data.i < n) {
4530 gint offset;
4531 ip += 2 * (guint32)sp->data.i;
4532 offset = READ32 (ip);
4533 ip = ip + offset;
4534 } else {
4535 ip = st;
4537 MINT_IN_BREAK;
4539 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4540 NULL_CHECK (sp [-1].data.p);
4541 ++ip;
4542 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4543 MINT_IN_BREAK;
4544 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4545 NULL_CHECK (sp [-1].data.p);
4546 ++ip;
4547 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4548 MINT_IN_BREAK;
4549 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4550 NULL_CHECK (sp [-1].data.p);
4551 ++ip;
4552 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4553 MINT_IN_BREAK;
4554 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4555 NULL_CHECK (sp [-1].data.p);
4556 ++ip;
4557 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4558 MINT_IN_BREAK;
4559 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4560 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4561 NULL_CHECK (sp [-1].data.p);
4562 ++ip;
4563 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4564 MINT_IN_BREAK;
4565 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4566 NULL_CHECK (sp [-1].data.p);
4567 ++ip;
4568 #ifdef NO_UNALIGNED_ACCESS
4569 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4570 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4571 else
4572 #endif
4573 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4574 MINT_IN_BREAK;
4575 MINT_IN_CASE(MINT_LDIND_I) {
4576 guint16 offset = ip [1];
4577 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4578 ip += 2;
4579 MINT_IN_BREAK;
4581 MINT_IN_CASE(MINT_LDIND_I8) {
4582 guint16 offset = ip [1];
4583 #ifdef NO_UNALIGNED_ACCESS
4584 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4585 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4586 else
4587 #endif
4588 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4589 ip += 2;
4590 MINT_IN_BREAK;
4592 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4593 NULL_CHECK (sp [-1].data.p);
4594 ++ip;
4595 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4596 MINT_IN_BREAK;
4597 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4598 NULL_CHECK (sp [-1].data.p);
4599 ++ip;
4600 #ifdef NO_UNALIGNED_ACCESS
4601 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4602 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4603 else
4604 #endif
4605 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4606 MINT_IN_BREAK;
4607 MINT_IN_CASE(MINT_LDIND_REF)
4608 ++ip;
4609 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4610 MINT_IN_BREAK;
4611 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4612 NULL_CHECK (sp [-1].data.p);
4613 ++ip;
4614 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4615 MINT_IN_BREAK;
4617 MINT_IN_CASE(MINT_STIND_REF)
4618 NULL_CHECK (sp [-2].data.p);
4619 ++ip;
4620 sp -= 2;
4621 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4622 MINT_IN_BREAK;
4623 MINT_IN_CASE(MINT_STIND_I1)
4624 NULL_CHECK (sp [-2].data.p);
4625 ++ip;
4626 sp -= 2;
4627 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4628 MINT_IN_BREAK;
4629 MINT_IN_CASE(MINT_STIND_I2)
4630 NULL_CHECK (sp [-2].data.p);
4631 ++ip;
4632 sp -= 2;
4633 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4634 MINT_IN_BREAK;
4635 MINT_IN_CASE(MINT_STIND_I4)
4636 NULL_CHECK (sp [-2].data.p);
4637 ++ip;
4638 sp -= 2;
4639 * (gint32 *) sp->data.p = sp[1].data.i;
4640 MINT_IN_BREAK;
4641 MINT_IN_CASE(MINT_STIND_I)
4642 NULL_CHECK (sp [-2].data.p);
4643 ++ip;
4644 sp -= 2;
4645 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4646 MINT_IN_BREAK;
4647 MINT_IN_CASE(MINT_STIND_I8)
4648 NULL_CHECK (sp [-2].data.p);
4649 ++ip;
4650 sp -= 2;
4651 #ifdef NO_UNALIGNED_ACCESS
4652 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4653 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4654 else
4655 #endif
4656 * (gint64 *) sp->data.p = sp[1].data.l;
4657 MINT_IN_BREAK;
4658 MINT_IN_CASE(MINT_STIND_R4)
4659 NULL_CHECK (sp [-2].data.p);
4660 ++ip;
4661 sp -= 2;
4662 * (float *) sp->data.p = sp[1].data.f_r4;
4663 MINT_IN_BREAK;
4664 MINT_IN_CASE(MINT_STIND_R8)
4665 NULL_CHECK (sp [-2].data.p);
4666 ++ip;
4667 sp -= 2;
4668 #ifdef NO_UNALIGNED_ACCESS
4669 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4670 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4671 else
4672 #endif
4673 * (double *) sp->data.p = sp[1].data.f;
4674 MINT_IN_BREAK;
4675 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4676 ++ip;
4677 sp -= 2;
4678 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4679 MINT_IN_BREAK;
4680 #define BINOP(datamem, op) \
4681 --sp; \
4682 sp [-1].data.datamem op ## = sp [0].data.datamem; \
4683 ++ip;
4684 MINT_IN_CASE(MINT_ADD_I4)
4685 BINOP(i, +);
4686 MINT_IN_BREAK;
4687 MINT_IN_CASE(MINT_ADD_I8)
4688 BINOP(l, +);
4689 MINT_IN_BREAK;
4690 MINT_IN_CASE(MINT_ADD_R4)
4691 BINOP(f_r4, +);
4692 MINT_IN_BREAK;
4693 MINT_IN_CASE(MINT_ADD_R8)
4694 BINOP(f, +);
4695 MINT_IN_BREAK;
4696 MINT_IN_CASE(MINT_ADD1_I4)
4697 ++sp [-1].data.i;
4698 ++ip;
4699 MINT_IN_BREAK;
4700 MINT_IN_CASE(MINT_ADD1_I8)
4701 ++sp [-1].data.l;
4702 ++ip;
4703 MINT_IN_BREAK;
4704 MINT_IN_CASE(MINT_LOCADD1_I4)
4705 *(gint32*)(locals + ip [1]) += 1;
4706 ip += 2;
4707 MINT_IN_BREAK;
4708 MINT_IN_CASE(MINT_LOCADD1_I8)
4709 *(gint64*)(locals + ip [1]) += 1;
4710 ip += 2;
4711 MINT_IN_BREAK;
4712 MINT_IN_CASE(MINT_SUB_I4)
4713 BINOP(i, -);
4714 MINT_IN_BREAK;
4715 MINT_IN_CASE(MINT_SUB_I8)
4716 BINOP(l, -);
4717 MINT_IN_BREAK;
4718 MINT_IN_CASE(MINT_SUB_R4)
4719 BINOP(f_r4, -);
4720 MINT_IN_BREAK;
4721 MINT_IN_CASE(MINT_SUB_R8)
4722 BINOP(f, -);
4723 MINT_IN_BREAK;
4724 MINT_IN_CASE(MINT_SUB1_I4)
4725 --sp [-1].data.i;
4726 ++ip;
4727 MINT_IN_BREAK;
4728 MINT_IN_CASE(MINT_SUB1_I8)
4729 --sp [-1].data.l;
4730 ++ip;
4731 MINT_IN_BREAK;
4732 MINT_IN_CASE(MINT_LOCSUB1_I4)
4733 *(gint32*)(locals + ip [1]) -= 1;
4734 ip += 2;
4735 MINT_IN_BREAK;
4736 MINT_IN_CASE(MINT_LOCSUB1_I8)
4737 *(gint64*)(locals + ip [1]) -= 1;
4738 MINT_IN_BREAK;
4739 MINT_IN_CASE(MINT_MUL_I4)
4740 BINOP(i, *);
4741 MINT_IN_BREAK;
4742 MINT_IN_CASE(MINT_MUL_I8)
4743 BINOP(l, *);
4744 MINT_IN_BREAK;
4745 MINT_IN_CASE(MINT_MUL_R4)
4746 BINOP(f_r4, *);
4747 MINT_IN_BREAK;
4748 MINT_IN_CASE(MINT_MUL_R8)
4749 BINOP(f, *);
4750 MINT_IN_BREAK;
4751 MINT_IN_CASE(MINT_DIV_I4) {
4752 gint32 l1 = sp [-1].data.i;
4753 gint32 l2 = sp [-2].data.i;
4754 if (l1 == 0)
4755 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4756 if (l1 == (-1) && l2 == G_MININT32)
4757 THROW_EX (mono_get_exception_overflow (), ip);
4758 BINOP(i, /);
4759 MINT_IN_BREAK;
4761 MINT_IN_CASE(MINT_DIV_I8) {
4762 gint64 l1 = sp [-1].data.l;
4763 gint64 l2 = sp [-2].data.l;
4764 if (l1 == 0)
4765 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4766 if (l1 == (-1) && l2 == G_MININT64)
4767 THROW_EX (mono_get_exception_overflow (), ip);
4768 BINOP(l, /);
4769 MINT_IN_BREAK;
4771 MINT_IN_CASE(MINT_DIV_R4)
4772 BINOP(f_r4, /);
4773 MINT_IN_BREAK;
4774 MINT_IN_CASE(MINT_DIV_R8)
4775 BINOP(f, /);
4776 MINT_IN_BREAK;
4778 #define BINOP_CAST(datamem, op, type) \
4779 --sp; \
4780 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4781 ++ip;
4782 MINT_IN_CASE(MINT_DIV_UN_I4)
4783 if (sp [-1].data.i == 0)
4784 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4785 BINOP_CAST(i, /, guint32);
4786 MINT_IN_BREAK;
4787 MINT_IN_CASE(MINT_DIV_UN_I8)
4788 if (sp [-1].data.l == 0)
4789 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4790 BINOP_CAST(l, /, guint64);
4791 MINT_IN_BREAK;
4792 MINT_IN_CASE(MINT_REM_I4) {
4793 int i1 = sp [-1].data.i;
4794 int i2 = sp [-2].data.i;
4795 if (i1 == 0)
4796 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4797 if (i1 == (-1) && i2 == G_MININT32)
4798 THROW_EX (mono_get_exception_overflow (), ip);
4799 BINOP(i, %);
4800 MINT_IN_BREAK;
4802 MINT_IN_CASE(MINT_REM_I8) {
4803 gint64 l1 = sp [-1].data.l;
4804 gint64 l2 = sp [-2].data.l;
4805 if (l1 == 0)
4806 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4807 if (l1 == (-1) && l2 == G_MININT64)
4808 THROW_EX (mono_get_exception_overflow (), ip);
4809 BINOP(l, %);
4810 MINT_IN_BREAK;
4812 MINT_IN_CASE(MINT_REM_R4)
4813 /* FIXME: what do we actually do here? */
4814 --sp;
4815 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4816 ++ip;
4817 MINT_IN_BREAK;
4818 MINT_IN_CASE(MINT_REM_R8)
4819 /* FIXME: what do we actually do here? */
4820 --sp;
4821 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4822 ++ip;
4823 MINT_IN_BREAK;
4824 MINT_IN_CASE(MINT_REM_UN_I4)
4825 if (sp [-1].data.i == 0)
4826 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4827 BINOP_CAST(i, %, guint32);
4828 MINT_IN_BREAK;
4829 MINT_IN_CASE(MINT_REM_UN_I8)
4830 if (sp [-1].data.l == 0)
4831 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4832 BINOP_CAST(l, %, guint64);
4833 MINT_IN_BREAK;
4834 MINT_IN_CASE(MINT_AND_I4)
4835 BINOP(i, &);
4836 MINT_IN_BREAK;
4837 MINT_IN_CASE(MINT_AND_I8)
4838 BINOP(l, &);
4839 MINT_IN_BREAK;
4840 MINT_IN_CASE(MINT_OR_I4)
4841 BINOP(i, |);
4842 MINT_IN_BREAK;
4843 MINT_IN_CASE(MINT_OR_I8)
4844 BINOP(l, |);
4845 MINT_IN_BREAK;
4846 MINT_IN_CASE(MINT_XOR_I4)
4847 BINOP(i, ^);
4848 MINT_IN_BREAK;
4849 MINT_IN_CASE(MINT_XOR_I8)
4850 BINOP(l, ^);
4851 MINT_IN_BREAK;
4853 #define SHIFTOP(datamem, op) \
4854 --sp; \
4855 sp [-1].data.datamem op ## = sp [0].data.i; \
4856 ++ip;
4858 MINT_IN_CASE(MINT_SHL_I4)
4859 SHIFTOP(i, <<);
4860 MINT_IN_BREAK;
4861 MINT_IN_CASE(MINT_SHL_I8)
4862 SHIFTOP(l, <<);
4863 MINT_IN_BREAK;
4864 MINT_IN_CASE(MINT_SHR_I4)
4865 SHIFTOP(i, >>);
4866 MINT_IN_BREAK;
4867 MINT_IN_CASE(MINT_SHR_I8)
4868 SHIFTOP(l, >>);
4869 MINT_IN_BREAK;
4870 MINT_IN_CASE(MINT_SHR_UN_I4)
4871 --sp;
4872 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4873 ++ip;
4874 MINT_IN_BREAK;
4875 MINT_IN_CASE(MINT_SHR_UN_I8)
4876 --sp;
4877 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4878 ++ip;
4879 MINT_IN_BREAK;
4880 MINT_IN_CASE(MINT_NEG_I4)
4881 sp [-1].data.i = - sp [-1].data.i;
4882 ++ip;
4883 MINT_IN_BREAK;
4884 MINT_IN_CASE(MINT_NEG_I8)
4885 sp [-1].data.l = - sp [-1].data.l;
4886 ++ip;
4887 MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_NEG_R4)
4889 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4890 ++ip;
4891 MINT_IN_BREAK;
4892 MINT_IN_CASE(MINT_NEG_R8)
4893 sp [-1].data.f = - sp [-1].data.f;
4894 ++ip;
4895 MINT_IN_BREAK;
4896 MINT_IN_CASE(MINT_NOT_I4)
4897 sp [-1].data.i = ~ sp [-1].data.i;
4898 ++ip;
4899 MINT_IN_BREAK;
4900 MINT_IN_CASE(MINT_NOT_I8)
4901 sp [-1].data.l = ~ sp [-1].data.l;
4902 ++ip;
4903 MINT_IN_BREAK;
4904 MINT_IN_CASE(MINT_CONV_I1_I4)
4905 sp [-1].data.i = (gint8)sp [-1].data.i;
4906 ++ip;
4907 MINT_IN_BREAK;
4908 MINT_IN_CASE(MINT_CONV_I1_I8)
4909 sp [-1].data.i = (gint8)sp [-1].data.l;
4910 ++ip;
4911 MINT_IN_BREAK;
4912 MINT_IN_CASE(MINT_CONV_I1_R4)
4913 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4914 ++ip;
4915 MINT_IN_BREAK;
4916 MINT_IN_CASE(MINT_CONV_I1_R8)
4917 /* without gint32 cast, C compiler is allowed to use undefined
4918 * behaviour if data.f is bigger than >255. See conv.fpint section
4919 * in C standard:
4920 * > The conversion truncates; that is, the fractional part
4921 * > is discarded. The behavior is undefined if the truncated
4922 * > value cannot be represented in the destination type.
4923 * */
4924 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4925 ++ip;
4926 MINT_IN_BREAK;
4927 MINT_IN_CASE(MINT_CONV_U1_I4)
4928 sp [-1].data.i = (guint8)sp [-1].data.i;
4929 ++ip;
4930 MINT_IN_BREAK;
4931 MINT_IN_CASE(MINT_CONV_U1_I8)
4932 sp [-1].data.i = (guint8)sp [-1].data.l;
4933 ++ip;
4934 MINT_IN_BREAK;
4935 MINT_IN_CASE(MINT_CONV_U1_R4)
4936 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4937 ++ip;
4938 MINT_IN_BREAK;
4939 MINT_IN_CASE(MINT_CONV_U1_R8)
4940 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4941 ++ip;
4942 MINT_IN_BREAK;
4943 MINT_IN_CASE(MINT_CONV_I2_I4)
4944 sp [-1].data.i = (gint16)sp [-1].data.i;
4945 ++ip;
4946 MINT_IN_BREAK;
4947 MINT_IN_CASE(MINT_CONV_I2_I8)
4948 sp [-1].data.i = (gint16)sp [-1].data.l;
4949 ++ip;
4950 MINT_IN_BREAK;
4951 MINT_IN_CASE(MINT_CONV_I2_R4)
4952 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4953 ++ip;
4954 MINT_IN_BREAK;
4955 MINT_IN_CASE(MINT_CONV_I2_R8)
4956 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4957 ++ip;
4958 MINT_IN_BREAK;
4959 MINT_IN_CASE(MINT_CONV_U2_I4)
4960 sp [-1].data.i = (guint16)sp [-1].data.i;
4961 ++ip;
4962 MINT_IN_BREAK;
4963 MINT_IN_CASE(MINT_CONV_U2_I8)
4964 sp [-1].data.i = (guint16)sp [-1].data.l;
4965 ++ip;
4966 MINT_IN_BREAK;
4967 MINT_IN_CASE(MINT_CONV_U2_R4)
4968 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4969 ++ip;
4970 MINT_IN_BREAK;
4971 MINT_IN_CASE(MINT_CONV_U2_R8)
4972 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4973 ++ip;
4974 MINT_IN_BREAK;
4975 MINT_IN_CASE(MINT_CONV_I4_R4)
4976 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4977 ++ip;
4978 MINT_IN_BREAK;
4979 MINT_IN_CASE(MINT_CONV_I4_R8)
4980 sp [-1].data.i = (gint32)sp [-1].data.f;
4981 ++ip;
4982 MINT_IN_BREAK;
4983 MINT_IN_CASE(MINT_CONV_U4_I8)
4984 MINT_IN_CASE(MINT_CONV_I4_I8)
4985 sp [-1].data.i = (gint32)sp [-1].data.l;
4986 ++ip;
4987 MINT_IN_BREAK;
4988 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4989 sp [-2].data.i = (gint32)sp [-2].data.l;
4990 ++ip;
4991 MINT_IN_BREAK;
4992 MINT_IN_CASE(MINT_CONV_U4_R4)
4993 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4994 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4995 #else
4996 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4997 #endif
4998 ++ip;
4999 MINT_IN_BREAK;
5000 MINT_IN_CASE(MINT_CONV_U4_R8)
5001 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
5002 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
5003 #else
5004 sp [-1].data.i = (guint32) sp [-1].data.f;
5005 #endif
5006 ++ip;
5007 MINT_IN_BREAK;
5008 MINT_IN_CASE(MINT_CONV_I8_I4)
5009 sp [-1].data.l = sp [-1].data.i;
5010 ++ip;
5011 MINT_IN_BREAK;
5012 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
5013 sp [-2].data.l = sp [-2].data.i;
5014 ++ip;
5015 MINT_IN_BREAK;
5016 MINT_IN_CASE(MINT_CONV_I8_U4)
5017 sp [-1].data.l = (guint32)sp [-1].data.i;
5018 ++ip;
5019 MINT_IN_BREAK;
5020 MINT_IN_CASE(MINT_CONV_I8_R4)
5021 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
5022 ++ip;
5023 MINT_IN_BREAK;
5024 MINT_IN_CASE(MINT_CONV_I8_R8)
5025 sp [-1].data.l = (gint64)sp [-1].data.f;
5026 ++ip;
5027 MINT_IN_BREAK;
5028 MINT_IN_CASE(MINT_CONV_R4_I4)
5029 sp [-1].data.f_r4 = (float)sp [-1].data.i;
5030 ++ip;
5031 MINT_IN_BREAK;
5032 MINT_IN_CASE(MINT_CONV_R4_I8)
5033 sp [-1].data.f_r4 = (float)sp [-1].data.l;
5034 ++ip;
5035 MINT_IN_BREAK;
5036 MINT_IN_CASE(MINT_CONV_R4_R8)
5037 sp [-1].data.f_r4 = (float)sp [-1].data.f;
5038 ++ip;
5039 MINT_IN_BREAK;
5040 MINT_IN_CASE(MINT_CONV_R8_I4)
5041 sp [-1].data.f = (double)sp [-1].data.i;
5042 ++ip;
5043 MINT_IN_BREAK;
5044 MINT_IN_CASE(MINT_CONV_R8_I8)
5045 sp [-1].data.f = (double)sp [-1].data.l;
5046 ++ip;
5047 MINT_IN_BREAK;
5048 MINT_IN_CASE(MINT_CONV_R8_R4)
5049 sp [-1].data.f = (double) sp [-1].data.f_r4;
5050 ++ip;
5051 MINT_IN_BREAK;
5052 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
5053 sp [-2].data.f = (double) sp [-2].data.f_r4;
5054 ++ip;
5055 MINT_IN_BREAK;
5056 MINT_IN_CASE(MINT_CONV_U8_R4)
5057 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
5058 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
5059 #else
5060 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
5061 #endif
5062 ++ip;
5063 MINT_IN_BREAK;
5064 MINT_IN_CASE(MINT_CONV_U8_R8)
5065 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
5066 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
5067 #else
5068 sp [-1].data.l = (guint64)sp [-1].data.f;
5069 #endif
5070 ++ip;
5071 MINT_IN_BREAK;
5072 MINT_IN_CASE(MINT_CPOBJ) {
5073 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5074 g_assert (m_class_is_valuetype (c));
5075 /* if this assertion fails, we need to add a write barrier */
5076 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
5077 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
5078 ip += 2;
5079 sp -= 2;
5080 MINT_IN_BREAK;
5082 MINT_IN_CASE(MINT_CPOBJ_VT) {
5083 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5084 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
5085 ip += 2;
5086 sp -= 2;
5087 MINT_IN_BREAK;
5089 MINT_IN_CASE(MINT_LDOBJ_VT) {
5090 int size = READ32(ip + 1);
5091 ip += 3;
5092 memcpy (vt_sp, sp [-1].data.p, size);
5093 sp [-1].data.p = vt_sp;
5094 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5095 MINT_IN_BREAK;
5097 MINT_IN_CASE(MINT_LDSTR)
5098 sp->data.p = frame->imethod->data_items [ip [1]];
5099 ++sp;
5100 ip += 2;
5101 MINT_IN_BREAK;
5102 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
5103 MonoString *s = NULL;
5104 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [1]];
5106 MonoMethod *method = frame->imethod->method;
5107 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
5108 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
5109 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
5110 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
5111 } else {
5112 g_assert_not_reached ();
5114 sp->data.p = s;
5115 ++sp;
5116 ip += 2;
5117 MINT_IN_BREAK;
5119 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
5120 MonoClass *newobj_class;
5121 guint32 token = ip [1];
5122 guint16 param_count = ip [2];
5124 newobj_class = (MonoClass*) frame->imethod->data_items [token];
5126 sp -= param_count;
5127 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
5128 if (!is_ok (error))
5129 THROW_EX (mono_error_convert_to_exception (error), ip);
5131 ++sp;
5132 ip += 3;
5133 MINT_IN_BREAK;
5135 MINT_IN_CASE(MINT_NEWOBJ_STRING) {
5136 cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
5138 const int param_count = ip [2];
5139 if (param_count) {
5140 sp -= param_count;
5141 memmove (sp + 1, sp, param_count * sizeof (stackval));
5143 // `this` is implicit null. The created string will be returned
5144 // by the call, even though the call has void return (?!).
5145 sp->data.p = NULL;
5146 ip += 3;
5147 goto call;
5149 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
5150 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]];
5151 INIT_VTABLE (vtable);
5152 guint16 param_count;
5153 guint16 imethod_index = ip [1];
5155 const gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG;
5157 param_count = ip [2];
5159 // Make room for two copies of o -- this parameter and return value.
5160 if (param_count || !is_inlined) {
5161 sp -= param_count;
5162 memmove (sp + 2, sp, param_count * sizeof (stackval));
5165 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5166 if (G_UNLIKELY (!o)) {
5167 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
5168 THROW_EX (mono_error_convert_to_exception (error), ip);
5171 // Store o next to and before the parameters on the stack so GC will see it,
5172 // and where it is needed when the call returns.
5173 sp [0].data.o = o;
5174 sp [1].data.o = o;
5175 ip += 4;
5176 if (is_inlined) {
5177 sp += param_count + 2;
5178 } else {
5179 cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index];
5180 goto call_newobj;
5183 MINT_IN_BREAK;
5186 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
5187 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
5188 guint16 imethod_index = ip [1];
5189 gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG;
5191 guint16 const param_count = ip [2];
5193 // Make room for extra parameter and result.
5194 if (param_count) {
5195 sp -= param_count;
5196 memmove (sp + 2, sp, param_count * sizeof (stackval));
5199 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
5200 if (vtst) {
5201 memset (vt_sp, 0, ip [3]);
5202 ip += 4;
5203 // Put extra parameter and result on stack, before other parameters,
5204 // and point stack to extra parameter, after result.
5205 // This pattern occurs for newobj_vt_fast and newobj_fast.
5206 sp [1].data.p = vt_sp;
5207 sp [0].data.p = vt_sp;
5208 } else {
5209 ip += 3;
5210 // Like newobj_fast, add valuetype_this parameter
5211 // and result and point stack to this after result.
5212 memset (sp, 0, sizeof (*sp));
5213 sp [1].data.p = &sp [0].data; // valuetype_this == result
5216 if (is_inlined) {
5217 if (vtst)
5218 vt_sp += ALIGN_TO (ip [-1], MINT_VT_ALIGNMENT);
5219 sp += param_count + 2;
5220 MINT_IN_BREAK;
5222 cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index];
5224 // call_newobj captures the pattern where the return value is placed
5225 // on the stack before the call, instead of the call forming it.
5226 call_newobj:
5227 ++sp; // Point sp at added extra param, after return value.
5228 goto call;
5230 MINT_IN_CASE(MINT_NEWOBJ) {
5231 guint32 const token = ip [1];
5233 cmethod = (InterpMethod*)frame->imethod->data_items [token];
5235 MonoMethodSignature* const csig = mono_method_signature_internal (cmethod->method);
5237 g_assert (csig->hasthis);
5239 // Make room for first parameter and return value.
5240 const int param_count = csig->param_count;
5241 if (param_count) {
5242 sp -= param_count;
5243 memmove (sp + 2, sp, param_count * sizeof (stackval));
5246 MonoClass * const newobj_class = cmethod->method->klass;
5248 /*if (profiling_classes) {
5249 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
5250 count++;
5251 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
5255 * First arg is the object.
5256 * a constructor returns void, but we need to return the object we created
5259 g_assert (!m_class_is_valuetype (newobj_class));
5261 MonoDomain* const domain = frame->imethod->domain;
5262 MonoVTable *vtable = mono_class_vtable_checked (domain, newobj_class, error);
5263 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
5264 MonoException *exc = mono_error_convert_to_exception (error);
5265 g_assert (exc);
5266 THROW_EX (exc, ip);
5268 error_init_reuse (error);
5269 MonoObject* o = mono_object_new_checked (domain, newobj_class, error);
5270 sp [0].data.o = o; // return value
5271 sp [1].data.o = o; // first parameter
5273 mono_error_cleanup (error); // FIXME: do not swallow the error
5274 error_init_reuse (error);
5275 EXCEPTION_CHECKPOINT;
5276 #ifndef DISABLE_REMOTING
5277 if (mono_object_is_transparent_proxy (o)) {
5278 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (cmethod->method, error);
5279 mono_error_assert_ok (error);
5280 cmethod = mono_interp_get_imethod (domain, remoting_invoke_method, error);
5281 mono_error_assert_ok (error);
5283 #endif
5284 ip += 2;
5285 goto call_newobj;
5287 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
5288 ip += 2;
5290 MINT_IN_BREAK;
5292 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
5293 gpointer arg0 = sp [-1].data.p;
5294 gpointer *byreference_this = (gpointer*)vt_sp;
5295 *byreference_this = arg0;
5297 sp [-1].data.p = vt_sp;
5298 vt_sp += MINT_VT_ALIGNMENT;
5299 ip++;
5300 MINT_IN_BREAK;
5302 MINT_IN_CASE(MINT_INTRINS_SPAN_CTOR) {
5303 gpointer ptr = sp [-2].data.p;
5304 int len = sp [-1].data.i;
5305 if (len < 0)
5306 THROW_EX (mono_get_exception_argument_out_of_range ("length"), ip);
5307 *(gpointer*)vt_sp = ptr;
5308 *(gint32*)((gpointer*)vt_sp + 1) = len;
5309 sp [-2].data.p = vt_sp;
5310 #if SIZEOF_VOID_P == 8
5311 vt_sp += ALIGN_TO (12, MINT_VT_ALIGNMENT);
5312 #else
5313 vt_sp += ALIGN_TO (8, MINT_VT_ALIGNMENT);
5314 #endif
5315 sp--;
5316 ip++;
5317 MINT_IN_BREAK;
5319 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
5320 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
5321 sp [-1].data.p = *byreference_this;
5322 ++ip;
5323 MINT_IN_BREAK;
5325 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
5326 sp -= 2;
5327 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
5328 sp ++;
5329 ++ip;
5330 MINT_IN_BREAK;
5332 MINT_IN_CASE(MINT_INTRINS_CLEAR_WITH_REFERENCES) {
5333 sp -= 2;
5334 gpointer p = sp [0].data.p;
5335 size_t size = sp [1].data.nati * sizeof (gpointer);
5336 mono_gc_bzero_aligned (p, size);
5337 ++ip;
5338 MINT_IN_BREAK;
5340 MINT_IN_CASE(MINT_INTRINS_MARVIN_BLOCK) {
5341 sp -= 2;
5342 interp_intrins_marvin_block ((guint32*)sp [0].data.p, (guint32*)sp [1].data.p);
5343 ++ip;
5344 MINT_IN_BREAK;
5346 MINT_IN_CASE(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE) {
5347 sp [-1].data.i = interp_intrins_ascii_chars_to_uppercase ((guint32)sp [-1].data.i);
5348 ++ip;
5349 MINT_IN_BREAK;
5351 MINT_IN_CASE(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF) {
5352 MonoObject* const o = sp [-1].data.o;
5353 NULL_CHECK (o);
5354 sp[-1].data.p = (guint8*)o + MONO_STRUCT_OFFSET (MonoArray, vector);
5355 ++ip;
5356 MINT_IN_BREAK;
5358 MINT_IN_CASE(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII) {
5359 sp--;
5360 sp [-1].data.i = interp_intrins_ordinal_ignore_case_ascii ((guint32)sp [-1].data.i, (guint32)sp [0].data.i);
5361 ++ip;
5362 MINT_IN_BREAK;
5364 MINT_IN_CASE(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII) {
5365 sp--;
5366 sp [-1].data.i = interp_intrins_64ordinal_ignore_case_ascii ((guint64)sp [-1].data.l, (guint64)sp [0].data.l);
5367 ++ip;
5368 MINT_IN_BREAK;
5370 MINT_IN_CASE(MINT_INTRINS_U32_TO_DECSTR) {
5371 MonoArray **cache_addr = (MonoArray**)frame->imethod->data_items [ip [1]];
5372 MonoVTable *string_vtable = (MonoVTable*)frame->imethod->data_items [ip [2]];
5373 sp [-1].data.o = (MonoObject*)interp_intrins_u32_to_decstr ((guint32)sp [-1].data.i, *cache_addr, string_vtable);
5374 ip += 3;
5375 MINT_IN_BREAK;
5377 MINT_IN_CASE(MINT_INTRINS_WIDEN_ASCII_TO_UTF16) {
5378 sp -= 2;
5379 sp [-1].data.nati = interp_intrins_widen_ascii_to_utf16 ((guint8*)sp [-1].data.p, (mono_unichar2*)sp [0].data.p, sp [1].data.nati);
5380 ip++;
5381 MINT_IN_BREAK;
5383 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
5384 sp -= 2;
5385 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
5386 sp ++;
5387 ++ip;
5388 MINT_IN_BREAK;
5390 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
5391 MonoObject *obj = sp [-1].data.o;
5392 sp [-1].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
5393 ++ip;
5394 MINT_IN_BREAK;
5396 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
5397 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
5398 MonoObject* const o = sp [-1].data.o;
5399 if (o) {
5400 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5401 gboolean isinst;
5402 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
5403 isinst = TRUE;
5404 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
5405 /* slow path */
5406 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
5407 } else {
5408 isinst = FALSE;
5411 if (!isinst) {
5412 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
5413 if (isinst_instr)
5414 sp [-1].data.p = NULL;
5415 else
5416 THROW_EX (mono_get_exception_invalid_cast (), ip);
5419 ip += 2;
5420 MINT_IN_BREAK;
5422 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
5423 MINT_IN_CASE(MINT_ISINST_COMMON) {
5424 MonoObject* const o = sp [-1].data.o;
5425 if (o) {
5426 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5427 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
5429 if (!isinst) {
5430 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
5431 if (isinst_instr)
5432 sp [-1].data.p = NULL;
5433 else
5434 THROW_EX (mono_get_exception_invalid_cast (), ip);
5437 ip += 2;
5438 MINT_IN_BREAK;
5440 MINT_IN_CASE(MINT_CASTCLASS)
5441 MINT_IN_CASE(MINT_ISINST) {
5442 MonoObject* const o = sp [-1].data.o;
5443 if (o) {
5444 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5445 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
5446 gboolean const isinst_instr = *ip == MINT_ISINST;
5447 if (isinst_instr)
5448 sp [-1].data.p = NULL;
5449 else
5450 THROW_EX (mono_get_exception_invalid_cast (), ip);
5453 ip += 2;
5454 MINT_IN_BREAK;
5456 MINT_IN_CASE(MINT_CONV_R_UN_I4)
5457 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
5458 ++ip;
5459 MINT_IN_BREAK;
5460 MINT_IN_CASE(MINT_CONV_R_UN_I8)
5461 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
5462 ++ip;
5463 MINT_IN_BREAK;
5464 MINT_IN_CASE(MINT_UNBOX) {
5465 MonoObject* const o = sp [-1].data.o;
5466 NULL_CHECK (o);
5467 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5469 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
5470 THROW_EX (mono_get_exception_invalid_cast (), ip);
5472 sp [-1].data.p = mono_object_unbox_internal (o);
5473 ip += 2;
5474 MINT_IN_BREAK;
5476 MINT_IN_CASE(MINT_THROW)
5477 --sp;
5478 if (!sp->data.p)
5479 sp->data.p = mono_get_exception_null_reference ();
5481 THROW_EX ((MonoException *)sp->data.p, ip);
5482 MINT_IN_BREAK;
5483 MINT_IN_CASE(MINT_CHECKPOINT)
5484 /* Do synchronous checking of abort requests */
5485 EXCEPTION_CHECKPOINT;
5486 ++ip;
5487 MINT_IN_BREAK;
5488 MINT_IN_CASE(MINT_SAFEPOINT)
5489 /* Do synchronous checking of abort requests */
5490 EXCEPTION_CHECKPOINT;
5491 /* Poll safepoint */
5492 mono_threads_safepoint ();
5493 ++ip;
5494 MINT_IN_BREAK;
5495 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
5496 sp[-1].data.p = (char*)sp [-1].data.o + ip [1];
5497 ip += 2;
5498 MINT_IN_BREAK;
5500 MINT_IN_CASE(MINT_LDFLDA) {
5501 MonoObject* const o = sp [-1].data.o;
5502 NULL_CHECK (o);
5503 sp[-1].data.p = (char *)o + ip [1];
5504 ip += 2;
5505 MINT_IN_BREAK;
5507 MINT_IN_CASE(MINT_CKNULL_N) {
5508 /* Same as CKNULL, but further down the stack */
5509 int const n = ip [1];
5510 MonoObject* const o = sp [-n].data.o;
5511 NULL_CHECK (o);
5512 ip += 2;
5513 MINT_IN_BREAK;
5516 #define LDFLD_VT_UNALIGNED(datamem, fieldtype, unaligned) do { \
5517 gpointer p = sp [-1].data.p; \
5518 vt_sp -= ip [2]; \
5519 if (unaligned) \
5520 memcpy (&sp[-1].data.datamem, (char *)p + ip [1], sizeof (fieldtype)); \
5521 else \
5522 sp [-1].data.datamem = * (fieldtype *)((char *)p + ip [1]); \
5523 ip += 3; \
5524 } while (0)
5526 #define LDFLD_VT(datamem, fieldtype) LDFLD_VT_UNALIGNED(datamem, fieldtype, FALSE)
5528 MINT_IN_CASE(MINT_LDFLD_VT_I1) LDFLD_VT(i, gint8); MINT_IN_BREAK;
5529 MINT_IN_CASE(MINT_LDFLD_VT_U1) LDFLD_VT(i, guint8); MINT_IN_BREAK;
5530 MINT_IN_CASE(MINT_LDFLD_VT_I2) LDFLD_VT(i, gint16); MINT_IN_BREAK;
5531 MINT_IN_CASE(MINT_LDFLD_VT_U2) LDFLD_VT(i, guint16); MINT_IN_BREAK;
5532 MINT_IN_CASE(MINT_LDFLD_VT_I4) LDFLD_VT(i, gint32); MINT_IN_BREAK;
5533 MINT_IN_CASE(MINT_LDFLD_VT_I8) LDFLD_VT(l, gint64); MINT_IN_BREAK;
5534 MINT_IN_CASE(MINT_LDFLD_VT_R4) LDFLD_VT(f_r4, float); MINT_IN_BREAK;
5535 MINT_IN_CASE(MINT_LDFLD_VT_R8) LDFLD_VT(f, double); MINT_IN_BREAK;
5536 MINT_IN_CASE(MINT_LDFLD_VT_O) LDFLD_VT(p, gpointer); MINT_IN_BREAK;
5537 MINT_IN_CASE(MINT_LDFLD_VT_I8_UNALIGNED) LDFLD_VT_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5538 MINT_IN_CASE(MINT_LDFLD_VT_R8_UNALIGNED) LDFLD_VT_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5540 MINT_IN_CASE(MINT_LDFLD_VT_VT) {
5541 gpointer p = sp [-1].data.p;
5543 vt_sp -= ip [2];
5544 sp [-1].data.p = vt_sp;
5545 memmove (vt_sp, (char *)p + ip [1], ip [3]);
5546 vt_sp += ip [3];
5547 ip += 4;
5548 MINT_IN_BREAK;
5551 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5552 MonoObject* const o = sp [-1].data.o; \
5553 NULL_CHECK (o); \
5554 if (unaligned) \
5555 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
5556 else \
5557 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
5558 ip += 2; \
5559 } while (0)
5561 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
5563 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
5564 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
5565 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
5566 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
5567 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
5568 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
5569 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
5570 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
5571 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
5572 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5573 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5575 MINT_IN_CASE(MINT_LDFLD_VT) {
5576 MonoObject* const o = sp [-1].data.o;
5577 NULL_CHECK (o);
5579 int size = READ32(ip + 2);
5580 sp [-1].data.p = vt_sp;
5581 memcpy (sp [-1].data.p, (char *)o + ip [1], size);
5582 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5583 ip += 4;
5584 MINT_IN_BREAK;
5587 MINT_IN_CASE(MINT_LDRMFLD) {
5588 MonoObject* const o = sp [-1].data.o;
5589 NULL_CHECK (o);
5590 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
5591 ip += 2;
5592 MINT_IN_BREAK;
5594 MINT_IN_CASE(MINT_LDRMFLD_VT) {
5595 MonoObject* const o = sp [-1].data.o;
5596 NULL_CHECK (o);
5597 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
5598 ip += 2;
5599 MINT_IN_BREAK;
5602 #define LDLOCFLD(datamem, fieldtype) do { \
5603 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5604 NULL_CHECK (o); \
5605 sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \
5606 sp++; \
5607 ip += 3; \
5608 } while (0)
5609 MINT_IN_CASE(MINT_LDLOCFLD_I1) LDLOCFLD(i, gint8); MINT_IN_BREAK;
5610 MINT_IN_CASE(MINT_LDLOCFLD_U1) LDLOCFLD(i, guint8); MINT_IN_BREAK;
5611 MINT_IN_CASE(MINT_LDLOCFLD_I2) LDLOCFLD(i, gint16); MINT_IN_BREAK;
5612 MINT_IN_CASE(MINT_LDLOCFLD_U2) LDLOCFLD(i, guint16); MINT_IN_BREAK;
5613 MINT_IN_CASE(MINT_LDLOCFLD_I4) LDLOCFLD(i, gint32); MINT_IN_BREAK;
5614 MINT_IN_CASE(MINT_LDLOCFLD_I8) LDLOCFLD(l, gint64); MINT_IN_BREAK;
5615 MINT_IN_CASE(MINT_LDLOCFLD_R4) LDLOCFLD(f_r4, float); MINT_IN_BREAK;
5616 MINT_IN_CASE(MINT_LDLOCFLD_R8) LDLOCFLD(f, double); MINT_IN_BREAK;
5617 MINT_IN_CASE(MINT_LDLOCFLD_O) LDLOCFLD(p, gpointer); MINT_IN_BREAK;
5619 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5620 MonoObject* const o = sp [-2].data.o; \
5621 NULL_CHECK (o); \
5622 sp -= 2; \
5623 if (unaligned) \
5624 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
5625 else \
5626 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
5627 ip += 2; \
5628 } while (0)
5630 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5632 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
5633 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
5634 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
5635 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
5636 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5637 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5638 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5639 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5640 MINT_IN_CASE(MINT_STFLD_O) {
5641 MonoObject* const o = sp [-2].data.o;
5642 NULL_CHECK (o);
5643 sp -= 2;
5644 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [1], sp [1].data.o);
5645 ip += 2;
5646 MINT_IN_BREAK;
5648 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5649 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5651 MINT_IN_CASE(MINT_STFLD_VT_NOREF) {
5652 MonoObject* const o = sp [-2].data.o;
5653 NULL_CHECK (o);
5654 sp -= 2;
5656 guint16 offset = ip [1];
5657 guint16 vtsize = ip [2];
5659 memcpy ((char *) o + offset, sp [1].data.p, vtsize);
5661 vt_sp -= ALIGN_TO (vtsize, MINT_VT_ALIGNMENT);
5662 ip += 3;
5663 MINT_IN_BREAK;
5666 MINT_IN_CASE(MINT_STFLD_VT) {
5667 MonoObject* const o = sp [-2].data.o;
5668 NULL_CHECK (o);
5669 sp -= 2;
5671 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [2]];
5672 int const i32 = mono_class_value_size (klass, NULL);
5674 guint16 offset = ip [1];
5675 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5677 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5678 ip += 3;
5679 MINT_IN_BREAK;
5681 MINT_IN_CASE(MINT_STRMFLD) {
5682 MonoClassField *field;
5684 MonoObject* const o = sp [-2].data.o;
5685 NULL_CHECK (o);
5687 field = (MonoClassField*)frame->imethod->data_items[ip [1]];
5688 ip += 2;
5690 #ifndef DISABLE_REMOTING
5691 if (mono_object_is_transparent_proxy (o)) {
5692 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5693 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5694 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5695 } else
5696 #endif
5697 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5699 sp -= 2;
5700 MINT_IN_BREAK;
5702 MINT_IN_CASE(MINT_STRMFLD_VT)
5704 NULL_CHECK (sp [-2].data.o);
5705 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5706 ip += 2;
5707 sp -= 2;
5708 MINT_IN_BREAK;
5710 #define STLOCFLD(datamem, fieldtype) do { \
5711 MonoObject *o = *(MonoObject**)(locals + ip [1]); \
5712 NULL_CHECK (o); \
5713 sp--; \
5714 * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \
5715 ip += 3; \
5716 } while (0)
5717 MINT_IN_CASE(MINT_STLOCFLD_I1) STLOCFLD(i, gint8); MINT_IN_BREAK;
5718 MINT_IN_CASE(MINT_STLOCFLD_U1) STLOCFLD(i, guint8); MINT_IN_BREAK;
5719 MINT_IN_CASE(MINT_STLOCFLD_I2) STLOCFLD(i, gint16); MINT_IN_BREAK;
5720 MINT_IN_CASE(MINT_STLOCFLD_U2) STLOCFLD(i, guint16); MINT_IN_BREAK;
5721 MINT_IN_CASE(MINT_STLOCFLD_I4) STLOCFLD(i, gint32); MINT_IN_BREAK;
5722 MINT_IN_CASE(MINT_STLOCFLD_I8) STLOCFLD(l, gint64); MINT_IN_BREAK;
5723 MINT_IN_CASE(MINT_STLOCFLD_R4) STLOCFLD(f_r4, float); MINT_IN_BREAK;
5724 MINT_IN_CASE(MINT_STLOCFLD_R8) STLOCFLD(f, double); MINT_IN_BREAK;
5725 MINT_IN_CASE(MINT_STLOCFLD_O) {
5726 MonoObject *o = *(MonoObject**)(locals + ip [1]);
5727 NULL_CHECK (o);
5728 sp--;
5729 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o);
5730 ip += 3;
5731 MINT_IN_BREAK;
5734 MINT_IN_CASE(MINT_LDSFLDA) {
5735 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5736 INIT_VTABLE (vtable);
5737 sp->data.p = frame->imethod->data_items [ip [2]];
5738 ip += 3;
5739 ++sp;
5740 MINT_IN_BREAK;
5743 MINT_IN_CASE(MINT_LDSSFLDA) {
5744 guint32 offset = READ32(ip + 1);
5745 sp->data.p = mono_get_special_static_data (offset);
5746 ip += 3;
5747 ++sp;
5748 MINT_IN_BREAK;
5751 /* We init class here to preserve cctor order */
5752 #define LDSFLD(datamem, fieldtype) { \
5753 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5754 INIT_VTABLE (vtable); \
5755 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5756 ip += 3; \
5757 sp++; \
5760 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5761 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5762 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5763 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5764 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5765 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5766 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5767 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5768 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5770 MINT_IN_CASE(MINT_LDSFLD_VT) {
5771 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5772 INIT_VTABLE (vtable);
5773 sp->data.p = vt_sp;
5775 gpointer addr = frame->imethod->data_items [ip [2]];
5776 int const i32 = READ32 (ip + 3);
5777 memcpy (vt_sp, addr, i32);
5778 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5779 ip += 5;
5780 ++sp;
5781 MINT_IN_BREAK;
5784 #define LDTSFLD(datamem, fieldtype) { \
5785 MonoInternalThread *thread = mono_thread_internal_current (); \
5786 guint32 offset = READ32 (ip + 1); \
5787 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5788 sp[0].data.datamem = *(fieldtype*)addr; \
5789 ip += 3; \
5790 ++sp; \
5792 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5793 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5794 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5795 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5796 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5797 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5798 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5799 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5800 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5802 MINT_IN_CASE(MINT_LDSSFLD) {
5803 guint32 offset = READ32(ip + 2);
5804 gpointer addr = mono_get_special_static_data (offset);
5805 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5806 stackval_from_data (field->type, sp, addr, FALSE);
5807 ip += 4;
5808 ++sp;
5809 MINT_IN_BREAK;
5811 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5812 guint32 offset = READ32(ip + 1);
5813 gpointer addr = mono_get_special_static_data (offset);
5815 int size = READ32 (ip + 3);
5816 memcpy (vt_sp, addr, size);
5817 sp->data.p = vt_sp;
5818 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5819 ip += 5;
5820 ++sp;
5821 MINT_IN_BREAK;
5823 #define STSFLD(datamem, fieldtype) { \
5824 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5825 INIT_VTABLE (vtable); \
5826 sp --; \
5827 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5828 ip += 3; \
5831 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5832 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5833 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5834 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5835 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5836 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5837 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5838 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5839 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5841 MINT_IN_CASE(MINT_STSFLD_VT) {
5842 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5843 INIT_VTABLE (vtable);
5844 int const i32 = READ32 (ip + 3);
5845 gpointer addr = frame->imethod->data_items [ip [2]];
5847 memcpy (addr, sp [-1].data.vt, i32);
5848 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5849 ip += 5;
5850 --sp;
5851 MINT_IN_BREAK;
5854 #define STTSFLD(datamem, fieldtype) { \
5855 MonoInternalThread *thread = mono_thread_internal_current (); \
5856 guint32 offset = READ32 (ip + 1); \
5857 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5858 sp--; \
5859 *(fieldtype*)addr = sp[0].data.datamem; \
5860 ip += 3; \
5863 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5864 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5865 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5866 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5867 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5868 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5869 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5870 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5871 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5873 MINT_IN_CASE(MINT_STSSFLD) {
5874 guint32 offset = READ32(ip + 2);
5875 gpointer addr = mono_get_special_static_data (offset);
5876 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5877 --sp;
5878 stackval_to_data (field->type, sp, addr, FALSE);
5879 ip += 4;
5880 MINT_IN_BREAK;
5882 MINT_IN_CASE(MINT_STSSFLD_VT) {
5883 guint32 offset = READ32(ip + 1);
5884 gpointer addr = mono_get_special_static_data (offset);
5885 --sp;
5886 int size = READ32 (ip + 3);
5887 memcpy (addr, sp->data.vt, size);
5888 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5889 ip += 5;
5890 MINT_IN_BREAK;
5893 MINT_IN_CASE(MINT_STOBJ_VT) {
5894 int size;
5895 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5896 ip += 2;
5897 size = mono_class_value_size (c, NULL);
5898 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5899 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5900 sp -= 2;
5901 MINT_IN_BREAK;
5903 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5904 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5905 THROW_EX (mono_get_exception_overflow (), ip);
5906 sp [-1].data.i = (gint32)sp [-1].data.f;
5907 ++ip;
5908 MINT_IN_BREAK;
5909 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5910 if (sp [-1].data.i < 0)
5911 THROW_EX (mono_get_exception_overflow (), ip);
5912 sp [-1].data.l = sp [-1].data.i;
5913 ++ip;
5914 MINT_IN_BREAK;
5915 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5916 if (sp [-1].data.l < 0)
5917 THROW_EX (mono_get_exception_overflow (), ip);
5918 ++ip;
5919 MINT_IN_BREAK;
5920 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5921 if ((guint64) sp [-1].data.l > G_MAXINT64)
5922 THROW_EX (mono_get_exception_overflow (), ip);
5923 ++ip;
5924 MINT_IN_BREAK;
5925 MINT_IN_CASE(MINT_CONV_OVF_U8_R4) {
5926 guint64 res = (guint64)sp [-1].data.f_r4;
5927 if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res)
5928 THROW_EX (mono_get_exception_overflow (), ip);
5929 sp [-1].data.l = res;
5930 ++ip;
5931 MINT_IN_BREAK;
5933 MINT_IN_CASE(MINT_CONV_OVF_U8_R8) {
5934 guint64 res = (guint64)sp [-1].data.f;
5935 if (mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res)
5936 THROW_EX (mono_get_exception_overflow (), ip);
5937 sp [-1].data.l = res;
5938 ++ip;
5939 MINT_IN_BREAK;
5941 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8) {
5942 gint64 res = (gint64)sp [-1].data.f;
5943 if (res < 0 || mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res)
5944 THROW_EX (mono_get_exception_overflow (), ip);
5945 sp [-1].data.l = res;
5946 ++ip;
5947 MINT_IN_BREAK;
5949 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4) {
5950 gint64 res = (gint64)sp [-1].data.f_r4;
5951 if (res < 0 || mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res)
5952 THROW_EX (mono_get_exception_overflow (), ip);
5953 sp [-1].data.l = res;
5954 ++ip;
5955 MINT_IN_BREAK;
5957 MINT_IN_CASE(MINT_CONV_OVF_I8_R4) {
5958 gint64 res = (gint64)sp [-1].data.f_r4;
5959 if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res)
5960 THROW_EX (mono_get_exception_overflow (), ip);
5961 sp [-1].data.l = res;
5962 ++ip;
5963 MINT_IN_BREAK;
5965 MINT_IN_CASE(MINT_CONV_OVF_I8_R8) {
5966 gint64 res = (gint64)sp [-1].data.f;
5967 if (mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res)
5968 THROW_EX (mono_get_exception_overflow (), ip);
5969 sp [-1].data.l = res;
5970 ++ip;
5971 MINT_IN_BREAK;
5973 MINT_IN_CASE(MINT_BOX) {
5974 mono_interp_box (frame, ip, sp, tmp_handle);
5975 ip += 3;
5976 MINT_IN_BREAK;
5978 MINT_IN_CASE(MINT_BOX_VT) {
5979 vt_sp -= mono_interp_box_vt (frame, ip, sp, tmp_handle);
5980 ip += 4;
5981 MINT_IN_BREAK;
5983 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5984 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5985 ip += 4;
5986 MINT_IN_BREAK;
5988 MINT_IN_CASE(MINT_NEWARR) {
5989 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]];
5990 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5991 if (!is_ok (error)) {
5992 THROW_EX (mono_error_convert_to_exception (error), ip);
5994 ip += 2;
5995 /*if (profiling_classes) {
5996 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5997 count++;
5998 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
6001 MINT_IN_BREAK;
6003 MINT_IN_CASE(MINT_LDLEN) {
6004 MonoObject* const o = sp [-1].data.o;
6005 NULL_CHECK (o);
6006 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
6007 ++ip;
6008 MINT_IN_BREAK;
6010 MINT_IN_CASE(MINT_LDLEN_SPAN) {
6011 MonoObject* const o = sp [-1].data.o;
6012 NULL_CHECK (o);
6013 gsize offset_length = (gsize)(gint16)ip [1];
6014 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
6015 ip += 2;
6016 MINT_IN_BREAK;
6018 MINT_IN_CASE(MINT_GETCHR) {
6019 MonoString *s;
6020 s = (MonoString*)sp [-2].data.p;
6021 NULL_CHECK (s);
6022 int const i32 = sp [-1].data.i;
6023 if (i32 < 0 || i32 >= mono_string_length_internal (s))
6024 THROW_EX (mono_get_exception_index_out_of_range (), ip);
6025 --sp;
6026 sp [-1].data.i = mono_string_chars_internal (s)[i32];
6027 ++ip;
6028 MINT_IN_BREAK;
6030 MINT_IN_CASE(MINT_GETITEM_SPAN) {
6031 guint8 * const span = (guint8 *) sp [-2].data.p;
6032 const int index = sp [-1].data.i;
6033 sp--;
6035 NULL_CHECK (span);
6037 const gsize offset_length = (gsize)(gint16)ip [2];
6039 const gint32 length = *(gint32 *) (span + offset_length);
6040 if (index < 0 || index >= length)
6041 THROW_EX (mono_get_exception_index_out_of_range (), ip);
6043 const gsize element_size = (gsize)(gint16)ip [1];
6044 const gsize offset_pointer = (gsize)(gint16)ip [3];
6046 const gpointer pointer = *(gpointer *)(span + offset_pointer);
6047 sp [-1].data.p = (guint8 *) pointer + index * element_size;
6049 ip += 4;
6050 MINT_IN_BREAK;
6052 MINT_IN_CASE(MINT_STRLEN) {
6053 ++ip;
6054 MonoObject* const o = sp [-1].data.o;
6055 NULL_CHECK (o);
6056 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
6057 MINT_IN_BREAK;
6059 MINT_IN_CASE(MINT_ARRAY_RANK) {
6060 MonoObject* const o = sp [-1].data.o;
6061 NULL_CHECK (o);
6062 sp [-1].data.i = m_class_get_rank (mono_object_class (o));
6063 ip++;
6064 MINT_IN_BREAK;
6066 MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE) {
6067 MonoObject* const o = sp [-1].data.o;
6068 NULL_CHECK (o);
6069 sp [-1].data.i = mono_array_element_size (mono_object_class (o));
6070 ip++;
6071 MINT_IN_BREAK;
6073 MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE) {
6074 MonoObject* const o = sp [-1].data.o;
6075 NULL_CHECK (o);
6076 sp [-1].data.i = m_class_is_primitive (m_class_get_element_class (mono_object_class (o)));
6077 ip++;
6078 MINT_IN_BREAK;
6080 MINT_IN_CASE(MINT_LDELEMA1) {
6081 /* No bounds, one direction */
6082 MonoArray *ao = (MonoArray*)sp [-2].data.o;
6083 NULL_CHECK (ao);
6084 gint32 const index = sp [-1].data.i;
6085 if (index >= ao->max_length)
6086 THROW_EX (mono_get_exception_index_out_of_range (), ip);
6087 gint32 const size = READ32 (ip + 1);
6088 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
6089 ip += 3;
6090 sp --;
6092 MINT_IN_BREAK;
6094 MINT_IN_CASE(MINT_LDELEMA) {
6095 guint16 rank = ip [1];
6096 gint32 const esize = READ32 (ip + 2);
6097 ip += 4;
6098 sp -= rank;
6100 MonoArray* const ao = (MonoArray*) sp [-1].data.o;
6101 NULL_CHECK (ao);
6103 g_assert (ao->bounds);
6104 guint32 pos = 0;
6105 for (int i = 0; i < rank; i++) {
6106 gint32 idx = sp [i].data.i;
6107 gint32 lower = ao->bounds [i].lower_bound;
6108 guint32 len = ao->bounds [i].length;
6109 if (idx < lower || (guint32)(idx - lower) >= len)
6110 THROW_EX (mono_get_exception_index_out_of_range (), ip);
6111 pos = (pos * len) + (guint32)(idx - lower);
6114 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
6115 MINT_IN_BREAK;
6117 MINT_IN_CASE(MINT_LDELEMA_TC) {
6118 guint16 rank = ip [1];
6119 ip += 3;
6120 sp -= rank;
6122 MonoObject* const o = sp [-1].data.o;
6123 NULL_CHECK (o);
6125 MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [-3 + 2]];
6126 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
6127 MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, sp, needs_typecheck);
6128 if (ex)
6129 THROW_EX (ex, ip);
6130 MINT_IN_BREAK;
6133 #define LDELEM(datamem,elemtype) do { \
6134 sp--; \
6135 MonoArray *o = (MonoArray*)sp [-1].data.p; \
6136 NULL_CHECK (o); \
6137 gint32 aindex = sp [0].data.i; \
6138 if (aindex >= mono_array_length_internal (o)) \
6139 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
6140 sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \
6141 ip++; \
6142 } while (0)
6143 MINT_IN_CASE(MINT_LDELEM_I1) LDELEM(i, gint8); MINT_IN_BREAK;
6144 MINT_IN_CASE(MINT_LDELEM_U1) LDELEM(i, guint8); MINT_IN_BREAK;
6145 MINT_IN_CASE(MINT_LDELEM_I2) LDELEM(i, gint16); MINT_IN_BREAK;
6146 MINT_IN_CASE(MINT_LDELEM_U2) LDELEM(i, guint16); MINT_IN_BREAK;
6147 MINT_IN_CASE(MINT_LDELEM_I4) LDELEM(i, gint32); MINT_IN_BREAK;
6148 MINT_IN_CASE(MINT_LDELEM_U4) LDELEM(i, guint32); MINT_IN_BREAK;
6149 MINT_IN_CASE(MINT_LDELEM_I8) LDELEM(l, guint64); MINT_IN_BREAK;
6150 MINT_IN_CASE(MINT_LDELEM_I) LDELEM(nati, mono_i); MINT_IN_BREAK;
6151 MINT_IN_CASE(MINT_LDELEM_R4) LDELEM(f_r4, float); MINT_IN_BREAK;
6152 MINT_IN_CASE(MINT_LDELEM_R8) LDELEM(f, double); MINT_IN_BREAK;
6153 MINT_IN_CASE(MINT_LDELEM_REF) LDELEM(p, gpointer); MINT_IN_BREAK;
6154 MINT_IN_CASE(MINT_LDELEM_VT) {
6155 sp--;
6156 MonoArray *o = (MonoArray*)sp [-1].data.p;
6157 NULL_CHECK (o);
6158 mono_u aindex = sp [0].data.i;
6159 if (aindex >= mono_array_length_internal (o))
6160 THROW_EX (mono_get_exception_index_out_of_range (), ip);
6162 int i32 = READ32 (ip + 1);
6163 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
6164 sp [-1].data.vt = vt_sp;
6165 // Copying to vtstack. No wbarrier needed
6166 memcpy (sp [-1].data.vt, src_addr, i32);
6167 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6169 ip += 3;
6170 MINT_IN_BREAK;
6172 #define STELEM_PROLOG(o, aindex) do { \
6173 sp -= 3; \
6174 o = (MonoArray*)sp [0].data.p; \
6175 NULL_CHECK (o); \
6176 aindex = sp [1].data.i; \
6177 if (aindex >= mono_array_length_internal (o)) \
6178 THROW_EX (mono_get_exception_index_out_of_range (), ip); \
6179 } while (0)
6181 #define STELEM(datamem,elemtype) do { \
6182 MonoArray *o; \
6183 gint32 aindex; \
6184 STELEM_PROLOG(o, aindex); \
6185 mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \
6186 ip++; \
6187 } while (0)
6188 MINT_IN_CASE(MINT_STELEM_I1) STELEM(i, gint8); MINT_IN_BREAK;
6189 MINT_IN_CASE(MINT_STELEM_U1) STELEM(i, guint8); MINT_IN_BREAK;
6190 MINT_IN_CASE(MINT_STELEM_I2) STELEM(i, gint16); MINT_IN_BREAK;
6191 MINT_IN_CASE(MINT_STELEM_U2) STELEM(i, guint16); MINT_IN_BREAK;
6192 MINT_IN_CASE(MINT_STELEM_I4) STELEM(i, gint32); MINT_IN_BREAK;
6193 MINT_IN_CASE(MINT_STELEM_I8) STELEM(l, gint64); MINT_IN_BREAK;
6194 MINT_IN_CASE(MINT_STELEM_I) STELEM(nati, mono_i); MINT_IN_BREAK;
6195 MINT_IN_CASE(MINT_STELEM_R4) STELEM(f_r4, float); MINT_IN_BREAK;
6196 MINT_IN_CASE(MINT_STELEM_R8) STELEM(f, double); MINT_IN_BREAK;
6197 MINT_IN_CASE(MINT_STELEM_REF) {
6198 MonoArray *o;
6199 gint32 aindex;
6200 STELEM_PROLOG(o, aindex);
6202 if (sp [2].data.o) {
6203 gboolean isinst = mono_interp_isinst (sp [2].data.o, m_class_get_element_class (mono_object_class (o)));
6204 if (!isinst)
6205 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
6207 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
6208 ip++;
6209 MINT_IN_BREAK;
6212 MINT_IN_CASE(MINT_STELEM_VT) {
6213 MonoArray *o;
6214 gint32 aindex;
6215 STELEM_PROLOG(o, aindex);
6217 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [1]];
6218 int const i32 = READ32 (ip + 2);
6219 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
6221 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
6222 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6223 ip += 4;
6224 MINT_IN_BREAK;
6226 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
6227 if (sp [-1].data.i < 0)
6228 THROW_EX (mono_get_exception_overflow (), ip);
6229 ++ip;
6230 MINT_IN_BREAK;
6231 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
6232 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
6233 THROW_EX (mono_get_exception_overflow (), ip);
6234 sp [-1].data.i = (gint32) sp [-1].data.l;
6235 ++ip;
6236 MINT_IN_BREAK;
6237 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
6238 if ((guint64)sp [-1].data.l > G_MAXINT32)
6239 THROW_EX (mono_get_exception_overflow (), ip);
6240 sp [-1].data.i = (gint32) sp [-1].data.l;
6241 ++ip;
6242 MINT_IN_BREAK;
6243 MINT_IN_CASE(MINT_CONV_OVF_I4_R4) {
6244 gint32 res = (gint32)sp [-1].data.f_r4;
6245 if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res)
6246 THROW_EX (mono_get_exception_overflow (), ip);
6247 sp [-1].data.i = res;
6248 ++ip;
6249 MINT_IN_BREAK;
6251 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
6252 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32 || isnan (sp [-1].data.f))
6253 THROW_EX (mono_get_exception_overflow (), ip);
6254 sp [-1].data.i = (gint32) sp [-1].data.f;
6255 ++ip;
6256 MINT_IN_BREAK;
6257 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
6258 if (sp [-1].data.i < 0)
6259 THROW_EX (mono_get_exception_overflow (), ip);
6260 ++ip;
6261 MINT_IN_BREAK;
6262 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
6263 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
6264 THROW_EX (mono_get_exception_overflow (), ip);
6265 sp [-1].data.i = (guint32) sp [-1].data.l;
6266 ++ip;
6267 MINT_IN_BREAK;
6268 MINT_IN_CASE(MINT_CONV_OVF_U4_R4) {
6269 guint32 res = (guint32)sp [-1].data.f_r4;
6270 if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res)
6271 THROW_EX (mono_get_exception_overflow (), ip);
6272 sp [-1].data.i = res;
6273 ++ip;
6274 MINT_IN_BREAK;
6276 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
6277 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32 || isnan (sp [-1].data.f))
6278 THROW_EX (mono_get_exception_overflow (), ip);
6279 sp [-1].data.i = (guint32) sp [-1].data.f;
6280 ++ip;
6281 MINT_IN_BREAK;
6282 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
6283 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
6284 THROW_EX (mono_get_exception_overflow (), ip);
6285 ++ip;
6286 MINT_IN_BREAK;
6287 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
6288 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
6289 THROW_EX (mono_get_exception_overflow (), ip);
6290 ++ip;
6291 MINT_IN_BREAK;
6292 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
6293 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
6294 THROW_EX (mono_get_exception_overflow (), ip);
6295 sp [-1].data.i = (gint16) sp [-1].data.l;
6296 ++ip;
6297 MINT_IN_BREAK;
6298 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
6299 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
6300 THROW_EX (mono_get_exception_overflow (), ip);
6301 sp [-1].data.i = (gint16) sp [-1].data.l;
6302 ++ip;
6303 MINT_IN_BREAK;
6304 MINT_IN_CASE(MINT_CONV_OVF_I2_R4)
6305 if (sp [-1].data.f_r4 < G_MININT16 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4))
6306 THROW_EX (mono_get_exception_overflow (), ip);
6307 sp [-1].data.i = (gint16) sp [-1].data.f_r4;
6308 ++ip;
6309 MINT_IN_BREAK;
6310 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
6311 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f))
6312 THROW_EX (mono_get_exception_overflow (), ip);
6313 sp [-1].data.i = (gint16) sp [-1].data.f;
6314 ++ip;
6315 MINT_IN_BREAK;
6316 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4)
6317 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4))
6318 THROW_EX (mono_get_exception_overflow (), ip);
6319 sp [-1].data.i = (gint16) sp [-1].data.f_r4;
6320 ++ip;
6321 MINT_IN_BREAK;
6322 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
6323 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f))
6324 THROW_EX (mono_get_exception_overflow (), ip);
6325 sp [-1].data.i = (gint16) sp [-1].data.f;
6326 ++ip;
6327 MINT_IN_BREAK;
6328 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
6329 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
6330 THROW_EX (mono_get_exception_overflow (), ip);
6331 ++ip;
6332 MINT_IN_BREAK;
6333 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
6334 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
6335 THROW_EX (mono_get_exception_overflow (), ip);
6336 sp [-1].data.i = (guint16) sp [-1].data.l;
6337 ++ip;
6338 MINT_IN_BREAK;
6339 MINT_IN_CASE(MINT_CONV_OVF_U2_R4)
6340 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT16 || isnan (sp [-1].data.f_r4))
6341 THROW_EX (mono_get_exception_overflow (), ip);
6342 sp [-1].data.i = (guint16) sp [-1].data.f_r4;
6343 ++ip;
6344 MINT_IN_BREAK;
6345 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
6346 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16 || isnan (sp [-1].data.f))
6347 THROW_EX (mono_get_exception_overflow (), ip);
6348 sp [-1].data.i = (guint16) sp [-1].data.f;
6349 ++ip;
6350 MINT_IN_BREAK;
6351 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
6352 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
6353 THROW_EX (mono_get_exception_overflow (), ip);
6354 ++ip;
6355 MINT_IN_BREAK;
6356 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
6357 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
6358 THROW_EX (mono_get_exception_overflow (), ip);
6359 ++ip;
6360 MINT_IN_BREAK;
6361 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
6362 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
6363 THROW_EX (mono_get_exception_overflow (), ip);
6364 sp [-1].data.i = (gint8) sp [-1].data.l;
6365 ++ip;
6366 MINT_IN_BREAK;
6367 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
6368 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
6369 THROW_EX (mono_get_exception_overflow (), ip);
6370 sp [-1].data.i = (gint8) sp [-1].data.l;
6371 ++ip;
6372 MINT_IN_BREAK;
6373 MINT_IN_CASE(MINT_CONV_OVF_I1_R4)
6374 if (sp [-1].data.f_r4 < G_MININT8 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4))
6375 THROW_EX (mono_get_exception_overflow (), ip);
6376 sp [-1].data.i = (gint8) sp [-1].data.f_r4;
6377 ++ip;
6378 MINT_IN_BREAK;
6379 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
6380 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f))
6381 THROW_EX (mono_get_exception_overflow (), ip);
6382 sp [-1].data.i = (gint8) sp [-1].data.f;
6383 ++ip;
6384 MINT_IN_BREAK;
6385 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4)
6386 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4))
6387 THROW_EX (mono_get_exception_overflow (), ip);
6388 sp [-1].data.i = (gint8) sp [-1].data.f_r4;
6389 ++ip;
6390 MINT_IN_BREAK;
6391 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
6392 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f))
6393 THROW_EX (mono_get_exception_overflow (), ip);
6394 sp [-1].data.i = (gint8) sp [-1].data.f;
6395 ++ip;
6396 MINT_IN_BREAK;
6397 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
6398 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
6399 THROW_EX (mono_get_exception_overflow (), ip);
6400 ++ip;
6401 MINT_IN_BREAK;
6402 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
6403 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
6404 THROW_EX (mono_get_exception_overflow (), ip);
6405 sp [-1].data.i = (guint8) sp [-1].data.l;
6406 ++ip;
6407 MINT_IN_BREAK;
6408 MINT_IN_CASE(MINT_CONV_OVF_U1_R4)
6409 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT8 || isnan (sp [-1].data.f_r4))
6410 THROW_EX (mono_get_exception_overflow (), ip);
6411 sp [-1].data.i = (guint8) sp [-1].data.f_r4;
6412 ++ip;
6413 MINT_IN_BREAK;
6414 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
6415 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8 || isnan (sp [-1].data.f))
6416 THROW_EX (mono_get_exception_overflow (), ip);
6417 sp [-1].data.i = (guint8) sp [-1].data.f;
6418 ++ip;
6419 MINT_IN_BREAK;
6420 MINT_IN_CASE(MINT_CKFINITE)
6421 if (!mono_isfinite (sp [-1].data.f))
6422 THROW_EX (mono_get_exception_arithmetic (), ip);
6423 ++ip;
6424 MINT_IN_BREAK;
6425 MINT_IN_CASE(MINT_MKREFANY) {
6426 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
6428 /* The value address is on the stack */
6429 gpointer addr = sp [-1].data.p;
6430 /* Push the typedref value on the stack */
6431 sp [-1].data.p = vt_sp;
6432 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6434 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6435 tref->klass = c;
6436 tref->type = m_class_get_byval_arg (c);
6437 tref->value = addr;
6439 ip += 2;
6440 MINT_IN_BREAK;
6442 MINT_IN_CASE(MINT_REFANYTYPE) {
6443 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6444 MonoType *type = tref->type;
6446 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6447 sp [-1].data.p = vt_sp;
6448 vt_sp += 8;
6449 *(gpointer*)sp [-1].data.p = type;
6450 ip ++;
6451 MINT_IN_BREAK;
6453 MINT_IN_CASE(MINT_REFANYVAL) {
6454 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
6455 gpointer addr = tref->value;
6457 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
6458 if (c != tref->klass)
6459 THROW_EX (mono_get_exception_invalid_cast (), ip);
6461 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
6463 sp [-1].data.p = addr;
6464 ip += 2;
6465 MINT_IN_BREAK;
6467 MINT_IN_CASE(MINT_LDTOKEN)
6468 sp->data.p = vt_sp;
6469 vt_sp += 8;
6470 * (gpointer *)sp->data.p = frame->imethod->data_items[ip [1]];
6471 ip += 2;
6472 ++sp;
6473 MINT_IN_BREAK;
6474 MINT_IN_CASE(MINT_ADD_OVF_I4)
6475 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6476 THROW_EX (mono_get_exception_overflow (), ip);
6477 BINOP(i, +);
6478 MINT_IN_BREAK;
6479 MINT_IN_CASE(MINT_ADD_OVF_I8)
6480 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6481 THROW_EX (mono_get_exception_overflow (), ip);
6482 BINOP(l, +);
6483 MINT_IN_BREAK;
6484 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
6485 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6486 THROW_EX (mono_get_exception_overflow (), ip);
6487 BINOP_CAST(i, +, guint32);
6488 MINT_IN_BREAK;
6489 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
6490 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6491 THROW_EX (mono_get_exception_overflow (), ip);
6492 BINOP_CAST(l, +, guint64);
6493 MINT_IN_BREAK;
6494 MINT_IN_CASE(MINT_MUL_OVF_I4)
6495 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6496 THROW_EX (mono_get_exception_overflow (), ip);
6497 BINOP(i, *);
6498 MINT_IN_BREAK;
6499 MINT_IN_CASE(MINT_MUL_OVF_I8)
6500 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6501 THROW_EX (mono_get_exception_overflow (), ip);
6502 BINOP(l, *);
6503 MINT_IN_BREAK;
6504 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
6505 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6506 THROW_EX (mono_get_exception_overflow (), ip);
6507 BINOP_CAST(i, *, guint32);
6508 MINT_IN_BREAK;
6509 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
6510 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6511 THROW_EX (mono_get_exception_overflow (), ip);
6512 BINOP_CAST(l, *, guint64);
6513 MINT_IN_BREAK;
6514 MINT_IN_CASE(MINT_SUB_OVF_I4)
6515 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
6516 THROW_EX (mono_get_exception_overflow (), ip);
6517 BINOP(i, -);
6518 MINT_IN_BREAK;
6519 MINT_IN_CASE(MINT_SUB_OVF_I8)
6520 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
6521 THROW_EX (mono_get_exception_overflow (), ip);
6522 BINOP(l, -);
6523 MINT_IN_BREAK;
6524 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
6525 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
6526 THROW_EX (mono_get_exception_overflow (), ip);
6527 BINOP_CAST(i, -, guint32);
6528 MINT_IN_BREAK;
6529 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
6530 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
6531 THROW_EX (mono_get_exception_overflow (), ip);
6532 BINOP_CAST(l, -, guint64);
6533 MINT_IN_BREAK;
6534 MINT_IN_CASE(MINT_START_ABORT_PROT)
6535 mono_threads_begin_abort_protected_block ();
6536 ip ++;
6537 MINT_IN_BREAK;
6538 MINT_IN_CASE(MINT_ENDFINALLY) {
6539 gboolean pending_abort = mono_threads_end_abort_protected_block ();
6540 ip ++;
6542 // After mono_threads_end_abort_protected_block to conserve stack.
6543 const int clause_index = *ip;
6545 // clause_args stores the clause args only for the first frame that
6546 // we started executing in interp_exec_method. If we are exiting the
6547 // current frame at this finally clause, we need to make sure that
6548 // this is the first frame invoked with interp_exec_method.
6549 if (clause_args && clause_args->exec_frame == frame && clause_index == clause_args->exit_clause)
6550 goto exit_clause;
6552 // endfinally empties the stack
6553 vt_sp = (guchar*)frame->stack + frame->imethod->total_locals_size;
6554 sp = (stackval*)(vt_sp + frame->imethod->vt_stack_size);
6556 if (finally_ips) {
6557 ip = (const guint16*)finally_ips->data;
6558 finally_ips = g_slist_remove (finally_ips, ip);
6559 /* Throw abort after the last finally block to avoid confusing EH */
6560 if (pending_abort && !finally_ips)
6561 EXCEPTION_CHECKPOINT;
6562 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6563 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6564 goto main_loop;
6566 ves_abort();
6567 MINT_IN_BREAK;
6570 MINT_IN_CASE(MINT_LEAVE)
6571 MINT_IN_CASE(MINT_LEAVE_S)
6572 MINT_IN_CASE(MINT_LEAVE_CHECK)
6573 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
6574 guint32 ip_offset = ip - frame->imethod->code;
6575 // leave empties the stack
6576 vt_sp = (guchar*)frame->stack + frame->imethod->total_locals_size;
6577 sp = (stackval*)(vt_sp + frame->imethod->vt_stack_size);
6579 int opcode = *ip;
6580 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
6582 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
6583 MonoException *abort_exc = mono_interp_leave (frame);
6584 if (abort_exc)
6585 THROW_EX (abort_exc, ip);
6588 opcode = *ip; // Refetch to avoid register/stack pressure.
6589 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
6590 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
6591 const guint16 *endfinally_ip = ip;
6592 GSList *old_list = finally_ips;
6593 #if DEBUG_INTERP
6594 if (tracing)
6595 g_print ("* Handle finally IL_%04x\n", endfinally_ip - frame->imethod->code);
6596 #endif
6597 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
6599 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
6600 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
6601 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code))) {
6602 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6603 ip = frame->imethod->code + clause->handler_offset;
6604 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6605 #if DEBUG_INTERP
6606 if (tracing)
6607 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, context->has_resume_state ? "yes": "no");
6608 #endif
6613 if (old_list != finally_ips && finally_ips) {
6614 ip = (const guint16*)finally_ips->data;
6615 finally_ips = g_slist_remove (finally_ips, ip);
6616 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6617 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6618 goto main_loop;
6621 ves_abort();
6622 MINT_IN_BREAK;
6624 MINT_IN_CASE(MINT_ICALL_V_V)
6625 MINT_IN_CASE(MINT_ICALL_V_P)
6626 MINT_IN_CASE(MINT_ICALL_P_V)
6627 MINT_IN_CASE(MINT_ICALL_P_P)
6628 MINT_IN_CASE(MINT_ICALL_PP_V)
6629 MINT_IN_CASE(MINT_ICALL_PP_P)
6630 MINT_IN_CASE(MINT_ICALL_PPP_V)
6631 MINT_IN_CASE(MINT_ICALL_PPP_P)
6632 MINT_IN_CASE(MINT_ICALL_PPPP_V)
6633 MINT_IN_CASE(MINT_ICALL_PPPP_P)
6634 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
6635 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
6636 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
6637 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
6638 frame->state.ip = ip + 2;
6639 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [ip [1]], FALSE);
6640 EXCEPTION_CHECKPOINT_GC_UNSAFE;
6641 CHECK_RESUME_STATE (context);
6642 ip += 2;
6643 MINT_IN_BREAK;
6644 MINT_IN_CASE(MINT_MONO_LDPTR)
6645 sp->data.p = frame->imethod->data_items [ip [1]];
6646 ip += 2;
6647 ++sp;
6648 MINT_IN_BREAK;
6649 MINT_IN_CASE(MINT_MONO_NEWOBJ)
6650 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [1]]); // FIXME: do not swallow the error
6651 ip += 2;
6652 sp++;
6653 MINT_IN_BREAK;
6654 MINT_IN_CASE(MINT_MONO_RETOBJ)
6655 ++ip;
6656 sp--;
6657 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
6658 mono_method_signature_internal (frame->imethod->method)->pinvoke);
6659 if (sp > frame->stack)
6660 g_warning_d ("retobj: more values on stack: %d", sp - frame->stack);
6661 frame_data_allocator_pop (&context->data_stack, frame);
6662 goto exit_frame;
6663 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
6664 sp->data.p = mono_tls_get_sgen_thread_info ();
6665 sp++;
6666 ++ip;
6667 MINT_IN_BREAK;
6668 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
6669 ++ip;
6670 mono_memory_barrier ();
6671 MINT_IN_BREAK;
6673 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
6674 sp->data.p = mono_domain_get ();
6675 ++sp;
6676 ++ip;
6677 MINT_IN_BREAK;
6678 MINT_IN_CASE(MINT_MONO_GET_SP)
6679 sp->data.p = frame;
6680 ++sp;
6681 ++ip;
6682 MINT_IN_BREAK;
6683 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6684 if (G_UNLIKELY (ss_enabled)) {
6685 typedef void (*T) (void);
6686 static T ss_tramp;
6688 if (!ss_tramp) {
6689 void *tramp = mini_get_single_step_trampoline ();
6690 mono_memory_barrier ();
6691 ss_tramp = (T)tramp;
6695 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6696 * the address of that instruction is stored as the seq point address. Add also
6697 * 1 to offset subtraction from interp_frame_get_ip.
6699 frame->state.ip = ip + 2;
6702 * Use the same trampoline as the JIT. This ensures that
6703 * the debugger has the context for the last interpreter
6704 * native frame.
6706 do_debugger_tramp (ss_tramp, frame);
6708 CHECK_RESUME_STATE (context);
6710 ++ip;
6711 MINT_IN_BREAK;
6712 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6713 /* Just a placeholder for a breakpoint */
6714 ++ip;
6715 MINT_IN_BREAK;
6716 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6717 typedef void (*T) (void);
6718 static T bp_tramp;
6719 if (!bp_tramp) {
6720 void *tramp = mini_get_breakpoint_trampoline ();
6721 mono_memory_barrier ();
6722 bp_tramp = (T)tramp;
6725 /* Add 1 to offset subtraction from interp_frame_get_ip */
6726 frame->state.ip = ip + 1;
6728 /* Use the same trampoline as the JIT */
6729 do_debugger_tramp (bp_tramp, frame);
6731 CHECK_RESUME_STATE (context);
6733 ++ip;
6734 MINT_IN_BREAK;
6737 #define RELOP(datamem, op) \
6738 --sp; \
6739 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6740 ++ip;
6742 #define RELOP_FP(datamem, op, noorder) \
6743 --sp; \
6744 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6745 sp [-1].data.i = noorder; \
6746 else \
6747 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6748 ++ip;
6750 MINT_IN_CASE(MINT_CEQ_I4)
6751 RELOP(i, ==);
6752 MINT_IN_BREAK;
6753 MINT_IN_CASE(MINT_CEQ0_I4)
6754 sp [-1].data.i = (sp [-1].data.i == 0);
6755 ++ip;
6756 MINT_IN_BREAK;
6757 MINT_IN_CASE(MINT_CEQ_I8)
6758 RELOP(l, ==);
6759 MINT_IN_BREAK;
6760 MINT_IN_CASE(MINT_CEQ_R4)
6761 RELOP_FP(f_r4, ==, 0);
6762 MINT_IN_BREAK;
6763 MINT_IN_CASE(MINT_CEQ_R8)
6764 RELOP_FP(f, ==, 0);
6765 MINT_IN_BREAK;
6766 MINT_IN_CASE(MINT_CNE_I4)
6767 RELOP(i, !=);
6768 MINT_IN_BREAK;
6769 MINT_IN_CASE(MINT_CNE_I8)
6770 RELOP(l, !=);
6771 MINT_IN_BREAK;
6772 MINT_IN_CASE(MINT_CNE_R4)
6773 RELOP_FP(f_r4, !=, 1);
6774 MINT_IN_BREAK;
6775 MINT_IN_CASE(MINT_CNE_R8)
6776 RELOP_FP(f, !=, 1);
6777 MINT_IN_BREAK;
6778 MINT_IN_CASE(MINT_CGT_I4)
6779 RELOP(i, >);
6780 MINT_IN_BREAK;
6781 MINT_IN_CASE(MINT_CGT_I8)
6782 RELOP(l, >);
6783 MINT_IN_BREAK;
6784 MINT_IN_CASE(MINT_CGT_R4)
6785 RELOP_FP(f_r4, >, 0);
6786 MINT_IN_BREAK;
6787 MINT_IN_CASE(MINT_CGT_R8)
6788 RELOP_FP(f, >, 0);
6789 MINT_IN_BREAK;
6790 MINT_IN_CASE(MINT_CGE_I4)
6791 RELOP(i, >=);
6792 MINT_IN_BREAK;
6793 MINT_IN_CASE(MINT_CGE_I8)
6794 RELOP(l, >=);
6795 MINT_IN_BREAK;
6796 MINT_IN_CASE(MINT_CGE_R4)
6797 RELOP_FP(f_r4, >=, 0);
6798 MINT_IN_BREAK;
6799 MINT_IN_CASE(MINT_CGE_R8)
6800 RELOP_FP(f, >=, 0);
6801 MINT_IN_BREAK;
6803 #define RELOP_CAST(datamem, op, type) \
6804 --sp; \
6805 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6806 ++ip;
6808 MINT_IN_CASE(MINT_CGE_UN_I4)
6809 RELOP_CAST(l, >=, guint32);
6810 MINT_IN_BREAK;
6811 MINT_IN_CASE(MINT_CGE_UN_I8)
6812 RELOP_CAST(l, >=, guint64);
6813 MINT_IN_BREAK;
6815 MINT_IN_CASE(MINT_CGT_UN_I4)
6816 RELOP_CAST(i, >, guint32);
6817 MINT_IN_BREAK;
6818 MINT_IN_CASE(MINT_CGT_UN_I8)
6819 RELOP_CAST(l, >, guint64);
6820 MINT_IN_BREAK;
6821 MINT_IN_CASE(MINT_CGT_UN_R4)
6822 RELOP_FP(f_r4, >, 1);
6823 MINT_IN_BREAK;
6824 MINT_IN_CASE(MINT_CGT_UN_R8)
6825 RELOP_FP(f, >, 1);
6826 MINT_IN_BREAK;
6827 MINT_IN_CASE(MINT_CLT_I4)
6828 RELOP(i, <);
6829 MINT_IN_BREAK;
6830 MINT_IN_CASE(MINT_CLT_I8)
6831 RELOP(l, <);
6832 MINT_IN_BREAK;
6833 MINT_IN_CASE(MINT_CLT_R4)
6834 RELOP_FP(f_r4, <, 0);
6835 MINT_IN_BREAK;
6836 MINT_IN_CASE(MINT_CLT_R8)
6837 RELOP_FP(f, <, 0);
6838 MINT_IN_BREAK;
6839 MINT_IN_CASE(MINT_CLT_UN_I4)
6840 RELOP_CAST(i, <, guint32);
6841 MINT_IN_BREAK;
6842 MINT_IN_CASE(MINT_CLT_UN_I8)
6843 RELOP_CAST(l, <, guint64);
6844 MINT_IN_BREAK;
6845 MINT_IN_CASE(MINT_CLT_UN_R4)
6846 RELOP_FP(f_r4, <, 1);
6847 MINT_IN_BREAK;
6848 MINT_IN_CASE(MINT_CLT_UN_R8)
6849 RELOP_FP(f, <, 1);
6850 MINT_IN_BREAK;
6851 MINT_IN_CASE(MINT_CLE_I4)
6852 RELOP(i, <=);
6853 MINT_IN_BREAK;
6854 MINT_IN_CASE(MINT_CLE_I8)
6855 RELOP(l, <=);
6856 MINT_IN_BREAK;
6857 MINT_IN_CASE(MINT_CLE_UN_I4)
6858 RELOP_CAST(l, <=, guint32);
6859 MINT_IN_BREAK;
6860 MINT_IN_CASE(MINT_CLE_UN_I8)
6861 RELOP_CAST(l, <=, guint64);
6862 MINT_IN_BREAK;
6863 MINT_IN_CASE(MINT_CLE_R4)
6864 RELOP_FP(f_r4, <=, 0);
6865 MINT_IN_BREAK;
6866 MINT_IN_CASE(MINT_CLE_R8)
6867 RELOP_FP(f, <=, 0);
6868 MINT_IN_BREAK;
6870 #undef RELOP
6871 #undef RELOP_FP
6872 #undef RELOP_CAST
6874 MINT_IN_CASE(MINT_LDFTN) {
6875 sp->data.p = frame->imethod->data_items [ip [1]];
6876 ++sp;
6877 ip += 2;
6878 MINT_IN_BREAK;
6880 MINT_IN_CASE(MINT_LDVIRTFTN) {
6881 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [1]];
6882 --sp;
6883 NULL_CHECK (sp->data.p);
6885 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6886 ip += 2;
6887 ++sp;
6888 MINT_IN_BREAK;
6890 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6891 error_init_reuse (error);
6892 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6893 mono_error_assert_ok (error);
6894 sp [-1].data.p = m;
6895 ip++;
6896 MINT_IN_BREAK;
6899 MINT_IN_CASE(MINT_LDARG_VT) {
6900 sp->data.p = vt_sp;
6901 int const i32 = READ32 (ip + 2);
6902 memcpy(sp->data.p, frame->stack [ip [1]].data.p, i32);
6903 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6904 ip += 4;
6905 ++sp;
6906 MINT_IN_BREAK;
6909 MINT_IN_CASE(MINT_STARG_VT) {
6910 int const i32 = READ32 (ip + 2);
6911 --sp;
6912 memcpy(frame->stack [ip [1]].data.p, sp->data.p, i32);
6913 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6914 ip += 4;
6915 MINT_IN_BREAK;
6918 MINT_IN_CASE(MINT_PROF_ENTER) {
6919 guint16 flag = ip [1];
6920 ip += 2;
6922 if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter) &&
6923 (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT))) {
6924 MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6925 prof_ctx->interp_frame = frame;
6926 prof_ctx->method = frame->imethod->method;
6927 if (flag & TRACING_FLAG)
6928 mono_trace_enter_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx);
6929 if (flag & PROFILING_FLAG)
6930 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6931 g_free (prof_ctx);
6932 } else if ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter)) {
6933 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, NULL));
6935 MINT_IN_BREAK;
6938 MINT_IN_CASE(MINT_PROF_EXIT)
6939 MINT_IN_CASE(MINT_PROF_EXIT_VOID) {
6940 guint16 flag = ip [1];
6941 // Set retval
6942 int const i32 = READ32 (ip + 2);
6943 if (i32 == -1) {
6944 } else if (i32) {
6945 sp--;
6946 if (frame->parent) {
6947 gpointer dest_vt = frame->parent->state.vt_sp;
6948 /* Push the valuetype in the parent frame */
6949 memcpy (dest_vt, sp->data.p, i32);
6950 frame->parent->state.sp [0].data.p = dest_vt;
6951 frame->parent->state.sp++;
6952 frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6953 } else {
6954 memcpy (frame->retval->data.p, sp->data.p, i32);
6956 } else {
6957 sp--;
6958 if (frame->parent) {
6959 frame->parent->state.sp [0] = *sp;
6960 frame->parent->state.sp++;
6961 } else {
6962 *frame->retval = *sp;
6966 if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_leave) &&
6967 (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT))) {
6968 MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6969 prof_ctx->interp_frame = frame;
6970 prof_ctx->method = frame->imethod->method;
6971 if (i32 != -1) {
6972 if (i32) {
6973 if (frame->parent)
6974 prof_ctx->return_value = frame->parent->state.sp [-1].data.p;
6975 else
6976 prof_ctx->return_value = frame->retval->data.p;
6977 } else {
6978 if (frame->parent)
6979 prof_ctx->return_value = frame->parent->state.sp - 1;
6980 else
6981 prof_ctx->return_value = frame->retval;
6984 if (flag & TRACING_FLAG)
6985 mono_trace_leave_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx);
6986 if (flag & PROFILING_FLAG)
6987 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6988 g_free (prof_ctx);
6989 } else if ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_enter)) {
6990 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, NULL));
6993 ip += 4;
6994 frame_data_allocator_pop (&context->data_stack, frame);
6995 goto exit_frame;
6997 MINT_IN_CASE(MINT_PROF_COVERAGE_STORE) {
6998 ++ip;
6999 guint32 *p = (guint32*)GINT_TO_POINTER (READ64 (ip));
7000 *p = 1;
7001 ip += 4;
7002 MINT_IN_BREAK;
7005 MINT_IN_CASE(MINT_LDARGA_VT)
7006 sp->data.p = frame->stack [ip [1]].data.p;
7007 ip += 2;
7008 ++sp;
7009 MINT_IN_BREAK;
7011 #define LDLOC(datamem, argtype) \
7012 sp->data.datamem = * (argtype *)(locals + ip [1]); \
7013 ip += 2; \
7014 ++sp;
7016 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
7017 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
7018 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
7019 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
7020 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
7021 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
7022 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
7023 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
7024 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
7026 MINT_IN_CASE(MINT_LDLOC_VT) {
7027 sp->data.p = vt_sp;
7028 int const i32 = READ32 (ip + 2);
7029 memcpy(sp->data.p, locals + ip [1], i32);
7030 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
7031 ip += 4;
7032 ++sp;
7033 MINT_IN_BREAK;
7035 MINT_IN_CASE(MINT_LDLOCA_S)
7036 sp->data.p = locals + ip [1];
7037 ip += 2;
7038 ++sp;
7039 MINT_IN_BREAK;
7041 #define STLOC(datamem, argtype) \
7042 --sp; \
7043 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
7044 ip += 2;
7046 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
7047 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
7048 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
7049 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
7050 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
7051 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
7052 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
7053 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
7054 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
7056 #define STLOC_NP(datamem, argtype) \
7057 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
7058 ip += 2;
7060 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
7061 MINT_IN_CASE(MINT_STLOC_NP_I8) STLOC_NP(l, gint64); MINT_IN_BREAK;
7062 MINT_IN_CASE(MINT_STLOC_NP_R4) STLOC_NP(f_r4, float); MINT_IN_BREAK;
7063 MINT_IN_CASE(MINT_STLOC_NP_R8) STLOC_NP(f, double); MINT_IN_BREAK;
7064 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
7066 MINT_IN_CASE(MINT_STLOC_VT) {
7067 int const i32 = READ32 (ip + 2);
7068 --sp;
7069 memcpy(locals + ip [1], sp->data.p, i32);
7070 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
7071 ip += 4;
7072 MINT_IN_BREAK;
7075 #define MOVLOC(argtype) \
7076 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
7077 ip += 3;
7079 MINT_IN_CASE(MINT_MOVLOC_1) MOVLOC(guint8); MINT_IN_BREAK;
7080 MINT_IN_CASE(MINT_MOVLOC_2) MOVLOC(guint16); MINT_IN_BREAK;
7081 MINT_IN_CASE(MINT_MOVLOC_4) MOVLOC(guint32); MINT_IN_BREAK;
7082 MINT_IN_CASE(MINT_MOVLOC_8) MOVLOC(guint64); MINT_IN_BREAK;
7084 MINT_IN_CASE(MINT_MOVLOC_VT) {
7085 int const i32 = READ32(ip + 3);
7086 memcpy (locals + ip [2], locals + ip [1], i32);
7087 ip += 5;
7088 MINT_IN_BREAK;
7091 MINT_IN_CASE(MINT_LOCALLOC) {
7092 stackval *sp_start = (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size);
7093 if (sp != sp_start + 1) /*FIX?*/
7094 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
7096 int len = sp [-1].data.i;
7097 // FIXME we need a separate allocator for localloc sections
7098 sp [-1].data.p = frame_data_allocator_alloc (&context->data_stack, frame, ALIGN_TO (len, MINT_VT_ALIGNMENT));
7100 if (frame->imethod->init_locals)
7101 memset (sp [-1].data.p, 0, len);
7102 ++ip;
7103 MINT_IN_BREAK;
7105 MINT_IN_CASE(MINT_ENDFILTER)
7106 /* top of stack is result of filter */
7107 frame->retval->data.i = sp [-1].data.i;
7108 goto exit_clause;
7109 MINT_IN_CASE(MINT_INITOBJ)
7110 --sp;
7111 memset (sp->data.vt, 0, READ32(ip + 1));
7112 ip += 3;
7113 MINT_IN_BREAK;
7114 MINT_IN_CASE(MINT_CPBLK)
7115 sp -= 3;
7116 if (!sp [0].data.p || !sp [1].data.p)
7117 THROW_EX (mono_get_exception_null_reference(), ip - 1);
7118 ++ip;
7119 /* FIXME: value and size may be int64... */
7120 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
7121 MINT_IN_BREAK;
7122 #if 0
7123 MINT_IN_CASE(MINT_CONSTRAINED_) {
7124 guint32 token;
7125 /* FIXME: implement */
7126 ++ip;
7127 token = READ32 (ip);
7128 ip += 2;
7129 MINT_IN_BREAK;
7131 #endif
7132 MINT_IN_CASE(MINT_INITBLK)
7133 sp -= 3;
7134 NULL_CHECK (sp [0].data.p);
7135 ++ip;
7136 /* FIXME: value and size may be int64... */
7137 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
7138 MINT_IN_BREAK;
7139 #if 0
7140 MINT_IN_CASE(MINT_NO_)
7141 /* FIXME: implement */
7142 ip += 2;
7143 MINT_IN_BREAK;
7144 #endif
7145 MINT_IN_CASE(MINT_RETHROW) {
7146 int exvar_offset = ip [1];
7147 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
7148 MINT_IN_BREAK;
7150 MINT_IN_CASE(MINT_MONO_RETHROW) {
7152 * need to clarify what this should actually do:
7154 * Takes an exception from the stack and rethrows it.
7155 * This is useful for wrappers that don't want to have to
7156 * use CEE_THROW and lose the exception stacktrace.
7159 --sp;
7160 if (!sp->data.p)
7161 sp->data.p = mono_get_exception_null_reference ();
7163 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
7164 MINT_IN_BREAK;
7166 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
7167 MonoDelegate *del;
7169 --sp;
7170 del = (MonoDelegate*)sp->data.p;
7171 if (!del->interp_method) {
7172 /* Not created from interpreted code */
7173 error_init_reuse (error);
7174 g_assert (del->method);
7175 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
7176 mono_error_assert_ok (error);
7178 g_assert (del->interp_method);
7179 sp->data.p = del->interp_method;
7180 ++sp;
7181 ip += 1;
7182 MINT_IN_BREAK;
7184 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
7185 MonoDelegate *del;
7186 int n = ip [1];
7187 del = (MonoDelegate*)sp [-n].data.p;
7188 if (!del->interp_invoke_impl) {
7190 * First time we are called. Set up the invoke wrapper. We might be able to do this
7191 * in ctor but we would need to handle AllocDelegateLike_internal separately
7193 error_init_reuse (error);
7194 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
7195 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
7196 mono_error_assert_ok (error);
7198 sp ++;
7199 sp [-1].data.p = del->interp_invoke_impl;
7200 ip += 2;
7201 MINT_IN_BREAK;
7204 #define MATH_UNOP(mathfunc) \
7205 sp [-1].data.f = mathfunc (sp [-1].data.f); \
7206 ++ip;
7208 #define MATH_BINOP(mathfunc) \
7209 sp--; \
7210 sp [-1].data.f = mathfunc (sp [-1].data.f, sp [0].data.f); \
7211 ++ip;
7213 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
7214 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
7215 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
7216 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
7217 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
7218 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
7219 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
7220 MINT_IN_CASE(MINT_CEILING) MATH_UNOP(ceil); MINT_IN_BREAK;
7221 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
7222 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
7223 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
7224 MINT_IN_CASE(MINT_EXP) MATH_UNOP(exp); MINT_IN_BREAK;
7225 MINT_IN_CASE(MINT_FLOOR) MATH_UNOP(floor); MINT_IN_BREAK;
7226 MINT_IN_CASE(MINT_LOG) MATH_UNOP(log); MINT_IN_BREAK;
7227 MINT_IN_CASE(MINT_LOG2) MATH_UNOP(log2); MINT_IN_BREAK;
7228 MINT_IN_CASE(MINT_LOG10) MATH_UNOP(log10); MINT_IN_BREAK;
7229 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
7230 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
7231 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
7232 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
7233 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
7235 MINT_IN_CASE(MINT_ATAN2) MATH_BINOP(atan2); MINT_IN_BREAK;
7236 MINT_IN_CASE(MINT_POW) MATH_BINOP(pow); MINT_IN_BREAK;
7237 MINT_IN_CASE(MINT_FMA)
7238 sp -= 2;
7239 sp [-1].data.f = fma (sp [-1].data.f, sp [0].data.f, sp [1].data.f);
7240 ip++;
7241 MINT_IN_BREAK;
7242 MINT_IN_CASE(MINT_SCALEB)
7243 sp--;
7244 sp [-1].data.f = scalbn (sp [-1].data.f, sp [0].data.i);
7245 ip++;
7246 MINT_IN_BREAK;
7247 MINT_IN_CASE(MINT_ILOGB) {
7248 int result;
7249 double x = sp [-1].data.f;
7250 if (FP_ILOGB0 != INT_MIN && x == 0.0)
7251 result = INT_MIN;
7252 else if (FP_ILOGBNAN != INT_MAX && isnan(x))
7253 result = INT_MAX;
7254 else
7255 result = ilogb (x);
7256 sp [-1].data.i = result;
7257 ip++;
7258 MINT_IN_BREAK;
7261 #define MATH_UNOPF(mathfunc) \
7262 sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4); \
7263 ++ip;
7265 #define MATH_BINOPF(mathfunc) \
7266 sp--; \
7267 sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4, sp [0].data.f_r4); \
7268 ++ip;
7269 MINT_IN_CASE(MINT_ABSF) MATH_UNOPF(fabsf); MINT_IN_BREAK;
7270 MINT_IN_CASE(MINT_ASINF) MATH_UNOPF(asinf); MINT_IN_BREAK;
7271 MINT_IN_CASE(MINT_ASINHF) MATH_UNOPF(asinhf); MINT_IN_BREAK;
7272 MINT_IN_CASE(MINT_ACOSF) MATH_UNOPF(acosf); MINT_IN_BREAK;
7273 MINT_IN_CASE(MINT_ACOSHF) MATH_UNOPF(acoshf); MINT_IN_BREAK;
7274 MINT_IN_CASE(MINT_ATANF) MATH_UNOPF(atanf); MINT_IN_BREAK;
7275 MINT_IN_CASE(MINT_ATANHF) MATH_UNOPF(atanhf); MINT_IN_BREAK;
7276 MINT_IN_CASE(MINT_CEILINGF) MATH_UNOPF(ceilf); MINT_IN_BREAK;
7277 MINT_IN_CASE(MINT_COSF) MATH_UNOPF(cosf); MINT_IN_BREAK;
7278 MINT_IN_CASE(MINT_CBRTF) MATH_UNOPF(cbrtf); MINT_IN_BREAK;
7279 MINT_IN_CASE(MINT_COSHF) MATH_UNOPF(coshf); MINT_IN_BREAK;
7280 MINT_IN_CASE(MINT_EXPF) MATH_UNOPF(expf); MINT_IN_BREAK;
7281 MINT_IN_CASE(MINT_FLOORF) MATH_UNOPF(floorf); MINT_IN_BREAK;
7282 MINT_IN_CASE(MINT_LOGF) MATH_UNOPF(logf); MINT_IN_BREAK;
7283 MINT_IN_CASE(MINT_LOG2F) MATH_UNOPF(log2f); MINT_IN_BREAK;
7284 MINT_IN_CASE(MINT_LOG10F) MATH_UNOPF(log10f); MINT_IN_BREAK;
7285 MINT_IN_CASE(MINT_SINF) MATH_UNOPF(sinf); MINT_IN_BREAK;
7286 MINT_IN_CASE(MINT_SQRTF) MATH_UNOPF(sqrtf); MINT_IN_BREAK;
7287 MINT_IN_CASE(MINT_SINHF) MATH_UNOPF(sinhf); MINT_IN_BREAK;
7288 MINT_IN_CASE(MINT_TANF) MATH_UNOPF(tanf); MINT_IN_BREAK;
7289 MINT_IN_CASE(MINT_TANHF) MATH_UNOPF(tanhf); MINT_IN_BREAK;
7291 MINT_IN_CASE(MINT_ATAN2F) MATH_BINOPF(atan2f); MINT_IN_BREAK;
7292 MINT_IN_CASE(MINT_POWF) MATH_BINOPF(powf); MINT_IN_BREAK;
7293 MINT_IN_CASE(MINT_FMAF)
7294 sp -= 2;
7295 sp [-1].data.f_r4 = fmaf (sp [-1].data.f_r4, sp [0].data.f_r4, sp [1].data.f_r4);
7296 ip++;
7297 MINT_IN_BREAK;
7298 MINT_IN_CASE(MINT_SCALEBF)
7299 sp--;
7300 sp [-1].data.f_r4 = scalbnf (sp [-1].data.f_r4, sp [0].data.i);
7301 ip++;
7302 MINT_IN_BREAK;
7303 MINT_IN_CASE(MINT_ILOGBF) {
7304 int result;
7305 float x = sp [-1].data.f_r4;
7306 if (FP_ILOGB0 != INT_MIN && x == 0.0)
7307 result = INT_MIN;
7308 else if (FP_ILOGBNAN != INT_MAX && isnan(x))
7309 result = INT_MAX;
7310 else
7311 result = ilogbf (x);
7312 sp [-1].data.i = result;
7313 ip++;
7314 MINT_IN_BREAK;
7317 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
7318 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]];
7319 mono_interp_enum_hasflag (sp, klass);
7320 sp--;
7321 ip += 2;
7322 MINT_IN_BREAK;
7324 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
7325 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
7326 ip++;
7327 MINT_IN_BREAK;
7329 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
7330 NULL_CHECK (sp [-1].data.p);
7331 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
7332 ip++;
7333 MINT_IN_BREAK;
7336 #if !USE_COMPUTED_GOTO
7337 default:
7338 interp_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code);
7339 #endif
7343 g_assert_not_reached ();
7345 resume:
7346 g_assert (context->has_resume_state);
7347 g_assert (frame->imethod);
7349 if (frame == context->handler_frame) {
7351 * When running finally blocks, we can have the same frame twice on the stack. If we have
7352 * clause_args information, we need to check whether resuming should happen inside this
7353 * finally block, or in some other part of the method, in which case we need to exit.
7355 if (clause_args && frame == clause_args->exec_frame && context->handler_ip >= clause_args->end_at_ip) {
7356 goto exit_clause;
7357 } else {
7358 /* Set the current execution state to the resume state in context */
7359 ip = context->handler_ip;
7360 /* spec says stack should be empty at endfinally so it should be at the start too */
7361 locals = (guchar*)frame->stack;
7362 vt_sp = locals + frame->imethod->total_locals_size;
7363 sp = (stackval*)(vt_sp + frame->imethod->vt_stack_size);
7364 g_assert (context->exc_gchandle);
7365 sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle);
7366 ++sp;
7368 finally_ips = clear_resume_state (context, finally_ips);
7369 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
7370 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
7371 goto main_loop;
7373 } else if (clause_args && frame == clause_args->exec_frame) {
7375 * This frame doesn't handle the resume state and it is the first frame invoked from EH.
7376 * We can't just return to parent. We must first exit the EH mechanism and start resuming
7377 * again from the original frame.
7379 goto exit_clause;
7381 // Because we are resuming in another frame, bypassing a normal ret opcode,
7382 // we need to make sure to reset the localloc stack
7383 frame_data_allocator_pop (&context->data_stack, frame);
7384 // fall through
7385 exit_frame:
7386 g_assert_checked (frame->imethod);
7388 if (frame->parent && frame->parent->state.ip) {
7389 /* Return to the main loop after a non-recursive interpreter call */
7390 //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);
7391 g_assert_checked (frame->stack);
7392 frame = frame->parent;
7394 * FIXME We should be able to avoid dereferencing imethod here, if we will have
7395 * a param_area and all calls would inherit the same sp, or if we are full coop.
7397 context->stack_pointer = (guchar*)frame->stack + frame->imethod->alloca_size;
7398 LOAD_INTERP_STATE (frame);
7400 CHECK_RESUME_STATE (context);
7402 goto main_loop;
7404 exit_clause:
7405 if (!clause_args)
7406 context->stack_pointer = (guchar*)frame->stack;
7408 DEBUG_LEAVE ();
7410 HANDLE_FUNCTION_RETURN ();
7413 static void
7414 interp_parse_options (const char *options)
7416 char **args, **ptr;
7418 if (!options)
7419 return;
7421 args = g_strsplit (options, ",", -1);
7422 for (ptr = args; ptr && *ptr; ptr ++) {
7423 char *arg = *ptr;
7425 if (strncmp (arg, "jit=", 4) == 0)
7426 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
7427 else if (strncmp (arg, "interp-only=", strlen ("interp-only=")) == 0)
7428 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
7429 else if (strncmp (arg, "-inline", 7) == 0)
7430 mono_interp_opt &= ~INTERP_OPT_INLINE;
7431 else if (strncmp (arg, "-cprop", 6) == 0)
7432 mono_interp_opt &= ~INTERP_OPT_CPROP;
7433 else if (strncmp (arg, "-super", 6) == 0)
7434 mono_interp_opt &= ~INTERP_OPT_SUPER_INSTRUCTIONS;
7435 else if (strncmp (arg, "-bblocks", 8) == 0)
7436 mono_interp_opt &= ~INTERP_OPT_BBLOCKS;
7437 else if (strncmp (arg, "-all", 4) == 0)
7438 mono_interp_opt = INTERP_OPT_NONE;
7443 * interp_set_resume_state:
7445 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
7447 static void
7448 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoObject *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
7450 ThreadContext *context;
7452 g_assert (jit_tls);
7453 context = (ThreadContext*)jit_tls->interp_context;
7454 g_assert (context);
7456 context->has_resume_state = TRUE;
7457 context->handler_frame = (InterpFrame*)interp_frame;
7458 context->handler_ei = ei;
7459 if (context->exc_gchandle)
7460 mono_gchandle_free_internal (context->exc_gchandle);
7461 context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
7462 /* Ditto */
7463 if (ei)
7464 *(MonoObject**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
7465 context->handler_ip = (const guint16*)handler_ip;
7468 static void
7469 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
7471 g_assert (jit_tls);
7472 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
7474 *has_resume_state = context ? context->has_resume_state : FALSE;
7475 if (!*has_resume_state)
7476 return;
7478 *interp_frame = context->handler_frame;
7479 *handler_ip = (gpointer)context->handler_ip;
7483 * interp_run_finally:
7485 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
7486 * frame->interp_frame.
7487 * Return TRUE if the finally clause threw an exception.
7489 static gboolean
7490 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
7492 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
7493 ThreadContext *context = get_context ();
7494 FrameClauseArgs clause_args;
7495 const guint16 *state_ip;
7497 memset (&clause_args, 0, sizeof (FrameClauseArgs));
7498 clause_args.start_with_ip = (const guint16*)handler_ip;
7499 clause_args.end_at_ip = (const guint16*)handler_ip_end;
7500 clause_args.exit_clause = clause_index;
7501 clause_args.exec_frame = iframe;
7503 state_ip = iframe->state.ip;
7504 iframe->state.ip = NULL;
7506 InterpFrame* const next_free = iframe->next_free;
7507 iframe->next_free = NULL;
7509 interp_exec_method (iframe, context, &clause_args);
7511 iframe->next_free = next_free;
7512 iframe->state.ip = state_ip;
7513 if (context->has_resume_state) {
7514 return TRUE;
7515 } else {
7516 return FALSE;
7521 * interp_run_filter:
7523 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
7524 * frame->interp_frame.
7526 // Do not inline in case order of frame addresses matters.
7527 static MONO_NEVER_INLINE gboolean
7528 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
7530 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
7531 ThreadContext *context = get_context ();
7532 stackval retval;
7533 FrameClauseArgs clause_args;
7536 * Have to run the clause in a new frame which is a copy of IFRAME, since
7537 * during debugging, there are two copies of the frame on the stack.
7539 InterpFrame child_frame = {0};
7540 child_frame.parent = iframe;
7541 child_frame.imethod = iframe->imethod;
7542 child_frame.stack = (stackval*)context->stack_pointer;
7543 child_frame.retval = &retval;
7545 /* Copy the stack frame of the original method */
7546 memcpy (child_frame.stack, iframe->stack, iframe->imethod->total_locals_size);
7547 context->stack_pointer += iframe->imethod->alloca_size;
7549 memset (&clause_args, 0, sizeof (FrameClauseArgs));
7550 clause_args.start_with_ip = (const guint16*)handler_ip;
7551 clause_args.end_at_ip = (const guint16*)handler_ip_end;
7552 clause_args.filter_exception = ex;
7553 clause_args.exec_frame = &child_frame;
7555 interp_exec_method (&child_frame, context, &clause_args);
7557 /* Copy back the updated frame */
7558 memcpy (iframe->stack, child_frame.stack, iframe->imethod->total_locals_size);
7560 context->stack_pointer = (guchar*)child_frame.stack;
7562 /* ENDFILTER stores the result into child_frame->retval */
7563 return retval.data.i ? TRUE : FALSE;
7566 typedef struct {
7567 InterpFrame *current;
7568 } StackIter;
7570 static gpointer
7571 interp_frame_get_ip (MonoInterpFrameHandle frame)
7573 InterpFrame *iframe = (InterpFrame*)frame;
7575 g_assert (iframe->imethod);
7577 * For calls, state.ip points to the instruction following the call, so we need to subtract
7578 * in order to get inside the call instruction range. Other instructions that set the IP for
7579 * the rest of the runtime to see, like throws and sdb breakpoints, will need to account for
7580 * this subtraction that we are doing here.
7582 return (gpointer)(iframe->state.ip - 1);
7586 * interp_frame_iter_init:
7588 * Initialize an iterator for iterating through interpreted frames.
7590 static void
7591 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
7593 StackIter *stack_iter = (StackIter*)iter;
7595 stack_iter->current = (InterpFrame*)interp_exit_data;
7599 * interp_frame_iter_next:
7601 * Fill out FRAME with date for the next interpreter frame.
7603 static gboolean
7604 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
7606 StackIter *stack_iter = (StackIter*)iter;
7607 InterpFrame *iframe = stack_iter->current;
7609 memset (frame, 0, sizeof (StackFrameInfo));
7610 /* pinvoke frames doesn't have imethod set */
7611 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
7612 iframe = iframe->parent;
7613 if (!iframe)
7614 return FALSE;
7616 MonoMethod *method = iframe->imethod->method;
7617 frame->domain = iframe->imethod->domain;
7618 frame->interp_frame = iframe;
7619 frame->method = method;
7620 frame->actual_method = method;
7621 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
7622 frame->native_offset = -1;
7623 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
7624 } else {
7625 frame->type = FRAME_TYPE_INTERP;
7626 /* This is the offset in the interpreter IR. */
7627 frame->native_offset = (guint8*)interp_frame_get_ip (iframe) - (guint8*)iframe->imethod->code;
7628 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
7629 frame->managed = TRUE;
7631 frame->ji = iframe->imethod->jinfo;
7632 frame->frame_addr = iframe;
7634 stack_iter->current = iframe->parent;
7636 return TRUE;
7639 static MonoJitInfo*
7640 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
7642 InterpMethod* imethod;
7644 imethod = lookup_imethod (domain, method);
7645 if (imethod)
7646 return imethod->jinfo;
7647 else
7648 return NULL;
7651 static void
7652 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
7654 guint16 *code = (guint16*)ip;
7655 g_assert (*code == MINT_SDB_SEQ_POINT);
7656 *code = MINT_SDB_BREAKPOINT;
7659 static void
7660 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
7662 guint16 *code = (guint16*)ip;
7663 g_assert (*code == MINT_SDB_BREAKPOINT);
7664 *code = MINT_SDB_SEQ_POINT;
7667 static MonoJitInfo*
7668 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
7670 InterpFrame *iframe = (InterpFrame*)frame;
7672 g_assert (iframe->imethod);
7673 return iframe->imethod->jinfo;
7676 static gpointer
7677 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
7679 InterpFrame *iframe = (InterpFrame*)frame;
7680 MonoMethodSignature *sig;
7682 g_assert (iframe->imethod);
7684 sig = mono_method_signature_internal (iframe->imethod->method);
7685 return stackval_to_data_addr (sig->params [pos], &iframe->stack [pos + !!iframe->imethod->hasthis]);
7688 static gpointer
7689 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
7691 InterpFrame *iframe = (InterpFrame*)frame;
7693 g_assert (iframe->imethod);
7695 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
7698 static gpointer
7699 interp_frame_get_this (MonoInterpFrameHandle frame)
7701 InterpFrame *iframe = (InterpFrame*)frame;
7703 g_assert (iframe->imethod);
7704 g_assert (iframe->imethod->hasthis);
7705 return &iframe->stack [0].data.p;
7708 static MonoInterpFrameHandle
7709 interp_frame_get_parent (MonoInterpFrameHandle frame)
7711 InterpFrame *iframe = (InterpFrame*)frame;
7713 return iframe->parent;
7716 static gpointer
7717 interp_frame_get_res (MonoInterpFrameHandle frame)
7719 InterpFrame *iframe = (InterpFrame*)frame;
7720 MonoMethodSignature *sig;
7722 g_assert (iframe->imethod);
7723 sig = mono_method_signature_internal (iframe->imethod->method);
7724 if (sig->ret->type == MONO_TYPE_VOID)
7725 return NULL;
7726 else if (iframe->parent)
7727 return stackval_to_data_addr (sig->ret, iframe->parent->state.sp - 1);
7728 else
7729 return stackval_to_data_addr (sig->ret, iframe->retval);
7732 static void
7733 interp_start_single_stepping (void)
7735 ss_enabled = TRUE;
7738 static void
7739 interp_stop_single_stepping (void)
7741 ss_enabled = FALSE;
7745 * interp_mark_stack:
7747 * Mark the interpreter stack frames for a thread.
7750 static void
7751 interp_mark_stack (gpointer thread_data, GcScanFunc func, gpointer gc_data, gboolean precise)
7753 MonoThreadInfo *info = (MonoThreadInfo*)thread_data;
7755 if (!mono_use_interpreter)
7756 return;
7757 if (precise)
7758 return;
7761 * We explicitly mark the frames instead of registering the stack fragments as GC roots, so
7762 * we have to process less data and avoid false pinning from data which is above 'pos'.
7764 * The stack frame handling code uses compiler write barriers only, but the calling code
7765 * in sgen-mono.c already did a mono_memory_barrier_process_wide () so we can
7766 * process these data structures normally.
7768 MonoJitTlsData *jit_tls = (MonoJitTlsData *)info->tls [TLS_KEY_JIT_TLS];
7769 if (!jit_tls)
7770 return;
7772 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
7773 if (!context || !context->stack_start)
7774 return;
7776 // FIXME: Scan the whole area with 1 call
7777 for (gpointer *p = (gpointer*)context->stack_start; p < (gpointer*)context->stack_pointer; p++)
7778 func (p, gc_data);
7780 FrameDataFragment *frag;
7781 for (frag = context->data_stack.first; frag; frag = frag->next) {
7782 // FIXME: Scan the whole area with 1 call
7783 for (gpointer *p = (gpointer*)&frag->data; p < (gpointer*)frag->pos; ++p)
7784 func (p, gc_data);
7785 if (frag == context->data_stack.current)
7786 break;
7790 #if COUNT_OPS
7792 static int
7793 opcode_count_comparer (const void * pa, const void * pb)
7795 long counta = opcode_counts [*(int*)pa];
7796 long countb = opcode_counts [*(int*)pb];
7798 if (counta < countb)
7799 return 1;
7800 else if (counta > countb)
7801 return -1;
7802 else
7803 return 0;
7806 static void
7807 interp_print_op_count (void)
7809 int ordered_ops [MINT_LASTOP];
7810 int i;
7811 long total_ops = 0;
7813 for (i = 0; i < MINT_LASTOP; i++) {
7814 ordered_ops [i] = i;
7815 total_ops += opcode_counts [i];
7817 qsort (ordered_ops, MINT_LASTOP, sizeof (int), opcode_count_comparer);
7819 g_print ("total ops %ld\n", total_ops);
7820 for (i = 0; i < MINT_LASTOP; i++) {
7821 long count = opcode_counts [ordered_ops [i]];
7822 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops [i]), count, (double)count / total_ops * 100);
7825 #endif
7827 #if PROFILE_INTERP
7829 static InterpMethod **imethods;
7830 static int num_methods;
7831 const int opcount_threshold = 100000;
7833 static void
7834 interp_add_imethod (gpointer method)
7836 InterpMethod *imethod = (InterpMethod*) method;
7837 if (imethod->opcounts > opcount_threshold)
7838 imethods [num_methods++] = imethod;
7841 static int
7842 imethod_opcount_comparer (gconstpointer m1, gconstpointer m2)
7844 return (*(InterpMethod**)m2)->opcounts - (*(InterpMethod**)m1)->opcounts;
7847 static void
7848 interp_print_method_counts (void)
7850 MonoDomain *domain = mono_get_root_domain ();
7851 MonoJitDomainInfo *info = domain_jit_info (domain);
7853 mono_domain_jit_code_hash_lock (domain);
7854 imethods = (InterpMethod**) malloc (info->interp_code_hash.num_entries * sizeof (InterpMethod*));
7855 mono_internal_hash_table_apply (&info->interp_code_hash, interp_add_imethod);
7856 mono_domain_jit_code_hash_unlock (domain);
7858 qsort (imethods, num_methods, sizeof (InterpMethod*), imethod_opcount_comparer);
7860 printf ("Total executed opcodes %ld\n", total_executed_opcodes);
7861 long cumulative_executed_opcodes = 0;
7862 for (int i = 0; i < num_methods; i++) {
7863 cumulative_executed_opcodes += imethods [i]->opcounts;
7864 printf ("%d%% Opcounts %ld, calls %ld, Method %s, imethod ptr %p\n", (int)(cumulative_executed_opcodes * 100 / total_executed_opcodes), imethods [i]->opcounts, imethods [i]->calls, mono_method_full_name (imethods [i]->method, TRUE), imethods [i]);
7867 #endif
7869 static void
7870 interp_set_optimizations (guint32 opts)
7872 mono_interp_opt = opts;
7875 static void
7876 invalidate_transform (gpointer imethod_)
7878 InterpMethod *imethod = (InterpMethod *) imethod_;
7879 imethod->transformed = FALSE;
7882 static void
7883 interp_invalidate_transformed (MonoDomain *domain)
7885 MonoJitDomainInfo *info = domain_jit_info (domain);
7886 mono_domain_jit_code_hash_lock (domain);
7887 mono_internal_hash_table_apply (&info->interp_code_hash, invalidate_transform);
7888 mono_domain_jit_code_hash_unlock (domain);
7891 static void
7892 interp_cleanup (void)
7894 #if COUNT_OPS
7895 interp_print_op_count ();
7896 #endif
7897 #if PROFILE_INTERP
7898 interp_print_method_counts ();
7899 #endif
7902 static void
7903 register_interp_stats (void)
7905 mono_counters_init ();
7906 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
7907 mono_counters_register ("Methods transformed", MONO_COUNTER_INTERP | MONO_COUNTER_LONG, &mono_interp_stats.methods_transformed);
7908 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.cprop_time);
7909 mono_counters_register ("Total super instructions time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.super_instructions_time);
7910 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.stloc_nps);
7911 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.movlocs);
7912 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.copy_propagations);
7913 mono_counters_register ("Added pop count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.added_pop_count);
7914 mono_counters_register ("Constant folds", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.constant_folds);
7915 mono_counters_register ("Ldlocas removed", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.ldlocas_removed);
7916 mono_counters_register ("Super instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.super_instructions);
7917 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.killed_instructions);
7918 mono_counters_register ("Emitted instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.emitted_instructions);
7919 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
7920 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
7923 #undef MONO_EE_CALLBACK
7924 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
7926 static const MonoEECallbacks mono_interp_callbacks = {
7927 MONO_EE_CALLBACKS
7930 void
7931 mono_ee_interp_init (const char *opts)
7933 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
7934 g_assert (!interp_init_done);
7935 interp_init_done = TRUE;
7937 mono_native_tls_alloc (&thread_context_id, NULL);
7938 set_context (NULL);
7940 interp_parse_options (opts);
7941 /* Don't do any optimizations if running under debugger */
7942 if (mini_get_debug_options ()->mdb_optimizations)
7943 mono_interp_opt = 0;
7944 mono_interp_transform_init ();
7946 mini_install_interp_callbacks (&mono_interp_callbacks);
7948 register_interp_stats ();